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
@@ -2,33 +2,40 @@ import { execFile } from "node:child_process";
2
2
  import { lstat, rm } from "node:fs/promises";
3
3
  import { win32 } from "node:path";
4
4
  import { promisify } from "node:util";
5
- import { fetchCdpJson, parseCdpTargets, parseCdpVersion } from "./cdp.js";
6
- import { ELECTRON_PROFILE_DIR_PREFIX } from "./launch.js";
5
+ import { fetchCdpJson, parseCdpTargets, parseCdpVersion, } from "./cdp.js";
6
+ import { ELECTRON_PROFILE_DIR_PREFIX } from "./launch-types.js";
7
7
  import { pathExists } from "../fs-utils.js";
8
+ import { isRecord } from "../parsing.js";
9
+ import { stringifyUnknown } from "../results/text.js";
8
10
  import { getSecureTempChildDirectoryValidationError } from "../temp.js";
9
11
  const ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS = 5_000;
10
12
  const ELECTRON_CLEANUP_POLL_INTERVAL_MS = 100;
11
13
  const RESTORED_PROCESS_COMMAND_TIMEOUT_MS = 1_000;
14
+ // Node's callback-style execFile returns a ChildProcess; promisify owns its completion callback, not that return value.
15
+ // oxlint-disable-next-line typescript/strict-void-return
12
16
  const execFileAsync = promisify(execFile);
13
17
  function sleep(ms) {
14
- return new Promise((resolve) => setTimeout(resolve, ms));
18
+ return new Promise((resolve) => {
19
+ setTimeout(resolve, ms);
20
+ });
15
21
  }
16
22
  function isPidAlive(pid) {
17
- if (!pid || !Number.isSafeInteger(pid) || pid <= 0)
23
+ if (pid === undefined || !Number.isSafeInteger(pid) || pid <= 0) {
18
24
  return undefined;
25
+ }
19
26
  try {
20
27
  process.kill(pid, 0);
21
28
  return true;
22
29
  }
23
30
  catch (error) {
24
- const code = error.code;
25
- return code === "EPERM" ? true : false;
31
+ return isRecord(error) && error.code === "EPERM";
26
32
  }
27
33
  }
28
34
  async function isPortAlive(port, signal) {
29
35
  const version = parseCdpVersion(await fetchCdpJson(`http://127.0.0.1:${port}/json/version`, signal));
30
- if (!version)
36
+ if (!version) {
31
37
  return { targets: [] };
38
+ }
32
39
  const targets = parseCdpTargets(await fetchCdpJson(`http://127.0.0.1:${port}/json/list`, signal));
33
40
  return { targets, version };
34
41
  }
@@ -40,7 +47,7 @@ export async function inspectElectronLaunchStatus(record, signal) {
40
47
  userDataDirState = "present";
41
48
  }
42
49
  catch (error) {
43
- userDataDirState = error.code === "ENOENT" ? "absent" : "unknown";
50
+ userDataDirState = isRecord(error) && error.code === "ENOENT" ? "absent" : "unknown";
44
51
  }
