pi-agent-browser-native 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (392) hide show
  1. package/CHANGELOG.md +91 -5
  2. package/README.md +120 -86
  3. package/dist/extensions/agent-browser/index.js +43065 -2016
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +49 -26
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +82 -93
  6. package/dist/extensions/agent-browser/lib/bash-guard.js +129 -126
  7. package/dist/extensions/agent-browser/lib/batch-lifecycle.js +113 -49
  8. package/dist/extensions/agent-browser/lib/browser-execution-claim-codec.js +61 -0
  9. package/dist/extensions/agent-browser/lib/browser-execution-claim-storage.js +232 -0
  10. package/dist/extensions/agent-browser/lib/browser-execution-claims.js +202 -0
  11. package/dist/extensions/agent-browser/lib/browser-execution-identity.js +77 -0
  12. package/dist/extensions/agent-browser/lib/browser-journal-branch.js +98 -0
  13. package/dist/extensions/agent-browser/lib/browser-journal-contracts.js +1 -0
  14. package/dist/extensions/agent-browser/lib/browser-journal-projection.js +221 -0
  15. package/dist/extensions/agent-browser/lib/browser-journal-reader.js +89 -0
  16. package/dist/extensions/agent-browser/lib/browser-journal-replay.js +246 -0
  17. package/dist/extensions/agent-browser/lib/browser-journal.js +103 -394
  18. package/dist/extensions/agent-browser/lib/browser-legacy-pages.js +220 -0
  19. package/dist/extensions/agent-browser/lib/browser-legacy-projection.js +282 -0
  20. package/dist/extensions/agent-browser/lib/browser-legacy-types.js +1 -0
  21. package/dist/extensions/agent-browser/lib/browser-session-conversion-stream.js +217 -0
  22. package/dist/extensions/agent-browser/lib/browser-session-conversion.js +80 -335
  23. package/dist/extensions/agent-browser/lib/browser-transcript-contracts.js +35 -0
  24. package/dist/extensions/agent-browser/lib/browser-transcript-validation.js +166 -0
  25. package/dist/extensions/agent-browser/lib/browser-transcript.js +137 -81
  26. package/dist/extensions/agent-browser/lib/browser-value-parsing.js +15 -0
  27. package/dist/extensions/agent-browser/lib/command-capabilities.js +340 -0
  28. package/dist/extensions/agent-browser/lib/command-policy.js +107 -88
  29. package/dist/extensions/agent-browser/lib/command-taxonomy.js +49 -322
  30. package/dist/extensions/agent-browser/lib/config-policy.js +138 -343
  31. package/dist/extensions/agent-browser/lib/config-providers.js +71 -0
  32. package/dist/extensions/agent-browser/lib/config-validation.js +218 -0
  33. package/dist/extensions/agent-browser/lib/config.js +19 -7
  34. package/dist/extensions/agent-browser/lib/electron/cdp.js +15 -7
  35. package/dist/extensions/agent-browser/lib/electron/cleanup.js +134 -55
  36. package/dist/extensions/agent-browser/lib/electron/discovery-darwin.js +109 -0
  37. package/dist/extensions/agent-browser/lib/electron/discovery-desktop.js +136 -0
  38. package/dist/extensions/agent-browser/lib/electron/discovery-evidence.js +89 -0
  39. package/dist/extensions/agent-browser/lib/electron/discovery-linux.js +93 -0
  40. package/dist/extensions/agent-browser/lib/electron/discovery-packages.js +162 -0
  41. package/dist/extensions/agent-browser/lib/electron/discovery-types.js +2 -0
  42. package/dist/extensions/agent-browser/lib/electron/discovery.js +140 -549
  43. package/dist/extensions/agent-browser/lib/electron/launch-monitor.js +102 -0
  44. package/dist/extensions/agent-browser/lib/electron/launch-process.js +209 -0
  45. package/dist/extensions/agent-browser/lib/electron/launch-types.js +2 -0
  46. package/dist/extensions/agent-browser/lib/electron/launch.js +249 -354
  47. package/dist/extensions/agent-browser/lib/executable-path.js +21 -12
  48. package/dist/extensions/agent-browser/lib/execution-cwd.js +35 -18
  49. package/dist/extensions/agent-browser/lib/input-modes/electron.js +162 -121
  50. package/dist/extensions/agent-browser/lib/input-modes/job.js +116 -313
  51. package/dist/extensions/agent-browser/lib/input-modes/lookup-network-evidence.js +104 -0
  52. package/dist/extensions/agent-browser/lib/input-modes/lookup-plan.js +132 -0
  53. package/dist/extensions/agent-browser/lib/input-modes/lookup-redaction.js +57 -0
  54. package/dist/extensions/agent-browser/lib/input-modes/lookup-source-evidence.js +151 -0
  55. package/dist/extensions/agent-browser/lib/input-modes/lookup-workspace.js +142 -0
  56. package/dist/extensions/agent-browser/lib/input-modes/lookups.js +57 -412
  57. package/dist/extensions/agent-browser/lib/input-modes/params.js +63 -17
  58. package/dist/extensions/agent-browser/lib/input-modes/qa-analysis.js +268 -0
  59. package/dist/extensions/agent-browser/lib/input-modes/qa-presentation.js +117 -0
  60. package/dist/extensions/agent-browser/lib/input-modes/script-child.js +396 -0
  61. package/dist/extensions/agent-browser/lib/input-modes/script-protocol.js +86 -0
  62. package/dist/extensions/agent-browser/lib/input-modes/script-types.js +1 -0
  63. package/dist/extensions/agent-browser/lib/input-modes/script-validation.js +60 -0
  64. package/dist/extensions/agent-browser/lib/input-modes/script.js +60 -409
  65. package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +218 -128
  66. package/dist/extensions/agent-browser/lib/input-modes/shared.js +15 -4
  67. package/dist/extensions/agent-browser/lib/input-modes/types.js +56 -7
  68. package/dist/extensions/agent-browser/lib/json-schema.js +22 -10
  69. package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +17 -5
  70. package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +92 -425
  71. package/dist/extensions/agent-browser/lib/managed-session-posix-storage.js +58 -0
  72. package/dist/extensions/agent-browser/lib/managed-session-project-identity.js +244 -0
  73. package/dist/extensions/agent-browser/lib/managed-session-restore-context.js +84 -0
  74. package/dist/extensions/agent-browser/lib/managed-session-restore-policy.js +119 -0
  75. package/dist/extensions/agent-browser/lib/managed-session-restore-state.js +83 -0
  76. package/dist/extensions/agent-browser/lib/managed-session-restore.js +168 -300
  77. package/dist/extensions/agent-browser/lib/managed-session-snapshot-records.js +277 -0
  78. package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +128 -305
  79. package/dist/extensions/agent-browser/lib/managed-session-storage.js +56 -253
  80. package/dist/extensions/agent-browser/lib/native-confirmation.js +140 -0
  81. package/dist/extensions/agent-browser/lib/native-output.js +44 -9
  82. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +107 -66
  83. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-merge.js +14 -6
  84. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +109 -57
  85. package/dist/extensions/agent-browser/lib/orchestration/browser-run/browser-observation-result.js +82 -0
  86. package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +171 -57
  87. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostic-values.js +31 -0
  88. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +152 -781
  89. package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-observation.js +202 -0
  90. package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-text-diagnostics.js +109 -0
  91. package/dist/extensions/agent-browser/lib/orchestration/browser-run/fill-diagnostics.js +119 -0
  92. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-action-recovery.js +147 -0
  93. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-actions.js +144 -0
  94. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-content.js +123 -0
  95. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-contracts.js +1 -0
  96. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-details.js +156 -0
  97. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-electron.js +179 -0
  98. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-evidence.js +39 -0
  99. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-missing-binary.js +89 -0
  100. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-recovery.js +97 -0
  101. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-redaction.js +106 -0
  102. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-timeout.js +110 -0
  103. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +41 -538
  104. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +204 -108
  105. package/dist/extensions/agent-browser/lib/orchestration/browser-run/interaction-diagnostics.js +290 -0
  106. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-close.js +167 -0
  107. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-inspection.js +108 -0
  108. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +127 -199
  109. package/dist/extensions/agent-browser/lib/orchestration/browser-run/native-helper-observation.js +65 -0
  110. package/dist/extensions/agent-browser/lib/orchestration/browser-run/observation-types.js +1 -0
  111. package/dist/extensions/agent-browser/lib/orchestration/browser-run/overlay-diagnostics.js +120 -0
  112. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +113 -30
  113. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +109 -28
  114. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter-data.js +150 -0
  115. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +138 -253
  116. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-rendered-text.js +147 -0
  117. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +59 -24
  118. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-artifacts.js +159 -0
  119. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-command.js +131 -0
  120. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-contracts.js +1 -0
  121. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-daemon.js +93 -0
  122. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-failure.js +42 -0
  123. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-guards.js +242 -0
  124. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-input.js +75 -0
  125. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-observations.js +92 -0
  126. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-page-selection.js +254 -0
  127. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-page-state.js +121 -0
  128. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-refs.js +130 -0
  129. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-resources.js +114 -0
  130. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-semantic.js +121 -0
  131. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-session-plan.js +222 -0
  132. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-timeouts.js +68 -0
  133. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +176 -1114
  134. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-analysis.js +191 -0
  135. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-confirmation.js +152 -0
  136. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-diagnostics.js +182 -0
  137. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-electron.js +150 -0
  138. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-contracts.js +1 -0
  139. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-phase-contracts.js +1 -0
  140. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-phase.js +115 -0
  141. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle.js +256 -0
  142. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-managed-contracts.js +1 -0
  143. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-managed.js +256 -0
  144. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native-phase-contracts.js +1 -0
  145. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native-phase.js +93 -0
  146. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native.js +113 -0
  147. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-navigation-contracts.js +1 -0
  148. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-navigation.js +316 -0
  149. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-ownership.js +28 -0
  150. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-page-phase-contracts.js +1 -0
  151. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-page-phase.js +142 -0
  152. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-presentation-contracts.js +1 -0
  153. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-presentation.js +333 -0
  154. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication-phase-contracts.js +1 -0
  155. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication-phase.js +71 -0
  156. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication.js +201 -0
  157. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-receipts.js +183 -0
  158. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-refs.js +200 -0
  159. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-tabs.js +142 -0
  160. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +18 -910
  161. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +23 -13
  162. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-receipt-reconciliation.js +198 -0
  163. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery-contracts.js +1 -0
  164. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery-presentation.js +154 -0
  165. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery.js +68 -151
  166. package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-capture.js +14 -0
  167. package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-observation.js +169 -46
  168. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-commands.js +130 -0
  169. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-electron.js +210 -0
  170. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-observations.js +61 -0
  171. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-outcomes.js +187 -0
  172. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-refs.js +171 -0
  173. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-tabs.js +228 -0
  174. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +77 -753
  175. package/dist/extensions/agent-browser/lib/orchestration/browser-run/text-visibility-diagnostics.js +182 -0
  176. package/dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-diagnostics.js +256 -0
  177. package/dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-progress.js +108 -0
  178. package/dist/extensions/agent-browser/lib/orchestration/code-artifact-observation.js +39 -0
  179. package/dist/extensions/agent-browser/lib/orchestration/code-image-observation.js +119 -0
  180. package/dist/extensions/agent-browser/lib/orchestration/electron-host/branch.js +92 -0
  181. package/dist/extensions/agent-browser/lib/orchestration/electron-host/cleanup-result.js +58 -0
  182. package/dist/extensions/agent-browser/lib/orchestration/electron-host/cleanup.js +78 -0
  183. package/dist/extensions/agent-browser/lib/orchestration/electron-host/contracts.js +1 -0
  184. package/dist/extensions/agent-browser/lib/orchestration/electron-host/discovery.js +106 -0
  185. package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +48 -816
  186. package/dist/extensions/agent-browser/lib/orchestration/electron-host/policy.js +86 -0
  187. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-collection.js +69 -0
  188. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-data.js +167 -0
  189. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-presentation.js +164 -0
  190. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe.js +161 -0
  191. package/dist/extensions/agent-browser/lib/orchestration/electron-host/status.js +165 -0
  192. package/dist/extensions/agent-browser/lib/orchestration/execution-queue.js +21 -9
  193. package/dist/extensions/agent-browser/lib/orchestration/extension-artifact-preflight.js +211 -0
  194. package/dist/extensions/agent-browser/lib/orchestration/extension-artifacts.js +23 -0
  195. package/dist/extensions/agent-browser/lib/orchestration/extension-attachment-replay.js +99 -0
  196. package/dist/extensions/agent-browser/lib/orchestration/extension-branch-restore.js +275 -0
  197. package/dist/extensions/agent-browser/lib/orchestration/extension-code.js +280 -0
  198. package/dist/extensions/agent-browser/lib/orchestration/extension-command-admission.js +303 -0
  199. package/dist/extensions/agent-browser/lib/orchestration/extension-command-output.js +36 -0
  200. package/dist/extensions/agent-browser/lib/orchestration/extension-command-result.js +335 -0
  201. package/dist/extensions/agent-browser/lib/orchestration/extension-command-run.js +227 -0
  202. package/dist/extensions/agent-browser/lib/orchestration/extension-command-state.js +1 -0
  203. package/dist/extensions/agent-browser/lib/orchestration/extension-electron-ownership.js +204 -0
  204. package/dist/extensions/agent-browser/lib/orchestration/extension-execution-locks.js +139 -0
  205. package/dist/extensions/agent-browser/lib/orchestration/extension-execution-queue.js +24 -0
  206. package/dist/extensions/agent-browser/lib/orchestration/extension-host-coordination.js +98 -0
  207. package/dist/extensions/agent-browser/lib/orchestration/extension-host-run.js +295 -0
  208. package/dist/extensions/agent-browser/lib/orchestration/extension-intent-replay.js +41 -0
  209. package/dist/extensions/agent-browser/lib/orchestration/extension-invocation.js +7 -0
  210. package/dist/extensions/agent-browser/lib/orchestration/extension-lifecycle.js +102 -0
  211. package/dist/extensions/agent-browser/lib/orchestration/extension-managed-ownership.js +133 -0
  212. package/dist/extensions/agent-browser/lib/orchestration/extension-observation.js +120 -0
  213. package/dist/extensions/agent-browser/lib/orchestration/extension-prompt.js +180 -0
  214. package/dist/extensions/agent-browser/lib/orchestration/extension-recording.js +290 -0
  215. package/dist/extensions/agent-browser/lib/orchestration/extension-resource-contracts.js +1 -0
  216. package/dist/extensions/agent-browser/lib/orchestration/extension-resource-replay.js +269 -0
  217. package/dist/extensions/agent-browser/lib/orchestration/extension-result-state.js +113 -0
  218. package/dist/extensions/agent-browser/lib/orchestration/extension-runtime.js +146 -0
  219. package/dist/extensions/agent-browser/lib/orchestration/extension-script-leases.js +58 -0
  220. package/dist/extensions/agent-browser/lib/orchestration/extension-tool-boundary.js +62 -0
  221. package/dist/extensions/agent-browser/lib/orchestration/extension-version-check.js +54 -0
  222. package/dist/extensions/agent-browser/lib/orchestration/input-plan-types.js +1 -0
  223. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +261 -185
  224. package/dist/extensions/agent-browser/lib/orchestration/input-redaction.js +62 -0
  225. package/dist/extensions/agent-browser/lib/orchestration/native-config.js +144 -0
  226. package/dist/extensions/agent-browser/lib/orchestration/native-root-launch.js +77 -0
  227. package/dist/extensions/agent-browser/lib/orchestration/native-session-defaults.js +210 -139
  228. package/dist/extensions/agent-browser/lib/orchestration/operation-paths.js +124 -58
  229. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +198 -98
  230. package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +199 -96
  231. package/dist/extensions/agent-browser/lib/owned-managed-session-context.js +55 -0
  232. package/dist/extensions/agent-browser/lib/page-target-batch.js +118 -0
  233. package/dist/extensions/agent-browser/lib/page-target-guards.js +50 -0
  234. package/dist/extensions/agent-browser/lib/page-target-navigation.js +104 -0
  235. package/dist/extensions/agent-browser/lib/page-target-validation.js +59 -243
  236. package/dist/extensions/agent-browser/lib/parsing.js +13 -4
  237. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +134 -68
  238. package/dist/extensions/agent-browser/lib/playbook.js +18 -14
  239. package/dist/extensions/agent-browser/lib/process-child.js +284 -0
  240. package/dist/extensions/agent-browser/lib/process-environment.js +22 -6
  241. package/dist/extensions/agent-browser/lib/process-errors.js +23 -0
  242. package/dist/extensions/agent-browser/lib/process-identity.js +47 -15
  243. package/dist/extensions/agent-browser/lib/process-socket-storage.js +256 -0
  244. package/dist/extensions/agent-browser/lib/process-stdout.js +74 -0
  245. package/dist/extensions/agent-browser/lib/process.js +146 -537
  246. package/dist/extensions/agent-browser/lib/prompt-artifacts.js +287 -0
  247. package/dist/extensions/agent-browser/lib/prompt-policy.js +15 -194
  248. package/dist/extensions/agent-browser/lib/read-command.js +41 -0
  249. package/dist/extensions/agent-browser/lib/read-confirmation.js +138 -35
  250. package/dist/extensions/agent-browser/lib/recording-reservations.js +118 -45
  251. package/dist/extensions/agent-browser/lib/redaction-fields.js +75 -0
  252. package/dist/extensions/agent-browser/lib/redaction-json.js +149 -0
  253. package/dist/extensions/agent-browser/lib/redaction-url.js +88 -0
  254. package/dist/extensions/agent-browser/lib/results/action-contracts.js +1 -0
  255. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +28 -271
  256. package/dist/extensions/agent-browser/lib/results/artifact-contracts.js +1 -0
  257. package/dist/extensions/agent-browser/lib/results/artifact-manifest-validation.js +133 -0
  258. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +96 -94
  259. package/dist/extensions/agent-browser/lib/results/artifact-recommendations.js +73 -0
  260. package/dist/extensions/agent-browser/lib/results/categories.js +111 -54
  261. package/dist/extensions/agent-browser/lib/results/confirmation.js +29 -10
  262. package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +62 -27
  263. package/dist/extensions/agent-browser/lib/results/electron-recommendations.js +83 -0
  264. package/dist/extensions/agent-browser/lib/results/envelope-decoding.js +48 -0
  265. package/dist/extensions/agent-browser/lib/results/envelope.js +93 -66
  266. package/dist/extensions/agent-browser/lib/results/evidence-contracts.js +1 -0
  267. package/dist/extensions/agent-browser/lib/results/failure-recommendations.js +180 -0
  268. package/dist/extensions/agent-browser/lib/results/network-routes.js +86 -45
  269. package/dist/extensions/agent-browser/lib/results/network.js +35 -12
  270. package/dist/extensions/agent-browser/lib/results/next-actions.js +49 -19
  271. package/dist/extensions/agent-browser/lib/results/presentation/artifact-files.js +320 -0
  272. package/dist/extensions/agent-browser/lib/results/presentation/artifact-format.js +138 -0
  273. package/dist/extensions/agent-browser/lib/results/presentation/artifact-images.js +113 -0
  274. package/dist/extensions/agent-browser/lib/results/presentation/artifact-verification.js +145 -0
  275. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +99 -552
  276. package/dist/extensions/agent-browser/lib/results/presentation/batch-contracts.js +1 -0
  277. package/dist/extensions/agent-browser/lib/results/presentation/batch-recording.js +118 -0
  278. package/dist/extensions/agent-browser/lib/results/presentation/batch-redaction.js +68 -0
  279. package/dist/extensions/agent-browser/lib/results/presentation/batch-rendering.js +135 -0
  280. package/dist/extensions/agent-browser/lib/results/presentation/batch-step.js +227 -0
  281. package/dist/extensions/agent-browser/lib/results/presentation/batch-summary.js +91 -0
  282. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +91 -460
  283. package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +9 -5
  284. package/dist/extensions/agent-browser/lib/results/presentation/command-presenters.js +216 -0
  285. package/dist/extensions/agent-browser/lib/results/presentation/common.js +26 -9
  286. package/dist/extensions/agent-browser/lib/results/presentation/content.js +86 -29
  287. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-a11y.js +67 -0
  288. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-health.js +79 -0
  289. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-identity.js +199 -0
  290. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-logs.js +75 -0
  291. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-network-actions.js +216 -0
  292. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-network.js +124 -0
  293. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-redaction.js +64 -0
  294. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-storage.js +209 -0
  295. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-stream.js +69 -0
  296. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-summary.js +222 -0
  297. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +103 -1019
  298. package/dist/extensions/agent-browser/lib/results/presentation/early-result.js +70 -0
  299. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +130 -60
  300. package/dist/extensions/agent-browser/lib/results/presentation/input-contracts.js +1 -0
  301. package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +60 -145
  302. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +147 -88
  303. package/dist/extensions/agent-browser/lib/results/presentation/notices.js +75 -0
  304. package/dist/extensions/agent-browser/lib/results/presentation/observation-contracts.js +1 -0
  305. package/dist/extensions/agent-browser/lib/results/presentation/observation-rendering.js +127 -0
  306. package/dist/extensions/agent-browser/lib/results/presentation/outcomes.js +120 -0
  307. package/dist/extensions/agent-browser/lib/results/presentation/output-completion.js +77 -0
  308. package/dist/extensions/agent-browser/lib/results/presentation/output-spill.js +51 -0
  309. package/dist/extensions/agent-browser/lib/results/presentation/registry.js +117 -237
  310. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +35 -21
  311. package/dist/extensions/agent-browser/lib/results/presentation/skills.js +104 -73
  312. package/dist/extensions/agent-browser/lib/results/presentation/source.js +109 -0
  313. package/dist/extensions/agent-browser/lib/results/presentation.js +17 -248
  314. package/dist/extensions/agent-browser/lib/results/recommendation-contracts.js +1 -0
  315. package/dist/extensions/agent-browser/lib/results/recording.js +52 -14
  316. package/dist/extensions/agent-browser/lib/results/recovery-actions.js +14 -5
  317. package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +30 -22
  318. package/dist/extensions/agent-browser/lib/results/selector-recovery-target.js +83 -0
  319. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +123 -123
  320. package/dist/extensions/agent-browser/lib/results/snapshot-compact.js +266 -0
  321. package/dist/extensions/agent-browser/lib/results/snapshot-content.js +32 -0
  322. package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +104 -71
  323. package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +31 -11
  324. package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +125 -66
  325. package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +26 -7
  326. package/dist/extensions/agent-browser/lib/results/snapshot.js +28 -248
  327. package/dist/extensions/agent-browser/lib/results/text.js +16 -5
  328. package/dist/extensions/agent-browser/lib/runtime-args-validation.js +133 -0
  329. package/dist/extensions/agent-browser/lib/runtime-compatibility.js +81 -0
  330. package/dist/extensions/agent-browser/lib/runtime-contracts.js +1 -0
  331. package/dist/extensions/agent-browser/lib/runtime-redaction.js +118 -0
  332. package/dist/extensions/agent-browser/lib/runtime-replay-events.js +144 -0
  333. package/dist/extensions/agent-browser/lib/runtime-session-identity.js +76 -0
  334. package/dist/extensions/agent-browser/lib/runtime-session-plan.js +114 -0
  335. package/dist/extensions/agent-browser/lib/runtime-session-replay.js +123 -0
  336. package/dist/extensions/agent-browser/lib/runtime-tab-correction.js +65 -0
  337. package/dist/extensions/agent-browser/lib/runtime-timeouts.js +28 -0
  338. package/dist/extensions/agent-browser/lib/runtime.js +137 -1037
  339. package/dist/extensions/agent-browser/lib/session-identity.js +51 -0
  340. package/dist/extensions/agent-browser/lib/session-page-observation.js +357 -0
  341. package/dist/extensions/agent-browser/lib/session-page-state.js +188 -324
  342. package/dist/extensions/agent-browser/lib/session-page-types.js +1 -0
  343. package/dist/extensions/agent-browser/lib/temp-artifact-budget.js +78 -0
  344. package/dist/extensions/agent-browser/lib/temp-mutation-queue.js +7 -0
  345. package/dist/extensions/agent-browser/lib/temp-root-ownership.js +234 -0
  346. package/dist/extensions/agent-browser/lib/temp-root.js +207 -0
  347. package/dist/extensions/agent-browser/lib/temp.js +33 -446
  348. package/dist/extensions/agent-browser/lib/tool-surface.js +94 -24
  349. package/dist/extensions/agent-browser/lib/upstream-version.js +3 -2
  350. package/dist/extensions/agent-browser/lib/web-search-providers.js +229 -0
  351. package/dist/extensions/agent-browser/lib/web-search-request.js +108 -0
  352. package/dist/extensions/agent-browser/lib/web-search-results.js +281 -0
  353. package/dist/extensions/agent-browser/lib/web-search-schema.js +82 -0
  354. package/dist/extensions/agent-browser/lib/web-search.js +109 -617
  355. package/dist/extensions/agent-browser/lib/webmcp-observation.js +13 -6
  356. package/dist/extensions/agent-browser/lib/windows-stock-launcher.js +63 -37
  357. package/dist/extensions/agent-browser/script-worker.js +80 -43
  358. package/dist/scripts/agent-browser-target.mjs +4 -2
  359. package/docs/ARCHITECTURE.md +22 -10
  360. package/docs/CODE_QUALITY.md +242 -0
  361. package/docs/COMMAND_REFERENCE.md +264 -229
  362. package/docs/ELECTRON.md +53 -44
  363. package/docs/RELEASE.md +21 -17
  364. package/docs/REQUIREMENTS.md +2 -0
  365. package/docs/SESSION_STORAGE.md +1 -1
  366. package/docs/SUPPORT_MATRIX.md +84 -77
  367. package/docs/TOOL_CONTRACT.md +165 -130
  368. package/docs/platform-smoke.md +5 -5
  369. package/package.json +143 -120
  370. package/scripts/agent-browser-capability-baseline.mjs +361 -957
  371. package/scripts/agent-browser-target.mjs +6 -2
  372. package/scripts/build.mjs +37 -8
  373. package/scripts/capability-core-commands.mjs +193 -0
  374. package/scripts/capability-options.mjs +283 -0
  375. package/scripts/capability-samples.mjs +133 -0
  376. package/scripts/capability-section.mjs +11 -0
  377. package/scripts/config.mjs +213 -114
  378. package/scripts/convert-browser-session.mjs +30 -9
  379. package/scripts/doctor-sources.mjs +195 -0
  380. package/scripts/doctor.mjs +92 -247
  381. package/scripts/platform-smoke/artifacts.mjs +38 -11
  382. package/scripts/platform-smoke/commands.mjs +104 -0
  383. package/scripts/platform-smoke/crabbox-runner.mjs +167 -80
  384. package/scripts/platform-smoke/doctor-support.mjs +157 -0
  385. package/scripts/platform-smoke/doctor-windows.mjs +230 -0
  386. package/scripts/platform-smoke/doctor.mjs +212 -320
  387. package/scripts/platform-smoke/lease-evidence.mjs +134 -0
  388. package/scripts/platform-smoke/suite-checks.mjs +98 -0
  389. package/scripts/platform-smoke/suite-evidence.mjs +281 -0
  390. package/scripts/platform-smoke/targets.mjs +158 -472
  391. package/scripts/platform-smoke.mjs +55 -40
  392. package/scripts/prepare.mjs +16 -7
