pi-agent-browser-native 0.9.3 → 0.9.4

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