45
52
  return {
46
53
  cleanupState: record.cleanupState,
@@ -61,31 +68,42 @@ function hasProcessExited(child, pid) {
61
68
  }
62
69
  async function waitForProcessExit(child, pid, deadlineMs) {
63
70
  while (Date.now() <= deadlineMs) {
64
- if (hasProcessExited(child, pid))
71
+ if (hasProcessExited(child, pid)) {
65
72
  return true;
73
+ }
74
+ // Polling observes exit between sleeps; parallel waits cannot preserve the deadline.
75
+ // oxlint-disable-next-line no-await-in-loop
66
76
  await sleep(ELECTRON_CLEANUP_POLL_INTERVAL_MS);
67
77
  }
68
78
  return hasProcessExited(child, pid);
69
79
  }
70
80
  async function readPidCommandLine(pid) {
71
- if (!pid || !Number.isSafeInteger(pid) || pid <= 0)
81
+ if (!Number.isSafeInteger(pid) || pid <= 0) {
72
82
  return undefined;
83
+ }
73
84
  try {
74
85
  // Win32_Process.CommandLine is the native ownership evidence; process
75
86
  // start time (used by daemon-policy locks) cannot prove profile ownership.
76
87
  const systemRoot = process.env.SystemRoot;
77
- const windowsRoot = systemRoot && win32.isAbsolute(systemRoot) ? systemRoot : "C:\\Windows";
88
+ const windowsRoot = systemRoot !== undefined && systemRoot.length > 0 && win32.isAbsolute(systemRoot)
89
+ ? systemRoot
90
+ : "C:\\Windows";
78
91
  const file = process.platform === "win32"
79
92
  ? win32.join(windowsRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
80
93
  : "ps";
81
94
  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)`]
95
+ ? [
96
+ "-NoProfile",
97
+ "-NonInteractive",
98
+ "-Command",
99
+ `[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new(); $p = [wmi]"Win32_Process.Handle='${pid}'"; [Console]::WriteLine($p.CommandLine)`,
100
+ ]
84
101
  : ["-ww", "-p", String(pid), "-o", "command="];
85
102
  const { stdout } = await execFileAsync(file, args, {
86
103
  timeout: RESTORED_PROCESS_COMMAND_TIMEOUT_MS,
87
104
  });
88
- return stdout.trim() || undefined;
105
+ const commandLine = stdout.trim();
106
+ return commandLine.length === 0 ? undefined : commandLine;
89
107
  }
90
108
  catch {
91
109
  return undefined;
@@ -95,18 +113,19 @@ function restoredLaunchCommandMatchesRecord(record, commandLine) {
95
113
  return commandLine?.includes(`--user-data-dir=${record.userDataDir}`) === true;
96
114
  }
97
115
  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.`;
116
+ const commandLine = record.pid === undefined ? undefined : await readPidCommandLine(record.pid);
117
+ if (commandLine === undefined || commandLine.length === 0) {
118
+ return `PID ${String(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.`;
101
119
  }
102
120
  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.`;
121
+ return `PID ${String(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.`;
104
122
  }
105
123
  return undefined;
106
124
  }
107
125
  function killPid(pid, signal) {
108
- if (!pid || !Number.isSafeInteger(pid) || pid <= 0)
126
+ if (pid === undefined || !Number.isSafeInteger(pid) || pid <= 0) {
109
127
  return false;
128
+ }
110
129
  try {
111
130
  process.kill(pid, signal);
112
131
  return true;
@@ -116,8 +135,12 @@ function killPid(pid, signal) {
116
135
  }
117
136
  }
118
137
  function killProcessGroup(processGroupId, signal) {
119
- if (process.platform === "win32" || !processGroupId || !Number.isSafeInteger(processGroupId) || processGroupId <= 0)
138
+ if (process.platform === "win32" ||
139
+ processGroupId === undefined ||
140
+ !Number.isSafeInteger(processGroupId) ||
141
+ processGroupId <= 0) {
120
142
  return false;
143
+ }
121
144
  try {
122
145
  process.kill(-processGroupId, signal);
123
146
  return true;
@@ -130,68 +153,118 @@ function signalRestoredLaunchProcess(record, signal) {
130
153
  return killProcessGroup(record.processGroupId, signal) || killPid(record.pid, signal);
131
154
  }
132
155
  async function cleanupProcess(record, child, deadlineMs) {
133
- if (!record.pid)
156
+ if (record.pid === undefined || record.pid === 0 || Number.isNaN(record.pid)) {
134
157
  return { resource: "process", state: "skipped" };
135
- if (hasProcessExited(child, record.pid))
158
+ }
159
+ if (hasProcessExited(child, record.pid)) {
136
160
  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)
161
+ }
162
+ return child === undefined
163
+ ? cleanupRestoredProcess(record, deadlineMs)
164
+ : cleanupTrackedProcess(record, child, deadlineMs);
165
+ }
166
+ async function cleanupRestoredProcess(record, deadlineMs) {
167
+ const verificationError = await getRestoredProcessVerificationError(record);
168
+ if (verificationError !== undefined) {
169
+ return { error: verificationError, resource: "process", state: "failed" };
170
+ }
171
+ if (!signalRestoredLaunchProcess(record, "SIGTERM")) {
172
+ return {
173
+ error: `PID ${String(record.pid)} matched wrapper launch metadata but could not be signaled.`,
174
+ resource: "process",
175
+ state: "failed",
176
+ };
177
+ }
178
+ if (await waitForProcessExit(undefined, record.pid, deadlineMs)) {
179
+ return { resource: "process", state: "removed" };
180
+ }
181
+ signalRestoredLaunchProcess(record, "SIGKILL");
182
+ if (await waitForProcessExit(undefined, record.pid, Date.now() + 1_000)) {
183
+ return { resource: "process", state: "removed" };
184
+ }
185
+ return {
186
+ error: `PID ${String(record.pid)} remained alive after SIGTERM/SIGKILL.`,
187
+ resource: "process",
188
+ state: "failed",
189
+ };
190
+ }
191
+ async function cleanupTrackedProcess(record, child, deadlineMs) {
192
+ if (child.exitCode === null && child.signalCode === null) {
152
193
  child.kill("SIGTERM");
153
- else
194
+ }
195
+ else {
154
196
  killPid(record.pid, "SIGTERM");
155
- if (await waitForProcessExit(child, record.pid, deadlineMs))
197
+ }
198
+ if (await waitForProcessExit(child, record.pid, deadlineMs)) {
156
199
  return { resource: "process", state: "removed" };
157
- if (child.exitCode === null && child.signalCode === null)
200
+ }
201
+ if (child.exitCode === null && child.signalCode === null) {
158
202
  child.kill("SIGKILL");
159
- else
203
+ }
204
+ else {
160
205
  killPid(record.pid, "SIGKILL");
161
- if (await waitForProcessExit(child, record.pid, Date.now() + 1_000))
206
+ }
207
+ if (await waitForProcessExit(child, record.pid, Date.now() + 1_000)) {
162
208
  return { resource: "process", state: "removed" };
163
- return { error: `PID ${record.pid} remained alive after SIGTERM/SIGKILL.`, resource: "process", state: "failed" };
209
+ }
210
+ return {
211
+ error: `PID ${String(record.pid)} remained alive after SIGTERM/SIGKILL.`,
212
+ resource: "process",
213
+ state: "failed",
214
+ };
164
215
  }
165
216
  async function cleanupUserDataDir(record) {
166
- if (!record.userDataDir)
217
+ if (record.userDataDir.length === 0) {
167
218
  return { resource: "user-data-dir", state: "skipped" };
168
- if (!await pathExists(record.userDataDir))
219
+ }
220
+ if (!(await pathExists(record.userDataDir))) {
169
221
  return { resource: "user-data-dir", state: "already-gone" };
222
+ }
170
223
  const validationError = await getSecureTempChildDirectoryValidationError(record.userDataDir, ELECTRON_PROFILE_DIR_PREFIX);
171
- if (validationError)
224
+ if (validationError !== undefined) {
172
225
  return { error: validationError, resource: "user-data-dir", state: "failed" };
226
+ }
173
227
  try {
174
228
  await rm(record.userDataDir, { force: true, recursive: true });
175
- return { resource: "user-data-dir", state: await pathExists(record.userDataDir) ? "failed" : "removed" };
229
+ return {
230
+ resource: "user-data-dir",
231
+ state: (await pathExists(record.userDataDir)) ? "failed" : "removed",
232
+ };
176
233
  }
177
234
  catch (error) {
178
- return { error: error instanceof Error ? error.message : String(error), resource: "user-data-dir", state: "failed" };
235
+ return {
236
+ error: error instanceof Error ? error.message : stringifyUnknown(error),
237
+ resource: "user-data-dir",
238
+ state: "failed",
239
+ };
179
240
  }
180
241
  }
181
242
  function shouldSkipUserDataDirCleanup(processStep, debugPortStep) {
182
- if (processStep.state === "failed")
243
+ if (processStep.state === "failed") {
183
244
  return `Skipped because process cleanup failed: ${processStep.error ?? "process state could not be verified"}.`;
184
- if (debugPortStep.state === "failed")
245
+ }
246
+ if (debugPortStep.state === "failed") {
185
247
  return `Skipped because debug port cleanup is incomplete: ${debugPortStep.error ?? "debug port still responds"}.`;
248
+ }
186
249
  return undefined;
187
250
  }
188
251
  async function cleanupDebugPort(record) {
189
252
  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" };
253
+ return cdp.version
254
+ ? {
255
+ resource: "debug-port",
256
+ state: "failed",
257
+ error: `/json/version still responds on port ${record.port}.`,
258
+ }
259
+ : { resource: "debug-port", state: "already-gone" };
191
260
  }
192
261
  function summarizeCleanup(launchId, steps) {
193
262
  const remainingResources = steps
194
- .filter((step) => step.state === "failed" || (step.resource === "user-data-dir" && step.state === "skipped" && step.error))
263
+ .filter((step) => step.state === "failed" ||
264
+ (step.resource === "user-data-dir" &&
265
+ step.state === "skipped" &&
266
+ step.error !== undefined &&
267
+ step.error.length > 0))
195
268
  .map((step) => step.resource);
196
269
  const partial = remainingResources.length > 0;
197
270
  return {
@@ -203,15 +276,21 @@ function summarizeCleanup(launchId, steps) {
203
276
  };
204
277
  }
205
278
  export async function cleanupElectronLaunchResources(options) {
206
- const timeoutMs = Number.isSafeInteger(options.timeoutMs) && (options.timeoutMs ?? 0) > 0
279
+ const timeoutMs = typeof options.timeoutMs === "number" &&
280
+ Number.isSafeInteger(options.timeoutMs) &&
281
+ options.timeoutMs > 0
207
282
  ? options.timeoutMs
208
283
  : ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS;
209
284
  const deadlineMs = Date.now() + timeoutMs;
210
285
  const processStep = await cleanupProcess(options.record, options.child, deadlineMs);
211
286
  const debugPortStep = await cleanupDebugPort(options.record);
212
287
  const userDataDirSkipReason = shouldSkipUserDataDirCleanup(processStep, debugPortStep);
213
- const userDataDirStep = userDataDirSkipReason
214
- ? { error: userDataDirSkipReason, resource: "user-data-dir", state: "skipped" }
288
+ const userDataDirStep = userDataDirSkipReason !== undefined
289
+ ? {
290
+ error: userDataDirSkipReason,
291
+ resource: "user-data-dir",
292
+ state: "skipped",
293
+ }
215
294
  : await cleanupUserDataDir(options.record);
216
295
  const steps = [processStep, debugPortStep, userDataDirStep];
217
296
  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,89 @@
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 isDirectory(join(resourcesDirectory, "app"))));
53
+ }
54
+ export async function hasLinuxElectronEvidence(executablePath) {
55
+ const resolved = await resolveRealPath(executablePath);
56
+ if (!(await isExecutableFile(resolved))) {
57
+ return false;
58
+ }
59
+ const directory = dirname(resolved);
60
+ if (!(await directoryContainsChromePak(directory))) {
61
+ return false;
62
+ }
63
+ for (const base of [directory, dirname(directory)]) {
64
+ // Ordered evidence checks avoid unnecessary filesystem work after the first match.
65
+ // oxlint-disable-next-line no-await-in-loop
66
+ if (await hasElectronAppPayload(join(base, "resources"))) {
67
+ return true;
68
+ }
69
+ }
70
+ return false;
71
+ }
72
+ export async function inspectWin32Executable(executablePath) {
73
+ const resolved = await resolveRealPath(executablePath);
74
+ if (!(await isExecutableFile(resolved))) {
75
+ return undefined;
76
+ }
77
+ const directory = dirname(resolved);
78
+ const hasAppPayload = await hasElectronAppPayload(join(directory, "resources"));
79
+ const hasPak = (await directoryContainsChromePak(directory)) ||
80
+ (await pathExists(join(directory, "resources.pak")));
81
+ if (!hasAppPayload || !hasPak) {
82
+ return undefined;
83
+ }
84
+ return {
85
+ executablePath: resolved,
86
+ name: basename(resolved, extname(resolved)),
87
+ platform: "win32",
88
+ };
89
+ }