@@ -1,1063 +1,163 @@
1
- import { createHash, randomUUID } from "node:crypto";
2
- import { basename } from "node:path";
3
- import { extractUpstreamCommandTokens, findCommandStartIndex, parseArgvDescriptor, parseCommandInfo, } from "./argv-descriptor.js";
4
- import { batchHasSuccessfulCloseAll, getSuccessfulBatchCloseLifecycle } from "./batch-lifecycle.js";
5
- import { getBrowserResultMessage } from "./browser-transcript.js";
6
- import { canonicalizeAgentBrowserNamespace, extractExplicitNamespace, extractExplicitSessionName, getAgentBrowserSessionIdentityKey, getBooleanFlagValue, GLOBAL_BOOLEAN_FLAGS_WITH_OPTIONAL_VALUES, GLOBAL_VALUE_FLAGS_ALLOWING_DASH_VALUE, isAgentBrowserSessionIdentityKeyInNamespace, isUpstreamEnvFlagEnabled, PREVALIDATED_VALUE_FLAGS, projectUpstreamGlobalFlags, resolveAgentBrowserNamespace, scanUpstreamGlobalFlagOccurrences, stripUpstreamGlobalFlags, } from "./argv-grammar.js";
1
+ import { parseArgvDescriptor } from "./argv-descriptor.js";
2
+ import { canonicalizeAgentBrowserNamespace, extractExplicitNamespace, extractExplicitSessionName, getAgentBrowserSessionIdentityKey, getBooleanFlagValue, scanUpstreamGlobalFlagOccurrences, } from "./argv-grammar.js";
7
3
  import { needsManagedSession } from "./command-policy.js";
8
- import { parseBatchCommandArgument } from "./orchestration/batch-stdin.js";
9
- import { isCloseAllCommand, isCloseCommand, isOpenNavigationCommand } from "./command-taxonomy.js";
10
- import { hasLaunchScopedFlagToken, LAUNCH_SCOPED_FLAG_DEFINITIONS, LAUNCH_SCOPED_FLAG_LABEL, } from "./launch-scoped-flags.js";
11
- import { MANAGED_SESSION_NAME_PREFIX, } from "./managed-session-restore.js";
12
- export { extractCommandTokens, extractUpstreamCommandTokens, findCommandStartIndex, parseArgvDescriptor, parseCommandInfo, parseWaitCommandTokens } from "./argv-descriptor.js";
13
- import { isRecord } from "./parsing.js";
4
+ import { isCloseCommand } from "./command-taxonomy.js";
5
+ import { hasLaunchScopedFlagToken, LAUNCH_SCOPED_FLAG_DEFINITIONS } from "./launch-scoped-flags.js";
14
6
  import { getAgentBrowserProcessEnvironment } from "./process-environment.js";
15
- import { TARGET_AGENT_BROWSER_VERSION } from "./upstream-version.js";
16
- const OPENAI_HEADLESS_COMPAT_HOSTS = new Set(["chat.com", "chat.openai.com", "chatgpt.com"]);
17
- const CLOUDFLARE_HEADLESS_COMPAT_HOST = "dash.cloudflare.com";
18
- const AGENT_BROWSER_IDLE_TIMEOUT_ENV = "AGENT_BROWSER_IDLE_TIMEOUT_MS";
19
- const IMPLICIT_SESSION_IDLE_TIMEOUT_ENV = "PI_AGENT_BROWSER_IMPLICIT_SESSION_IDLE_TIMEOUT_MS";
20
- const IMPLICIT_SESSION_CLOSE_TIMEOUT_ENV = "PI_AGENT_BROWSER_IMPLICIT_SESSION_CLOSE_TIMEOUT_MS";
21
- const DEFAULT_IMPLICIT_SESSION_IDLE_TIMEOUT_MS = 15 * 60 * 1000;
22
- // Native close includes a five-second Chrome exit grace after protocol shutdown.
23
- // Use the normal CLI watchdog budget rather than interrupting that grace.
24
- const DEFAULT_IMPLICIT_SESSION_CLOSE_TIMEOUT_MS = 35_000;
25
- const INSPECTION_FLAGS = new Set(["--help", "-h", "--version", "-V"]);
26
- const SENSITIVE_VALUE_FLAGS = new Set(["--body", "--headers", "--password", "--proxy"]);
27
- const SENSITIVE_QUERY_PARAM_PATTERN = /^(?:access(?:_|-)?token|api(?:_|-)?key|auth|authorization|authorization(?:_|-)?session(?:_|-)?id|bearer|client(?:_|-)?secret|code|cookie|id(?:_|-)?token|key|pass(?:word)?|refresh(?:_|-)?token|relay(?:_|-)?state|saml(?:_|-)?request|saml(?:_|-)?response|secret|sentry(?:_|-)?key|session(?:_|-)?id|sig(?:nature)?|token|write(?:_|-)?key)$/i;
28
- const AUTH_STATE_QUERY_PARAM_PATTERN = /^(?:nonce|state)$/i;
29
- const AUTH_URL_CONTEXT_PATTERN = /(?:^|[./_-])(?:auth|authorize|callback|login|oauth2?|oidc|saml|sso)(?:[./?#_-]|$)/i;
30
- const SENSITIVE_FIELD_NAME_PATTERN = /^(?:[A-Za-z0-9_-]*(?:api[_-]?key|access[_-]?key|private[_-]?key|secret(?:[_-]?(?:key|access[_-]?key))?|token|password|passwd|credentials?|database[_-]?url|db[_-]?url|connection[_-]?string|mongo(?:db)?[_-]?uri|redis[_-]?url)|[A-Za-z0-9]*(?:apiKey|ApiKey|apikey|privateKey|PrivateKey|databaseUrl|DatabaseUrl|dbUrl|DbUrl|connectionString|ConnectionString|mongoUri|MongoUri|mongodbUri|MongodbUri|mongoDbUri|MongoDbUri|redisUrl|RedisUrl|Token|Secret|Password|Credential|Credentials)|auth(?:orization)?|bearer|client(?:_|-)?secret|cookie|id(?:_|-)?token|pass(?:word)?|proxy(?:_|-)?authorization|refresh(?:_|-)?token|sentry(?:_|-)?key|session(?:_|-)?id|set(?:_|-)?cookie|sig(?:nature)?|write(?:_|-)?key|x(?:_|-)?api(?:_|-)?key)$/i;
31
- const ENV_SECRET_ASSIGNMENT_PATTERN = /\b((?:export\s+)?([A-Za-z_][A-Za-z0-9_-]*)(\s*[:=]\s*))(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,;]+)/g;
32
- const DEFAULT_HEADLESS_COMPAT_USER_AGENT_BY_PLATFORM = {
33
- darwin: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
34
- linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
35
- win32: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
36
- };
37
- const FALLBACK_HEADLESS_COMPAT_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36";
38
- const SHELL_OPERATOR_TOKENS = new Set(["&&", "||", "|", ";", ">", ">>", "<"]);
39
- const ANDROID_SESSION_NAME_IDENTITY_LENGTH = 20;
40
- const MAX_PROJECT_SLUG_LENGTH = 24;
41
- const SESSION_NAME_CWD_HASH_LENGTH = 8;
42
- const SESSION_NAME_SESSION_ID_LENGTH = 12;
43
- function isStringArray(value) {
44
- return Array.isArray(value) && value.every((item) => typeof item === "string");
45
- }
46
- function shouldRedactQueryParam(name) {
47
- return SENSITIVE_QUERY_PARAM_PATTERN.test(name) || isSensitiveFieldName(name);
48
- }
49
- function redactUrlToken(token) {
50
- let parsed;
51
- try {
52
- parsed = new URL(token);
53
- }
54
- catch {
55
- return token;
56
- }
57
- const originalHref = parsed.href;
58
- if (parsed.username.length > 0)
59
- parsed.username = "[REDACTED]";
60
- if (parsed.password.length > 0)
61
- parsed.password = "[REDACTED]";
62
- const hashText = parsed.hash.startsWith("#") ? parsed.hash.slice(1) : parsed.hash;
63
- const hashParams = hashText.includes("=") ? new URLSearchParams(hashText) : undefined;
64
- const authContext = AUTH_URL_CONTEXT_PATTERN.test(`${parsed.hostname}${parsed.pathname}`)
65
- || [...parsed.searchParams.keys(), ...(hashParams?.keys() ?? [])].some(shouldRedactQueryParam);
66
- for (const [name] of parsed.searchParams) {
67
- if (shouldRedactQueryParam(name) || (authContext && AUTH_STATE_QUERY_PARAM_PATTERN.test(name))) {
68
- parsed.searchParams.set(name, "[REDACTED]");
69
- }
70
- }
71
- if (hashParams) {
72
- let hashMutated = false;
73
- for (const [name] of hashParams) {
74
- if (shouldRedactQueryParam(name) || (authContext && AUTH_STATE_QUERY_PARAM_PATTERN.test(name))) {
75
- hashParams.set(name, "[REDACTED]");
76
- hashMutated = true;
77
- }
78
- }
79
- if (hashMutated)
80
- parsed.hash = `#${hashParams.toString()}`;
81
- }
82
- return parsed.href === originalHref ? token : parsed.href;
83
- }
84
- function redactLooseUrlParameterText(text) {
85
- return text.replace(/(?<![^\s"'`<>\])}])[^\s"'`<>\])}]*[?#&][^\s"'`<>\])}]*/g, (token) => {
86
- const queryNames = [...token.matchAll(/[?#&]([^=&#\s"'`<>\])}]+)=/g)].map((match) => {
87
- try {
88
- return decodeURIComponent((match[1] ?? "").replace(/\+/g, " "));
89
- }
90
- catch {
91
- return match[1] ?? "";
92
- }
93
- });
94
- const authContext = AUTH_URL_CONTEXT_PATTERN.test(token) || queryNames.some(shouldRedactQueryParam);
95
- return token.replace(/([?#&])([^=&#\s"'`<>\])}]+)=([^&#\s"'`<>\])}]*)/g, (match, separator, rawName, rawValue) => {
96
- if (rawValue === "[REDACTED" || rawValue === "[REDACTED]" || /%5Bredacted%5D/i.test(rawValue))
97
- return match;
98
- let name = rawName;
99
- try {
100
- name = decodeURIComponent(rawName.replace(/\+/g, " "));
101
- }
102
- catch {
103
- // Keep the raw name when percent decoding fails.
104
- }
105
- if (!shouldRedactQueryParam(name) && !(authContext && AUTH_STATE_QUERY_PARAM_PATTERN.test(name)))
106
- return match;
107
- return `${separator}${rawName}=[REDACTED]`;
108
- });
109
- });
110
- }
111
- function redactLooseUrlUserinfo(text) {
112
- return text.replace(/\b([A-Za-z][A-Za-z0-9+.-]*:\/\/)([^\s"'`/@]+)@([^\s"'`]+)/g, (match, prefix, userinfo, suffix) => {
113
- if (/%5Bredacted%5D/i.test(userinfo))
114
- return match;
115
- if (userinfo.includes("[REDACTED]"))
116
- return redactLooseUrlParameterText(match);
117
- return redactLooseUrlParameterText(`${prefix}${userinfo.includes(":") ? "[REDACTED]:[REDACTED]" : "[REDACTED]"}@${suffix}`);
118
- });
119
- }
120
- function redactLooseUrlMatches(text) {
121
- return text.replace(/\b[A-Za-z][A-Za-z0-9+.-]*:\/\/[^\s"'`<>\])]+/g, (match) => redactUrlToken(match));
122
- }
123
- function createBalancedJsonEndFinder(text) {
124
- let boundaries;
125
- return (startIndex) => {
126
- const opener = text[startIndex];
127
- if (opener !== "{" && opener !== "[")
128
- return undefined;
129
- if (!boundaries) {
130
- // Resolve each suffix once: skip strings and balanced groups to its first unmatched closer.
131
- boundaries = new Int32Array(text.length + 1).fill(-1);
132
- let quoteAtNext = -1;
133
- let quoteAfterNext = -1;
134
- for (let index = text.length - 1; index >= 0; index -= 1) {
135
- const char = text[index];
136
- if (char === "}" || char === "]") {
137
- boundaries[index] = index;
138
- }
139
- else if (char === '"') {
140
- boundaries[index] = quoteAtNext < 0 ? -1 : boundaries[quoteAtNext + 1];
141
- }
142
- else if (char === "{" || char === "[") {
143
- const end = boundaries[index + 1];
144
- boundaries[index] = end >= 0 && text[end] === (char === "{" ? "}" : "]") ? boundaries[end + 1] : -1;
145
- }
146
- else {
147
- boundaries[index] = boundaries[index + 1];
148
- }
149
- // Inside a string, backslash skips one character; outside, it is ordinary text.
150
- const quote = char === '"' ? index : char === "\\" ? quoteAfterNext : quoteAtNext;
151
- quoteAfterNext = quoteAtNext;
152
- quoteAtNext = quote;
153
- }
154
- }
155
- const end = boundaries[startIndex + 1];
156
- return end >= 0 && text[end] === (opener === "{" ? "}" : "]") ? end : undefined;
157
- };
158
- }
159
- function redactSerializedJson(text) {
160
- // Validate grammar only; rebuilding parsed values loses duplicates and numeric spelling.
161
- try {
162
- JSON.parse(text);
163
- }
164
- catch {
165
- return undefined;
166
- }
167
- let output = "";
168
- let cursor = 0;
169
- const findEnd = createBalancedJsonEndFinder(text);
170
- const strings = /"(?:\\.|[^"\\])*"/g;
171
- let match;
172
- while ((match = strings.exec(text)) !== null) {
173
- const end = strings.lastIndex;
174
- const value = JSON.parse(match[0]);
175
- const redacted = redactSensitiveText(value);
176
- if (redacted !== value) {
177
- output += text.slice(cursor, match.index) + JSON.stringify(redacted);
178
- cursor = end;
179
- }
180
- const separator = /^\s*:\s*/.exec(text.slice(end));
181
- if (!separator || !isSensitiveFieldName(value))
182
- continue;
183
- const valueStart = end + separator[0].length;
184
- let valueEnd = findEnd(valueStart);
185
- if (valueEnd !== undefined) {
186
- valueEnd += 1;
187
- }
188
- else if (text[valueStart] === '"') {
189
- strings.lastIndex = valueStart;
190
- const fieldValue = strings.exec(text);
191
- valueEnd = strings.lastIndex;
192
- if (JSON.parse(fieldValue[0]) === "[REDACTED]")
193
- continue;
194
- }
195
- else {
196
- valueEnd = valueStart;
197
- while (valueEnd < text.length && !/[\s,\]}]/.test(text[valueEnd]))
198
- valueEnd += 1;
199
- }
200
- output += text.slice(cursor, valueStart) + '"[REDACTED]"';
201
- cursor = valueEnd;
202
- strings.lastIndex = valueEnd;
203
- }
204
- return output + text.slice(cursor);
205
- }
206
- function redactEmbeddedStructuredText(text) {
207
- let output = "";
208
- let cursor = 0;
209
- const findEnd = createBalancedJsonEndFinder(text);
210
- while (cursor < text.length) {
211
- const char = text[cursor];
212
- if (char !== "{" && char !== "[") {
213
- output += char;
214
- cursor += 1;
215
- continue;
216
- }
217
- const endIndex = findEnd(cursor);
218
- if (endIndex === undefined) {
219
- output += char;
220
- cursor += 1;
221
- continue;
222
- }
223
- const candidate = text.slice(cursor, endIndex + 1);
224
- output += redactSerializedJson(candidate) ?? candidate;
225
- cursor = endIndex + 1;
226
- }
227
- return output;
228
- }
229
- function redactStandaloneBasicCredential(text) {
230
- return text.replace(/\b(Basic)\s+([A-Za-z0-9+/=]{12,})/gi, (match, label, credential) => {
231
- if (!/[0-9+/=]/.test(credential))
232
- return match;
233
- return `${label} [REDACTED]`;
234
- });
235
- }
236
- function credentialTrailingPunctuation(credential) {
237
- return credential.match(/[,.:;!?]+$/)?.[0] ?? "";
238
- }
239
- function formatRedactedCredential(label, credential, trailing = "") {
240
- return `${label} [REDACTED]${credentialTrailingPunctuation(credential)}${trailing}`;
241
- }
242
- function redactBearerCredentials(text) {
243
- return text
244
- .replace(/((?:\b([A-Za-z][A-Za-z0-9_-]*)\s*[:=]\s*|(?:^|\s)(?:-H\s*|--header(?:\s+|=)))["']?Bearer)\s+([^\s"',)\[\]]+)([),.]?)/gi, (match, label, field, credential, trailing) => {
245
- if (field && !isSensitiveFieldName(field))
246
- return match;
247
- return formatRedactedCredential(label, credential, trailing);
248
- })
249
- .replace(/\b(Bearer)\s+([^\s\\"',)\[\]]+)([),.]?)/gi, (match, label, credential, trailing) => {
250
- // Without a credential field/header, require a bearer-token shape, not prose, HTML or a URL.
251
- const token = credential.slice(0, credential.length - credentialTrailingPunctuation(credential).length);
252
- if (!/^[A-Za-z0-9._~+/-]+=*$/.test(token) || !/[0-9._~+/=-]/.test(token))
253
- return match;
254
- return formatRedactedCredential(label, credential, trailing);
255
- });
256
- }
257
- function isSensitiveFieldName(key) {
258
- SENSITIVE_FIELD_NAME_PATTERN.lastIndex = 0;
259
- return SENSITIVE_FIELD_NAME_PATTERN.test(key);
260
- }
261
- function isEnvSecretAssignmentKey(key) {
262
- if (!isSensitiveFieldName(key))
263
- return false;
264
- if (key === "password" || key.includes("_") || key.includes("-") || key === key.toUpperCase())
265
- return true;
266
- return /(?:apiKey|ApiKey|privateKey|PrivateKey|databaseUrl|DatabaseUrl|dbUrl|DbUrl|connectionString|ConnectionString|mongoUri|MongoUri|mongodbUri|MongodbUri|mongoDbUri|MongoDbUri|redisUrl|RedisUrl|Token|Secret|Password|Credential|Credentials)$/.test(key);
267
- }
268
- function redactEnvSecretAssignments(text) {
269
- return text.replace(ENV_SECRET_ASSIGNMENT_PATTERN, (match, prefix, key, _separator, offset) => {
270
- if (!isEnvSecretAssignmentKey(key))
271
- return match;
272
- if (key === "password") {
273
- // The loose matcher cannot safely distinguish inline punctuation from password characters.
274
- const end = offset + match.length;
275
- if ((offset > 0 && text[offset - 1] !== "\n" && text[offset - 1] !== "\r")
276
- || (end < text.length && text[end] !== "\n" && text[end] !== "\r")
277
- || /^(?:\[REDACTED\]|%5Bredacted%5D)/i.test(match.slice(prefix.length)))
278
- return match;
279
- const value = match.slice(prefix.length);
280
- const boundary = value[0] === '"' || value[0] === "'" ? -1 : value.search(/[&#](?=[A-Za-z_][A-Za-z0-9_-]*\s*=)/);
281
- return `${prefix}[REDACTED]${boundary < 0 ? "" : value.slice(boundary)}`;
282
- }
283
- return `${prefix}[REDACTED]`;
284
- });
285
- }
286
- export function redactSensitiveText(text) {
287
- // Redact JSON string literals before text heuristics can consume their escapes.
288
- // Non-JSON stays whole so assignments and headers retain their credential context.
289
- const serialized = redactSerializedJson(text);
290
- if (serialized !== undefined)
291
- return serialized;
292
- const embeddedRedactedText = redactEmbeddedStructuredText(text);
293
- return redactEmbeddedStructuredText(redactEnvSecretAssignments(redactStandaloneBasicCredential(redactBearerCredentials(redactLooseUrlParameterText(redactLooseUrlUserinfo(redactLooseUrlMatches(embeddedRedactedText))))
294
- .replace(/\b(Authorization\s*:\s*Basic)\s+[^\s",]+/gi, "$1 [REDACTED]")
295
- .replace(/\b(Cookie|Set-Cookie)\s*:\s*[^\n\r"]+/gi, "$1: [REDACTED]"))));
296
- }
297
- export function redactSensitiveValue(value) {
298
- if (typeof value === "string") {
299
- return redactSensitiveText(value);
300
- }
301
- if (Array.isArray(value)) {
302
- return value.map((item) => redactSensitiveValue(item));
303
- }
304
- if (!isRecord(value)) {
305
- return value;
306
- }
307
- return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => {
308
- if (isSensitiveFieldName(key)) {
309
- return [key, "[REDACTED]"];
310
- }
311
- return [key, redactSensitiveValue(entryValue)];
312
- }));
313
- }
314
- function redactFlagValue(flag, value) {
315
- if (SENSITIVE_VALUE_FLAGS.has(flag)) {
316
- return "[REDACTED]";
317
- }
318
- return redactUrlToken(value);
319
- }
320
- export function redactInvocationArgs(args) {
321
- const redacted = [];
322
- let pendingValueFlag;
323
- for (const token of args) {
324
- if (pendingValueFlag) {
325
- redacted.push(redactFlagValue(pendingValueFlag, token));
326
- pendingValueFlag = undefined;
327
- continue;
328
- }
329
- const normalizedToken = token.split("=", 1)[0] ?? token;
330
- if (SENSITIVE_VALUE_FLAGS.has(normalizedToken)) {
331
- if (token.includes("=")) {
332
- redacted.push(`${normalizedToken}=[REDACTED]`);
333
- }
334
- else {
335
- redacted.push(token);
336
- pendingValueFlag = normalizedToken;
337
- }
338
- continue;
339
- }
340
- redacted.push(redactSensitiveText(redactUrlToken(token)));
341
- }
342
- const commandStartIndex = findCommandStartIndex(args);
343
- if (commandStartIndex !== undefined && args[commandStartIndex] === "set" && args[commandStartIndex + 1] === "credentials") {
344
- for (const index of [commandStartIndex + 2, commandStartIndex + 3]) {
345
- if (redacted[index] !== undefined) {
346
- redacted[index] = "[REDACTED]";
347
- }
348
- }
349
- }
350
- if (commandStartIndex !== undefined && args[commandStartIndex] === "cookies" && args[commandStartIndex + 1] === "set"
351
- && !extractUpstreamCommandTokens(args).slice(2).includes("--curl")
352
- && redacted[commandStartIndex + 3] !== undefined) {
353
- redacted[commandStartIndex + 3] = "[REDACTED]";
354
- }
355
- if (commandStartIndex !== undefined
356
- && args[commandStartIndex] === "storage"
357
- && ["local", "session"].includes(args[commandStartIndex + 1] ?? "")
358
- && args[commandStartIndex + 2] === "set"
359
- && redacted[commandStartIndex + 4] !== undefined) {
360
- redacted[commandStartIndex + 4] = "[REDACTED]";
361
- }
362
- if (commandStartIndex !== undefined && args[commandStartIndex] === "clipboard" && args[commandStartIndex + 1] === "write") {
363
- for (let index = commandStartIndex + 2; index < redacted.length; index += 1) {
364
- redacted[index] = "[REDACTED]";
365
- }
366
- }
367
- const batch = projectUpstreamGlobalFlags(args);
368
- if (batch.tokens[0] === "batch") {
369
- for (let index = 1; index < batch.tokens.length; index++) {
370
- if (batch.tokens[index] === "--bail")
371
- continue;
372
- const step = parseBatchCommandArgument(batch.tokens[index]).step;
373
- if (!step)
374
- continue;
375
- const safe = redactInvocationArgs(step);
376
- if (safe.some((token, offset) => token !== step[offset]))
377
- redacted[batch.indices[index]] = safe.map(token => `'${token.replaceAll("'", "'\\''")}'`).join(" ");
378
- }
379
- }
380
- return redacted;
381
- }
382
- export function isPlainTextInspectionArgs(args) {
383
- return args.some((token) => INSPECTION_FLAGS.has(token));
7
+ import { formatInvalidValueFlagError, getInvalidValueFlagDetails, isPlainTextInspectionArgs, } from "./runtime-args-validation.js";
8
+ import { canUseHeadlessCompatibilityUserAgent, getCompatibilityWorkaround, getDefaultHeadlessCompatUserAgent, } from "./runtime-compatibility.js";
9
+ import { freshSessionRecoveryHint, launchFlagsRecoveryReason, selectExecutionSession, stripExplicitIdentityArgs, } from "./runtime-session-plan.js";
10
+ export { extractCommandTokens, extractUpstreamCommandTokens, findCommandStartIndex, parseArgvDescriptor, parseCommandInfo, parseWaitCommandTokens, } from "./argv-descriptor.js";
11
+ export { redactSensitiveText, redactSensitiveValue, redactInvocationArgs, } from "./runtime-redaction.js";
12
+ export { getImplicitSessionIdleTimeoutMs, getImplicitSessionCloseTimeoutMs, } from "./runtime-timeouts.js";
13
+ export { isPlainTextInspectionArgs, validateToolArgs } from "./runtime-args-validation.js";
14
+ export { canUseHeadlessCompatibilityUserAgent, getDefaultHeadlessCompatUserAgent, } from "./runtime-compatibility.js";
15
+ export { createEphemeralSessionSeed, createImplicitSessionName, createFreshSessionName, isRestorableManagedSessionName, resolveManagedSessionState, } from "./runtime-session-identity.js";
16
+ export { restoreManagedSessionStateFromBranch } from "./runtime-session-replay.js";
17
+ export { chooseOpenResultTabCorrection } from "./runtime-tab-correction.js";
18
+ export function getStartupScopedFlags(args) {
19
+ return LAUNCH_SCOPED_FLAG_DEFINITIONS.map((definition) => definition.flag).filter((flag) => hasLaunchScopedFlagToken(args, flag));
384
20
  }
385
- function parseTimeoutMs(rawValue, minimumValue) {
386
- if (typeof rawValue !== "string")
387
- return undefined;
388
- const normalizedValue = rawValue.trim();
389
- if (!/^\d+$/.test(normalizedValue))
390
- return undefined;
391
- const parsedValue = Number(normalizedValue);
392
- if (!Number.isSafeInteger(parsedValue) || parsedValue < minimumValue) {
393
- return undefined;
21
+ function withNativeSession(args) {
22
+ const nativeSession = getAgentBrowserProcessEnvironment().AGENT_BROWSER_SESSION;
23
+ if (nativeSession !== undefined &&
24
+ !isPlainTextInspectionArgs(args) &&
25
+ extractExplicitSessionName(args) === undefined) {
26
+ return ["--session", nativeSession, ...args];
394
27
  }
395
- return parsedValue;
396
- }
397
- export function getImplicitSessionIdleTimeoutMs(env = getAgentBrowserProcessEnvironment()) {
398
- return parseTimeoutMs(env[IMPLICIT_SESSION_IDLE_TIMEOUT_ENV], 0) ??
399
- parseTimeoutMs(env[AGENT_BROWSER_IDLE_TIMEOUT_ENV], 0) ??
400
- DEFAULT_IMPLICIT_SESSION_IDLE_TIMEOUT_MS;
28
+ return args;
401
29
  }
402
- function countExplicitGlobalFlags(args, targetFlag) {
403
- return scanUpstreamGlobalFlagOccurrences(args, targetFlag).length;
30
+ function jsonPrefix(args) {
31
+ return getBooleanFlagValue(args, "--json") === undefined ? ["--json"] : [];
404
32
  }
405
- export function getImplicitSessionCloseTimeoutMs(env = getAgentBrowserProcessEnvironment()) {
406
- return parseTimeoutMs(env[IMPLICIT_SESSION_CLOSE_TIMEOUT_ENV], 0) ?? DEFAULT_IMPLICIT_SESSION_CLOSE_TIMEOUT_MS;
407
- }
408
- export function resolveManagedSessionState(options) {
409
- const { command, managedSessionName, priorActive, priorSessionName, succeeded } = options;
410
- const managedSessionNamespace = canonicalizeAgentBrowserNamespace(options.managedSessionNamespace);
411
- const priorNamespace = canonicalizeAgentBrowserNamespace(options.priorNamespace);
412
- if (!managedSessionName) {
413
- return { active: priorActive, ...(priorNamespace ? { namespace: priorNamespace } : {}), sessionName: priorSessionName };
414
- }
415
- if (isCloseCommand(command) && managedSessionName === priorSessionName) {
416
- if (managedSessionNamespace !== priorNamespace)
417
- return { active: priorActive, ...(priorNamespace ? { namespace: priorNamespace } : {}), sessionName: priorSessionName };
418
- const namespace = succeeded ? undefined : priorNamespace;
419
- return { active: succeeded ? false : priorActive, ...(namespace ? { namespace } : {}), sessionName: priorSessionName };
420
- }
421
- if (!succeeded) {
422
- return { active: priorActive, ...(priorNamespace ? { namespace: priorNamespace } : {}), sessionName: priorSessionName };
423
- }
424
- return {
425
- active: true,
426
- ...(managedSessionNamespace ? { namespace: managedSessionNamespace } : {}),
427
- replacedSessionName: priorActive && priorSessionName !== managedSessionName ? priorSessionName : undefined,
428
- sessionName: managedSessionName,
33
+ function planningFailure(args) {
34
+ const invalidValueFlag = getInvalidValueFlagDetails(args);
35
+ const repeatedFlag = ["--session", "--namespace"].find((flag) => scanUpstreamGlobalFlagOccurrences(args, flag).length > 1);
36
+ if (!invalidValueFlag && repeatedFlag === undefined) {
37
+ return;
38
+ }
39
+ const validationError = invalidValueFlag
40
+ ? formatInvalidValueFlagError(invalidValueFlag)
41
+ : `Multiple ${repeatedFlag ?? ""} flags are not supported. Pass a single ${repeatedFlag ?? ""} value; upstream uses the last occurrence while this wrapper would otherwise mis-attribute managed-session ownership.`;
42
+ const plan = {
43
+ commandInfo: {},
44
+ effectiveArgs: jsonPrefix(args),
45
+ plainTextInspection: false,
46
+ startupScopedFlags: [],
47
+ usedImplicitSession: false,
48
+ validationError,
429
49
  };
50
+ return invalidValueFlag ? { ...plan, invalidValueFlag } : plan;
430
51
  }
431
- export function isRestorableManagedSessionName(sessionName, fallbackSessionName) {
432
- return sessionName === fallbackSessionName || sessionName.startsWith(`${fallbackSessionName}-fresh-`);
433
- }
434
- function getManagedSessionRestoreRank(options) {
435
- const { fallbackSessionName, freshSessionRanks, sessionName } = options;
436
- if (sessionName === fallbackSessionName) {
437
- return 0;
438
- }
439
- if (!sessionName.startsWith(`${fallbackSessionName}-fresh-`)) {
440
- return undefined;
441
- }
442
- const existingRank = freshSessionRanks.get(sessionName);
443
- if (existingRank !== undefined) {
444
- return existingRank;
445
- }
446
- const nextRank = freshSessionRanks.size + 1;
447
- freshSessionRanks.set(sessionName, nextRank);
448
- return nextRank;
449
- }
450
- function getRestorableManagedSessionName(value, fallbackSessionName) {
451
- return typeof value === "string" && isRestorableManagedSessionName(value, fallbackSessionName) ? value : undefined;
452
- }
453
- function getElectronCleanupClosedManagedSessions(details, fallbackSessionName) {
454
- const electron = isRecord(details.electron) ? details.electron : undefined;
455
- const cleanup = isRecord(electron?.cleanup) ? electron.cleanup : undefined;
456
- const results = Array.isArray(cleanup?.results) ? cleanup.results : [];
457
- const closedSessions = [];
458
- for (const result of results) {
459
- if (!isRecord(result) || !Array.isArray(result.steps))
460
- continue;
461
- const record = isRecord(result.record) ? result.record : undefined;
462
- const fallbackNamespace = typeof record?.namespace === "string"
463
- ? record.namespace
464
- : typeof details.namespace === "string" ? details.namespace : undefined;
465
- for (const step of result.steps) {
466
- if (!isRecord(step) || step.resource !== "managed-session")
467
- continue;
468
- if (step.state !== "removed" && step.state !== "already-gone")
469
- continue;
470
- const sessionName = getRestorableManagedSessionName(step.sessionName, fallbackSessionName)
471
- ?? getRestorableManagedSessionName(record?.sessionName, fallbackSessionName);
472
- const namespace = typeof step.namespace === "string" ? step.namespace : fallbackNamespace;
473
- if (sessionName)
474
- closedSessions.push({ namespace, sessionName });
475
- }
476
- }
477
- return closedSessions;
478
- }
479
- export function restoreManagedSessionStateFromBranch(branch, fallbackSessionName) {
480
- const restoreDisabledIdentities = new Map();
481
- let restoredState = {
482
- active: false,
483
- sessionName: fallbackSessionName,
484
- };
485
- let activeRestoreRank = 0;
486
- let closedSessionName;
487
- let freshSessionOrdinal = 0;
488
- const freshSessionRanks = new Map();
489
- const applyManagedClose = (sessionName, namespace) => {
490
- namespace = canonicalizeAgentBrowserNamespace(namespace);
491
- const restoreRank = getManagedSessionRestoreRank({
492
- fallbackSessionName,
493
- freshSessionRanks,
494
- sessionName,
495
- });
496
- if (restoreRank === undefined || sessionName !== restoredState.sessionName || namespace !== restoredState.namespace)
497
- return;
498
- restoredState = { active: false, sessionName: restoredState.sessionName };
499
- closedSessionName = sessionName;
500
- };
501
- for (const entry of branch) {
502
- const message = getBrowserResultMessage(entry);
503
- if (!message) {
504
- continue;
505
- }
506
- const details = isRecord(message.details) ? message.details : undefined;
507
- if (!details) {
508
- continue;
509
- }
510
- const args = isStringArray(details.args) ? details.args : [];
511
- if (isPlainTextInspectionArgs(args)) {
512
- continue;
513
- }
514
- for (const cleanupSession of getElectronCleanupClosedManagedSessions(details, fallbackSessionName)) {
515
- applyManagedClose(cleanupSession.sessionName, cleanupSession.namespace);
516
- }
517
- const explicitSessionName = extractExplicitSessionName(args);
518
- const sessionName = typeof details.sessionName === "string" ? details.sessionName : undefined;
519
- const namespace = canonicalizeAgentBrowserNamespace(typeof details.namespace === "string" ? details.namespace : undefined);
520
- const sessionMode = details.sessionMode === "fresh" || details.sessionMode === "auto" ? details.sessionMode : undefined;
521
- const usedImplicitSession = details.usedImplicitSession === true;
522
- const commandTokens = extractUpstreamCommandTokens(args);
523
- const command = typeof details.command === "string" ? details.command : parseCommandInfo(args).command;
524
- const batchCloseLifecycle = getSuccessfulBatchCloseLifecycle(details.batchSteps);
525
- const nestedBatchEndsClosed = batchCloseLifecycle?.endsClosed === true;
526
- const nestedBatchRemainsActive = batchCloseLifecycle?.endsClosed === false;
527
- const closeAllApplied = details.closeAllApplied === true
528
- || (message.isError !== true && isCloseAllCommand(commandTokens))
529
- || batchHasSuccessfulCloseAll(details.batchSteps);
530
- const commandClosesSession = isCloseCommand(command) || nestedBatchEndsClosed;
531
- const outcome = typeof details.managedSessionOutcome === "object" && details.managedSessionOutcome !== null ? details.managedSessionOutcome : undefined;
532
- const outcomeStatus = typeof outcome?.status === "string" ? outcome.status : undefined;
533
- const outcomeCurrentSessionName = typeof outcome?.currentSessionName === "string" ? outcome.currentSessionName : undefined;
534
- const outcomeAttemptedSessionName = getRestorableManagedSessionName(outcome?.attemptedSessionName, fallbackSessionName);
535
- const outcomeClosedSessionName = outcomeStatus === "closed" && outcome?.succeeded === true
536
- ? outcomeAttemptedSessionName ?? getRestorableManagedSessionName(outcomeCurrentSessionName, fallbackSessionName) ?? getRestorableManagedSessionName(sessionName, fallbackSessionName)
537
- : undefined;
538
- const restorableDetailSessionName = getRestorableManagedSessionName(sessionName, fallbackSessionName);
539
- if (closeAllApplied && restoredState.active) {
540
- const restoredKey = getAgentBrowserSessionIdentityKey(restoredState.sessionName, restoredState.namespace);
541
- const resultKey = restorableDetailSessionName ? getAgentBrowserSessionIdentityKey(restorableDetailSessionName, namespace) : undefined;
542
- const retainsCurrentSession = nestedBatchRemainsActive && resultKey === restoredKey;
543
- if (isAgentBrowserSessionIdentityKeyInNamespace(restoredKey, namespace) && !retainsCurrentSession) {
544
- applyManagedClose(restoredState.sessionName, restoredState.namespace);
545
- }
546
- }
547
- const explicitCloseSessionName = commandClosesSession && explicitSessionName && restorableDetailSessionName === explicitSessionName
548
- ? restorableDetailSessionName
549
- : undefined;
550
- // Sticky restore policy is session-identity state and must apply even for explicit
551
- // `--session <current-managed>` rows that are not used for managed-session lifecycle replay.
552
- if (details.managedSessionRestoreDisabled === true && typeof sessionName === "string") {
553
- restoreDisabledIdentities.set(getAgentBrowserSessionIdentityKey(sessionName, namespace), { namespace, sessionName });
554
- }
555
- const managedSessionName = outcomeClosedSessionName ?? (!explicitSessionName &&
556
- restorableDetailSessionName &&
557
- (usedImplicitSession || sessionMode === "fresh")
558
- ? restorableDetailSessionName
559
- : commandClosesSession
560
- ? explicitCloseSessionName
561
- : undefined);
562
- if (!managedSessionName) {
563
- continue;
564
- }
565
- const restoreRank = getManagedSessionRestoreRank({
566
- fallbackSessionName,
567
- freshSessionRanks,
568
- sessionName: managedSessionName,
569
- });
570
- if (restoreRank === undefined) {
571
- continue;
572
- }
573
- freshSessionOrdinal = Math.max(freshSessionOrdinal, restoreRank);
574
- const messageIsError = typeof message.isError === "boolean" ? message.isError : undefined;
575
- const exitCode = typeof details.exitCode === "number" ? details.exitCode : undefined;
576
- const outcomeActiveAfter = outcome?.activeAfter === true;
577
- const outcomeRepresentsActiveCurrentSession = outcomeActiveAfter && outcomeCurrentSessionName === managedSessionName && (outcomeStatus === "created" || outcomeStatus === "replaced" || outcomeStatus === "unchanged");
578
- const succeeded = outcomeRepresentsActiveCurrentSession || nestedBatchRemainsActive
579
- ? true
580
- : messageIsError === undefined ? exitCode === undefined || exitCode === 0 : !messageIsError;
581
- if (commandClosesSession || outcomeClosedSessionName) {
582
- if (nestedBatchEndsClosed || outcomeClosedSessionName || succeeded) {
583
- restoreDisabledIdentities.delete(getAgentBrowserSessionIdentityKey(managedSessionName, namespace));
584
- applyManagedClose(managedSessionName, namespace);
585
- }
586
- continue;
587
- }
588
- const staleCompletion = succeeded && restoreRank < activeRestoreRank;
589
- if (staleCompletion) {
590
- continue;
591
- }
592
- restoredState = resolveManagedSessionState({
593
- command,
594
- managedSessionName,
595
- managedSessionNamespace: namespace,
596
- priorActive: restoredState.active,
597
- priorNamespace: restoredState.namespace,
598
- priorSessionName: restoredState.sessionName,
599
- succeeded,
600
- });
601
- if (succeeded && restoredState.active) {
602
- activeRestoreRank = restoreRank;
603
- closedSessionName = undefined;
604
- }
605
- }
52
+ function effectiveStartupFlags(args, managedNamespace) {
53
+ const explicitNamespacePresent = scanUpstreamGlobalFlagOccurrences(args, "--namespace").length > 0;
54
+ const explicitNamespace = extractExplicitNamespace(args);
55
+ return getStartupScopedFlags(args).filter((flag) => !(flag === "--namespace" &&
56
+ explicitNamespacePresent &&
57
+ explicitNamespace === canonicalizeAgentBrowserNamespace(managedNamespace)));
58
+ }
59
+ function targetsActiveManagedSession(selection, options, needsSession) {
60
+ const { sessionName } = selection;
61
+ return (options.managedSessionActive &&
62
+ needsSession &&
63
+ sessionName !== undefined &&
64
+ sessionName.length > 0 &&
65
+ getAgentBrowserSessionIdentityKey(sessionName, selection.namespace) ===
66
+ getAgentBrowserSessionIdentityKey(options.managedSessionName, options.managedSessionNamespace));
67
+ }
68
+ function activeLaunchRecovery(args, flags, command, prior) {
69
+ if (flags.length === 0 ||
70
+ isCloseCommand(command) ||
71
+ (prior.validationError !== undefined && prior.validationError.length > 0)) {
72
+ return prior;
73
+ }
74
+ const explicitSession = extractExplicitSessionName(args);
75
+ const explicit = explicitSession !== undefined && explicitSession.length > 0;
76
+ const recoveryArgs = explicit ? stripExplicitIdentityArgs(args, "--session") : args;
606
77
  return {
607
- ...restoredState,
608
- ...(closedSessionName ? { closedSessionName } : {}),
609
- freshSessionOrdinal,
610
- managedSessionRestoreDisabledIdentities: [...restoreDisabledIdentities.values()],
78
+ recoveryHint: freshSessionRecoveryHint(recoveryArgs, launchFlagsRecoveryReason()),
79
+ validationError: [
80
+ `The current extension-managed agent-browser session is already running, so launch-scoped flags ${flags.join(", ")} would replace or be ignored by upstream agent-browser.`,
81
+ explicit
82
+ ? 'Remove the explicit `--session` and retry with `sessionMode: "fresh"` to force a fresh upstream launch.'
83
+ : 'Retry this call with `sessionMode: "fresh"` to force a fresh upstream launch.',
84
+ ].join(" "),
611
85
  };
612
86
  }
613
- export function createEphemeralSessionSeed() {
614
- return randomUUID();
615
- }
616
- function createCwdHash(cwd) {
617
- return createHash("sha256").update(`cwd:${cwd}`).digest("hex").slice(0, SESSION_NAME_CWD_HASH_LENGTH);
618
- }
619
- export function createImplicitSessionName(sessionId, cwd, ephemeralSeed, platform = process.platform) {
620
- const normalizedSessionId = sessionId?.replaceAll("-", "").toLowerCase();
621
- if (platform === "android") {
622
- const identity = normalizedSessionId ? `session:${normalizedSessionId}:cwd:${cwd}` : `ephemeral:${cwd}:${ephemeralSeed}`;
623
- const digest = createHash("sha256").update(identity).digest("hex").slice(0, ANDROID_SESSION_NAME_IDENTITY_LENGTH);
624
- return `${MANAGED_SESSION_NAME_PREFIX}${digest}`;
625
- }
626
- const slug = basename(cwd)
627
- .toLowerCase()
628
- .replace(/[^a-z0-9]+/g, "-")
629
- .replace(/^-+|-+$/g, "")
630
- .slice(0, MAX_PROJECT_SLUG_LENGTH) || "project";
631
- const cwdHash = createCwdHash(cwd);
632
- if (normalizedSessionId) {
633
- const stableSessionId = createHash("sha256")
634
- .update(`session:${normalizedSessionId}`)
635
- .digest("hex")
636
- .slice(0, SESSION_NAME_SESSION_ID_LENGTH);
637
- return `${MANAGED_SESSION_NAME_PREFIX}${slug}-${stableSessionId}-${cwdHash}`;
638
- }
639
- const digest = createHash("sha256")
640
- .update(`ephemeral:${cwd}:${ephemeralSeed}`)
641
- .digest("hex")
642
- .slice(0, SESSION_NAME_SESSION_ID_LENGTH);
643
- return `${MANAGED_SESSION_NAME_PREFIX}${slug}-${digest}-${cwdHash}`;
644
- }
645
- export function createFreshSessionName(baseSessionName, ephemeralSeed, ordinal) {
646
- const suffix = createHash("sha256")
647
- .update(`fresh:${baseSessionName}:${ephemeralSeed}:${ordinal}`)
648
- .digest("hex")
649
- .slice(0, 10);
650
- return `${baseSessionName}-fresh-${suffix}`;
651
- }
652
- function getSingleKeyCommandValidationError(args) {
653
- const { commandInfo, upstreamCommandTokens: commandTokens } = parseArgvDescriptor(args);
654
- const command = commandInfo.command;
655
- if (command !== "press" && command !== "key" && command !== "keydown" && command !== "keyup")
656
- return undefined;
657
- if (commandTokens.length === 2)
658
- return undefined;
659
- const label = command === "key" ? "key/press" : command;
660
- return `agent-browser ${label} accepts exactly one key argument. Do not pass a selector or ref to ${label}; focus or click the target first, then run ${command} <key> (for example: focus @e1, then press Enter).`;
661
- }
662
- function getBareMcpValidationError(args) {
663
- const { commandInfo, upstreamCommandTokens: commandTokens } = parseArgvDescriptor(args);
664
- if (commandInfo.command !== "mcp")
665
- return undefined;
666
- if (commandTokens.includes("--help") || commandTokens.includes("-h"))
667
- return undefined;
668
- return "agent-browser mcp starts a stdio MCP server for external MCP clients, not a one-shot native agent_browser tool workflow. Use the native agent_browser tool modes directly, or configure an MCP client to launch `agent-browser mcp`. Use `mcp --help` for help.";
669
- }
670
- function getUnsupportedInlineWaitDownloadError(args) {
671
- const descriptor = parseArgvDescriptor(args);
672
- if (descriptor.commandInfo.command !== "wait" || !descriptor.upstreamCommandTokens.some((token) => token.startsWith("--download=")))
673
- return undefined;
674
- return `agent-browser ${TARGET_AGENT_BROWSER_VERSION} does not support \`wait --download=<path>\`. Pass the optional path as a separate argument: \`wait --download <path>\` (or \`wait -d <path>\`).`;
675
- }
676
- function getBareNoSandboxValidationError(args, batchStep) {
677
- // Native batch rows skip global parsing; --args is effective only on the outer CLI call.
678
- const tokens = batchStep ? args : stripUpstreamGlobalFlags(args);
679
- const command = tokens[0];
680
- const leading = command === "--no-sandbox";
681
- if (!leading && (!isOpenNavigationCommand(command) || !tokens.slice(1).includes("--no-sandbox")))
682
- return undefined;
683
- const explanation = leading
684
- ? "`--no-sandbox` is not an agent-browser command."
685
- : `\`--no-sandbox\` is ignored as an option by \`${command}\`.`;
686
- return `${explanation} It is a Chromium launch argument. Put it in top-level \`--args\` and start a fresh session: { args: ["--args", "--no-sandbox", "open", "https://example.com"], sessionMode: "fresh" }. For batch, put --args before batch, not inside a step.`;
687
- }
688
- export function validateToolArgs(args, options = {}) {
689
- if (args.length === 0) {
690
- return "`args` must contain at least one agent-browser command token.";
691
- }
692
- const shellOperator = args.find((token) => SHELL_OPERATOR_TOKENS.has(token));
693
- if (shellOperator) {
694
- return `Do not pass shell operators like \`${shellOperator}\`. Pass exact agent-browser CLI arguments only.`;
695
- }
696
- const sessionModeArg = args.find((token) => token === "--session-mode" || token.startsWith("--session-mode="));
697
- if (sessionModeArg) {
698
- return "Do not pass `--session-mode` in args. Use the top-level agent_browser `sessionMode` field instead, for example { args: [\"--profile\", \"Default\", \"open\", \"https://example.com\"], sessionMode: \"fresh\" }.";
699
- }
700
- const inspection = !options.batchStep && isPlainTextInspectionArgs(args);
701
- const invalidValueFlag = inspection ? undefined : getInvalidValueFlagDetails(args, !options.batchStep);
702
- if (invalidValueFlag?.reason === "unsupported-assignment")
703
- return formatInvalidValueFlagError(invalidValueFlag, options.batchStep);
704
- return (inspection ? undefined : getBareNoSandboxValidationError(args, options.batchStep === true))
705
- ?? getBareMcpValidationError(args) ?? getSingleKeyCommandValidationError(args) ?? getUnsupportedInlineWaitDownloadError(args);
706
- }
707
- function getInvalidValueFlagDetails(args, allowRestoreAssignment = true) {
708
- for (let index = 0; index < args.length; index += 1) {
709
- const token = args[index];
710
- if (!token.startsWith("-")) {
711
- continue;
712
- }
713
- const normalizedToken = token.split("=", 1)[0] ?? token;
714
- if (token.includes("=")
715
- && (PREVALIDATED_VALUE_FLAGS.has(normalizedToken)
716
- || GLOBAL_BOOLEAN_FLAGS_WITH_OPTIONAL_VALUES.has(normalizedToken)
717
- || (!allowRestoreAssignment && normalizedToken === "--restore"))) {
718
- return {
719
- flag: normalizedToken,
720
- index,
721
- reason: "unsupported-assignment",
722
- };
723
- }
724
- if (!PREVALIDATED_VALUE_FLAGS.has(normalizedToken)) {
725
- continue;
726
- }
727
- const receivedToken = args[index + 1];
728
- if (receivedToken === undefined || (normalizedToken === "--args" && receivedToken.length === 0)) {
729
- return {
730
- flag: normalizedToken,
731
- index,
732
- reason: "missing-value",
733
- };
734
- }
735
- if (receivedToken.startsWith("-") && !GLOBAL_VALUE_FLAGS_ALLOWING_DASH_VALUE.has(normalizedToken)) {
736
- return {
737
- flag: normalizedToken,
738
- index,
739
- reason: "unexpected-flag",
740
- receivedToken,
741
- };
742
- }
743
- index += 1;
744
- }
745
- return undefined;
746
- }
747
- function formatInvalidValueFlagError(details, batchStep = false) {
748
- if (details.reason === "unsupported-assignment") {
749
- if (batchStep) {
750
- return details.flag === "--restore"
751
- ? "Global `--restore=<key>` belongs before `batch` in top-level args, not inside a batch step."
752
- : `Global \`${details.flag}=<value>\` is not supported inside a batch step. Move \`${details.flag}\` and its value before \`batch\` as separate top-level args.`;
753
- }
754
- return `agent-browser ${TARGET_AGENT_BROWSER_VERSION} does not support \`${details.flag}=<value>\`. Pass \`${details.flag}\` and its value as separate arguments.`;
755
- }
756
- if (details.reason === "unexpected-flag" && details.receivedToken) {
757
- return `Flag \`${details.flag}\` requires a value, but received \`${details.receivedToken}\` instead. Pass a non-flag value immediately after \`${details.flag}\`.`;
758
- }
759
- return `Flag \`${details.flag}\` requires a value immediately after it. Pass a non-flag token like \`${details.flag} demo\`.`;
760
- }
761
- function hasFlagToken(args, flag) {
762
- return args.some((token) => token === flag || token.startsWith(`${flag}=`));
763
- }
764
- function normalizeComparableUrl(url) {
765
- const normalizedUrl = url.trim();
766
- if (normalizedUrl.length === 0) {
767
- return undefined;
87
+ function activeCompatibilityPlan(args, requested, existing, prior) {
88
+ if (!canUseHeadlessCompatibilityUserAgent(args)) {
89
+ return { ...prior, compatibilityWorkaround: requested };
768
90
  }
769
- try {
770
- const parsedUrl = new URL(normalizedUrl);
771
- parsedUrl.hash = "";
772
- return parsedUrl.toString();
773
- }
774
- catch {
775
- return undefined;
776
- }
777
- }
778
- function normalizeTabSelectionValue(value) {
779
- const normalizedValue = value?.trim();
780
- return normalizedValue && normalizedValue.length > 0 ? normalizedValue : undefined;
781
- }
782
- function extractTabSelection(tab) {
783
- const tabId = normalizeTabSelectionValue(tab.tabId);
784
- if (tabId) {
785
- return { selectedTab: tabId, selectionKind: "tabId" };
786
- }
787
- const label = normalizeTabSelectionValue(tab.label);
788
- if (label) {
789
- return { selectedTab: label, selectionKind: "label" };
790
- }
791
- if (typeof tab.index === "number" && Number.isInteger(tab.index) && tab.index >= 0) {
792
- return { selectedTab: String(tab.index), selectionKind: "index" };
793
- }
794
- return undefined;
795
- }
796
- function parseComparableNavigationUrl(url) {
797
- try {
798
- return new URL(url);
799
- }
800
- catch {
801
- try {
802
- return new URL(`https://${url}`);
803
- }
804
- catch {
805
- return undefined;
806
- }
807
- }
808
- }
809
- export function getDefaultHeadlessCompatUserAgent(platform = process.platform) {
810
- return DEFAULT_HEADLESS_COMPAT_USER_AGENT_BY_PLATFORM[platform] ?? FALLBACK_HEADLESS_COMPAT_USER_AGENT;
811
- }
812
- export function canUseHeadlessCompatibilityUserAgent(args, env = getAgentBrowserProcessEnvironment()) {
813
- if (env.AGENT_BROWSER_SESSION !== undefined)
814
- return false;
815
- if (hasFlagToken(args, "--user-agent") || hasFlagToken(args, "--args"))
816
- return false;
817
- if (hasFlagToken(args, "--cdp") || hasFlagToken(args, "--provider") || hasFlagToken(args, "-p"))
818
- return false;
819
- if (env.AGENT_BROWSER_USER_AGENT !== undefined || env.AGENT_BROWSER_ARGS !== undefined || env.AGENT_BROWSER_CDP !== undefined || env.AGENT_BROWSER_PROVIDER !== undefined)
820
- return false;
821
- if ((getBooleanFlagValue(args, "--headed") ?? isUpstreamEnvFlagEnabled(env.AGENT_BROWSER_HEADED))
822
- || (getBooleanFlagValue(args, "--auto-connect") ?? isUpstreamEnvFlagEnabled(env.AGENT_BROWSER_AUTO_CONNECT)))
823
- return false;
824
- const engine = scanUpstreamGlobalFlagOccurrences(args, "--engine").at(-1)?.value ?? env.AGENT_BROWSER_ENGINE;
825
- return !engine || engine === "chrome";
826
- }
827
- function getCompatibilityWorkaround(args, commandInfo) {
828
- if (!commandInfo.command || !isOpenNavigationCommand(commandInfo.command) || !commandInfo.subcommand || !canUseHeadlessCompatibilityUserAgent(args))
829
- return undefined;
830
- const parsedTargetUrl = parseComparableNavigationUrl(commandInfo.subcommand);
831
- if (!parsedTargetUrl || !["http:", "https:"].includes(parsedTargetUrl.protocol))
832
- return undefined;
833
- const hostname = parsedTargetUrl.hostname.toLowerCase();
834
- if (hostname === CLOUDFLARE_HEADLESS_COMPAT_HOST) {
91
+ if (requested &&
92
+ !existing &&
93
+ (prior.validationError === undefined || prior.validationError.length === 0)) {
94
+ const sessionName = extractExplicitSessionName(args);
95
+ const explicit = sessionName !== undefined && sessionName.length > 0;
96
+ const recoveryArgs = explicit ? stripExplicitIdentityArgs(args, "--session") : args;
835
97
  return {
836
- id: "cloudflare-headless-user-agent",
837
- reason: "Cloudflare Dashboard challenges the default headless Chrome user agent; inject a normal Chrome user agent so authenticated headless browsing reaches the dashboard instead of Turnstile.",
98
+ compatibilityWorkaround: undefined,
99
+ recoveryHint: freshSessionRecoveryHint(recoveryArgs, "The requested site compatibility user agent is launch-scoped and needs a fresh browser session."),
100
+ validationError: explicit
101
+ ? 'The current extension-managed agent-browser session is already running without the user agent required by this site. Remove the explicit `--session` and retry with `sessionMode: "fresh"` so the compatibility user agent is applied at launch.'
102
+ : 'The current extension-managed agent-browser session is already running without the user agent required by this site. Retry this call with `sessionMode: "fresh"` so the compatibility user agent is applied at launch.',
838
103
  };
839
104
  }
840
- if (!OPENAI_HEADLESS_COMPAT_HOSTS.has(hostname))
841
- return undefined;
105
+ return { ...prior, compatibilityWorkaround: requested ?? existing };
106
+ }
107
+ function inspectionPlan(args, commandInfo, startupScopedFlags) {
108
+ const explicitNamespacePresent = scanUpstreamGlobalFlagOccurrences(args, "--namespace").length > 0;
842
109
  return {
843
- id: "chatgpt-headless-user-agent",
844
- reason: "OpenAI web properties currently challenge the default headless Chrome user agent; inject a normal Chrome user agent to preserve the default headless workflow without requiring headed mode or auto-connect.",
110
+ commandInfo,
111
+ effectiveArgs: [...args],
112
+ namespace: explicitNamespacePresent ? (extractExplicitNamespace(args) ?? "") : undefined,
113
+ plainTextInspection: true,
114
+ startupScopedFlags,
115
+ usedImplicitSession: false,
845
116
  };
846
117
  }
847
- function stripExplicitSessionArgs(args) {
848
- const sessionTokenIndexes = new Set();
849
- for (const occurrence of scanUpstreamGlobalFlagOccurrences(args, "--session")) {
850
- sessionTokenIndexes.add(occurrence.index);
851
- sessionTokenIndexes.add(occurrence.index + 1);
852
- }
853
- return args.filter((_token, index) => !sessionTokenIndexes.has(index));
854
- }
855
- function stripExplicitNamespaceArgs(args) {
856
- const namespaceTokenIndexes = new Set();
857
- for (const occurrence of scanUpstreamGlobalFlagOccurrences(args, "--namespace")) {
858
- namespaceTokenIndexes.add(occurrence.index);
859
- namespaceTokenIndexes.add(occurrence.index + 1);
860
- }
861
- return args.filter((_token, index) => !namespaceTokenIndexes.has(index));
862
- }
863
- export function getStartupScopedFlags(args) {
864
- return LAUNCH_SCOPED_FLAG_DEFINITIONS
865
- .map((definition) => definition.flag)
866
- .filter((flag) => hasLaunchScopedFlagToken(args, flag));
867
- }
868
- export function buildExecutionPlan(args, options) {
869
- const nativeSession = getAgentBrowserProcessEnvironment().AGENT_BROWSER_SESSION;
870
- if (nativeSession !== undefined && !isPlainTextInspectionArgs(args) && extractExplicitSessionName(args) === undefined)
871
- args = ["--session", nativeSession, ...args];
872
- const invalidValueFlag = getInvalidValueFlagDetails(args);
873
- const explicitNamespacePresent = scanUpstreamGlobalFlagOccurrences(args, "--namespace").length > 0;
874
- const explicitNamespace = extractExplicitNamespace(args);
875
- const managedSessionNamespace = canonicalizeAgentBrowserNamespace(options.managedSessionNamespace);
876
- const startupScopedFlags = getStartupScopedFlags(args).filter((flag) => !(flag === "--namespace" && explicitNamespacePresent && explicitNamespace === managedSessionNamespace));
877
- const plainTextInspection = isPlainTextInspectionArgs(args);
878
- const argvDescriptor = parseArgvDescriptor(args);
879
- const commandInfo = argvDescriptor.commandInfo;
880
- const commandNeedsManagedSession = !plainTextInspection && !options.browserIndependentReadConfirmation && needsManagedSession(argvDescriptor, options.stdin);
881
- const effectiveArgs = plainTextInspection ? [...args] : args.includes("--json") ? [] : ["--json"];
882
- let namespace = explicitNamespacePresent ? explicitNamespace ?? "" : undefined;
883
- if (plainTextInspection) {
884
- return {
885
- commandInfo,
886
- effectiveArgs,
887
- namespace,
888
- plainTextInspection,
889
- startupScopedFlags,
890
- usedImplicitSession: false,
891
- };
892
- }
893
- if (invalidValueFlag) {
894
- return {
895
- commandInfo: {},
896
- effectiveArgs,
897
- invalidValueFlag,
898
- plainTextInspection: false,
899
- startupScopedFlags: [],
900
- usedImplicitSession: false,
901
- validationError: formatInvalidValueFlagError(invalidValueFlag),
902
- };
903
- }
904
- for (const flag of ["--session", "--namespace"]) {
905
- if (countExplicitGlobalFlags(args, flag) <= 1)
906
- continue;
907
- return {
908
- commandInfo: {},
909
- effectiveArgs,
910
- plainTextInspection: false,
911
- startupScopedFlags: [],
912
- usedImplicitSession: false,
913
- validationError: `Multiple ${flag} flags are not supported. Pass a single ${flag} value; upstream uses the last occurrence while this wrapper would otherwise mis-attribute managed-session ownership.`,
914
- };
915
- }
916
- const explicitSessionName = extractExplicitSessionName(args);
917
- if (explicitSessionName && !explicitNamespacePresent) {
918
- const targetsCurrentManagedSession = options.managedSessionActive
919
- && getAgentBrowserSessionIdentityKey(explicitSessionName, managedSessionNamespace)
920
- === getAgentBrowserSessionIdentityKey(options.managedSessionName, managedSessionNamespace);
921
- namespace = targetsCurrentManagedSession
922
- ? managedSessionNamespace
923
- : resolveAgentBrowserNamespace(args, getAgentBrowserProcessEnvironment().AGENT_BROWSER_NAMESPACE);
924
- }
925
- const shouldCreateFreshManagedSession = !explicitSessionName && options.sessionMode === "fresh" && commandInfo.command !== undefined && !isCloseCommand(commandInfo.command);
926
- let argsToAppend = args;
927
- const requestedCompatibilityWorkaround = getCompatibilityWorkaround(args, commandInfo);
928
- let compatibilityWorkaround = requestedCompatibilityWorkaround;
929
- if (explicitSessionName && explicitNamespacePresent) {
930
- effectiveArgs.push("--namespace", explicitNamespace ?? "");
931
- argsToAppend = stripExplicitNamespaceArgs(args);
932
- }
933
- let managedSessionName;
934
- let recoveryHint;
935
- let sessionName = explicitSessionName;
936
- let usedImplicitSession = false;
937
- let validationError;
938
- if (!explicitSessionName && options.sessionMode === "auto" && commandNeedsManagedSession) {
939
- if (options.managedSessionActive && startupScopedFlags.length > 0) {
940
- recoveryHint = {
941
- exampleArgs: args,
942
- exampleParams: { args, sessionMode: "fresh" },
943
- reason: `Launch-scoped flags (${LAUNCH_SCOPED_FLAG_LABEL}) need a fresh upstream launch once the extension-managed session is already active.`,
944
- recommendedSessionMode: "fresh",
945
- };
946
- validationError = [
947
- `The current extension-managed agent-browser session is already running, so launch-scoped flags ${startupScopedFlags.join(", ")} would be ignored by upstream agent-browser.`,
948
- "Retry this call with `sessionMode: \"fresh\"` to force a fresh upstream launch, or pass an explicit `--session ...` if you want to name the new session yourself.",
949
- ].join(" ");
950
- }
951
- else {
952
- namespace = explicitNamespacePresent ? explicitNamespace ?? "" : managedSessionNamespace;
953
- if (namespace !== undefined)
954
- effectiveArgs.push("--namespace", namespace);
955
- effectiveArgs.push("--session", options.managedSessionName);
956
- if (explicitNamespacePresent)
957
- argsToAppend = stripExplicitNamespaceArgs(args);
958
- managedSessionName = options.managedSessionName;
959
- sessionName = options.managedSessionName;
960
- usedImplicitSession = true;
961
- }
962
- }
963
- else if (shouldCreateFreshManagedSession && commandNeedsManagedSession) {
964
- if (namespace !== undefined)
965
- effectiveArgs.push("--namespace", namespace);
966
- effectiveArgs.push("--session", options.freshSessionName);
967
- if (explicitNamespacePresent)
968
- argsToAppend = stripExplicitNamespaceArgs(args);
969
- managedSessionName = options.freshSessionName;
970
- sessionName = options.freshSessionName;
971
- }
972
- if (commandInfo.command !== undefined && !sessionName && !explicitNamespacePresent) {
973
- namespace = resolveAgentBrowserNamespace(args, getAgentBrowserProcessEnvironment().AGENT_BROWSER_NAMESPACE);
974
- }
975
- const targetsActiveManagedSession = options.managedSessionActive
976
- && commandNeedsManagedSession
977
- && sessionName
978
- && getAgentBrowserSessionIdentityKey(sessionName, namespace) === getAgentBrowserSessionIdentityKey(options.managedSessionName, options.managedSessionNamespace);
979
- if (targetsActiveManagedSession && startupScopedFlags.length > 0 && !isCloseCommand(commandInfo.command) && !validationError) {
980
- const recoveryArgs = explicitSessionName ? stripExplicitSessionArgs(args) : args;
981
- recoveryHint = {
982
- exampleArgs: recoveryArgs,
983
- exampleParams: { args: recoveryArgs, sessionMode: "fresh" },
984
- reason: `Launch-scoped flags (${LAUNCH_SCOPED_FLAG_LABEL}) need a fresh upstream launch once the extension-managed session is already active.`,
985
- recommendedSessionMode: "fresh",
986
- };
987
- validationError = [
988
- `The current extension-managed agent-browser session is already running, so launch-scoped flags ${startupScopedFlags.join(", ")} would replace or be ignored by upstream agent-browser.`,
989
- explicitSessionName
990
- ? "Remove the explicit `--session` and retry with `sessionMode: \"fresh\"` to force a fresh upstream launch."
991
- : "Retry this call with `sessionMode: \"fresh\"` to force a fresh upstream launch.",
992
- ].join(" ");
993
- }
994
- if (targetsActiveManagedSession && canUseHeadlessCompatibilityUserAgent(args)) {
995
- if (requestedCompatibilityWorkaround && !options.managedSessionCompatibilityWorkaround && !validationError) {
996
- compatibilityWorkaround = undefined;
997
- const recoveryArgs = explicitSessionName ? stripExplicitSessionArgs(args) : args;
998
- recoveryHint = {
999
- exampleArgs: recoveryArgs,
1000
- exampleParams: { args: recoveryArgs, sessionMode: "fresh" },
1001
- reason: "The requested site compatibility user agent is launch-scoped and needs a fresh browser session.",
1002
- recommendedSessionMode: "fresh",
1003
- };
1004
- validationError = explicitSessionName
1005
- ? "The current extension-managed agent-browser session is already running without the user agent required by this site. Remove the explicit `--session` and retry with `sessionMode: \"fresh\"` so the compatibility user agent is applied at launch."
1006
- : "The current extension-managed agent-browser session is already running without the user agent required by this site. Retry this call with `sessionMode: \"fresh\"` so the compatibility user agent is applied at launch.";
1007
- }
1008
- else {
1009
- compatibilityWorkaround = requestedCompatibilityWorkaround ?? options.managedSessionCompatibilityWorkaround;
1010
- }
1011
- }
1012
- if (compatibilityWorkaround && !targetsActiveManagedSession) {
118
+ export function buildExecutionPlan(inputArgs, options) {
119
+ const args = withNativeSession(inputArgs);
120
+ const startupScopedFlags = effectiveStartupFlags(args, options.managedSessionNamespace);
121
+ const descriptor = parseArgvDescriptor(args);
122
+ const commandInfo = descriptor.commandInfo;
123
+ if (isPlainTextInspectionArgs(args)) {
124
+ return inspectionPlan(args, commandInfo, startupScopedFlags);
125
+ }
126
+ const failure = planningFailure(args);
127
+ if (failure) {
128
+ return failure;
129
+ }
130
+ const needsSession = options.browserIndependentReadConfirmation !== true &&
131
+ needsManagedSession(descriptor, options.stdin);
132
+ const selection = selectExecutionSession(args, options, {
133
+ command: commandInfo.command,
134
+ needsManagedSession: needsSession,
135
+ startupScopedFlags,
136
+ });
137
+ const activeTarget = targetsActiveManagedSession(selection, options, needsSession);
138
+ const requested = getCompatibilityWorkaround(args, commandInfo);
139
+ const recovery = activeTarget
140
+ ? activeLaunchRecovery(args, startupScopedFlags, commandInfo.command, selection)
141
+ : selection;
142
+ const compatibility = activeTarget
143
+ ? activeCompatibilityPlan(args, requested, options.managedSessionCompatibilityWorkaround, recovery)
144
+ : { ...recovery, compatibilityWorkaround: requested };
145
+ const effectiveArgs = [...jsonPrefix(args), ...selection.prefixArgs];
146
+ if (compatibility.compatibilityWorkaround && !activeTarget) {
1013
147
  effectiveArgs.push("--user-agent", getDefaultHeadlessCompatUserAgent());
1014
148
  }
1015
- effectiveArgs.push(...argsToAppend);
149
+ effectiveArgs.push(...selection.argsToAppend);
1016
150
  return {
1017
151
  commandInfo,
1018
- compatibilityWorkaround,
152
+ compatibilityWorkaround: compatibility.compatibilityWorkaround,
1019
153
  effectiveArgs,
1020
- managedSessionName,
1021
- namespace,
1022
- plainTextInspection,
1023
- recoveryHint,
1024
- sessionName,
154
+ managedSessionName: selection.managedSessionName,
155
+ namespace: selection.namespace,
156
+ plainTextInspection: false,
157
+ recoveryHint: compatibility.recoveryHint,
158
+ sessionName: selection.sessionName,
1025
159
  startupScopedFlags,
1026
- usedImplicitSession,
1027
- validationError,
160
+ usedImplicitSession: selection.usedImplicitSession,
161
+ validationError: compatibility.validationError,
1028
162
  };
1029
163
  }
1030
- export function chooseOpenResultTabCorrection(options) {
1031
- const normalizedTargetUrl = typeof options.targetUrl === "string" ? normalizeComparableUrl(options.targetUrl) : undefined;
1032
- if (!normalizedTargetUrl) {
1033
- return undefined;
1034
- }
1035
- const tabsWithIndices = options.tabs.map((tab, index) => ({
1036
- ...tab,
1037
- index: typeof tab.index === "number" ? tab.index : index,
1038
- label: normalizeTabSelectionValue(tab.label),
1039
- tabId: normalizeTabSelectionValue(tab.tabId),
1040
- }));
1041
- const activeTab = tabsWithIndices.find((tab) => tab.active === true) ??
1042
- (typeof options.activeTabIndex === "number" ? tabsWithIndices.find((tab) => tab.index === options.activeTabIndex) : undefined);
1043
- if (activeTab && normalizeComparableUrl(activeTab.url ?? "") === normalizedTargetUrl) {
1044
- return undefined;
1045
- }
1046
- const matchingTabs = tabsWithIndices.filter((tab) => normalizeComparableUrl(tab.url ?? "") === normalizedTargetUrl);
1047
- if (matchingTabs.length === 0) {
1048
- return undefined;
1049
- }
1050
- const trimmedTargetTitle = typeof options.targetTitle === "string" ? options.targetTitle.trim() : "";
1051
- const titledMatch = trimmedTargetTitle.length === 0
1052
- ? undefined
1053
- : matchingTabs.find((tab) => typeof tab.title === "string" && tab.title.trim() === trimmedTargetTitle);
1054
- const selectedTab = titledMatch ?? matchingTabs[0];
1055
- const tabSelection = extractTabSelection(selectedTab);
1056
- return tabSelection
1057
- ? {
1058
- ...tabSelection,
1059
- targetTitle: trimmedTargetTitle.length > 0 ? trimmedTargetTitle : undefined,
1060
- targetUrl: normalizedTargetUrl,
1061
- }
1062
- : undefined;
1063
- }