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,122 +1,88 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
- import { createHash, randomInt, randomUUID } from "node:crypto";
3
- import { lstat, mkdir, readFile, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
4
- import { tmpdir } from "node:os";
5
- import { basename, dirname, join } from "node:path";
6
- import { canonicalizeAgentBrowserNamespace, foldAgentBrowserFilesystemIdentity } from "./argv-grammar.js";
7
- import { getAgentBrowserSocketDirValidationError, resolveAgentBrowserSocketDir } from "./process.js";
8
- import { processStartIdentitiesMatch, readProcessStartIdentity } from "./process-identity.js";
9
- const POLICY_LOCK_WAIT_MS = 1_000;
10
- const POLICY_LOCK_RETRY_MS = 10;
11
- const POLICY_LOCK_MAX_BYTES = 1_048_576; // One claim may cover an entire owned-browser cleanup set.
12
- const LOCK_OWNER_FILE = "owner.json";
13
- const LOCK_TICKET_FILE = "ticket.json";
14
- const STALE_CLAIM_MIN_AGE_MS = 30 * 60 * 1_000;
15
- const POLICY_GC_BATCH_SIZE = 8;
16
- let lastPolicyGcName;
17
- function getCoordinationDirectory(platform = process.platform) {
18
- if (platform !== "win32") {
19
- const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
20
- return platform === "android"
21
- ? join(tmpdir(), `pi-agent-browser-policy${uid === undefined ? "" : `-${uid}`}`)
22
- : `/tmp/pi-agent-browser-policy${uid === undefined ? "" : `-${uid}`}`;
23
- }
24
- const user = process.env.USERNAME ?? process.env.USER ?? "unknown";
25
- const suffix = createHash("sha256").update(user).digest("hex").slice(0, 12);
26
- return join(tmpdir(), `pi-agent-browser-policy-${suffix}`);
27
- }
28
- async function ensureCoordinationDirectory(path, platform) {
29
- try {
30
- try {
31
- await mkdir(path, { mode: 0o700 });
32
- }
33
- catch (error) {
34
- if (error.code !== "EEXIST")
35
- return false;
36
- }
37
- const entry = await lstat(path);
38
- if (entry.isSymbolicLink() || !entry.isDirectory())
39
- return false;
40
- if (platform !== "win32") {
41
- const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
42
- if (uid === undefined || entry.uid !== uid || (entry.mode & 0o077) !== 0)
43
- return false;
44
- }
45
- return true;
46
- }
47
- catch {
48
- return false;
49
- }
50
- }
51
- export async function resolveBrowserExecutionIdentity(options) {
52
- const socketDir = resolveAgentBrowserSocketDir(options);
53
- const namespace = canonicalizeAgentBrowserNamespace(options.namespace);
54
- let socketContext;
55
- if (process.platform === "win32") {
56
- // Native Windows can reach the same namespace/session TCP daemon from
57
- // different storage roots. Do not split those callers into separate locks.
58
- socketContext = `win32-native:${namespace ?? ""}`;
59
- }
60
- else {
61
- if (socketDir === undefined)
62
- throw new Error("Browser execution coordination requires the native socket directory.");
63
- const error = await getAgentBrowserSocketDirValidationError(socketDir);
64
- if (error)
65
- throw new Error(`Browser execution coordination cannot use socket storage: ${error}.`);
66
- const root = await realpath(socketDir);
67
- socketContext = namespace ? join(root, "namespaces", namespace, "run") : root;
68
- }
69
- return {
70
- socketContext: foldAgentBrowserFilesystemIdentity(socketContext, process.platform),
71
- ...(options.sessionName !== undefined ? { sessionName: foldAgentBrowserFilesystemIdentity(options.sessionName, process.platform) } : {}),
72
- };
73
- }
74
- export function getBrowserExecutionLockPath(identity) {
75
- const digest = createHash("sha256").update(identity.socketContext).digest("hex");
76
- return join(getCoordinationDirectory(), `.pi-agent-browser-policy-${digest}.lock-v4`);
77
- }
2
+ import { acquireExecutionClaim, } from "./browser-execution-claims.js";
3
+ import { resolveBrowserExecutionIdentity, } from "./browser-execution-identity.js";
4
+ export { resolveBrowserExecutionIdentity, getBrowserExecutionLockPath, } from "./browser-execution-identity.js";
78
5
  function groupExecutionIdentities(identities) {
79
- if (identities.length === 0)
6
+ if (identities.length === 0) {
80
7
  throw new Error("Browser execution coordination requires at least one identity.");
8
+ }
81
9
  const groups = new Map();
82
10
  for (const { socketContext, sessionName } of identities) {
83
- if (sessionName === undefined)
11
+ if (sessionName === undefined) {
84
12
  groups.set(socketContext, null);
13
+ }
85
14
  else if (groups.get(socketContext) !== null) {
86
15
  const sessions = groups.get(socketContext) ?? new Set();
87
16
  sessions.add(sessionName);
88
17
  groups.set(socketContext, sessions);
89
18
  }
90
19
  }
91
- return [...groups.keys()].sort().map(socketContext => {
20
+ return [...groups.keys()].sort().map((socketContext) => {
92
21
  const sessions = groups.get(socketContext);
93
22
  return { socketContext, sessionNames: sessions ? [...sessions].sort() : null };
94
23
  });
95
24
  }
96
25
  const executionScope = new AsyncLocalStorage();
26
+ function identityCovers(held, identity) {
27
+ if (held.socketContext !== identity.socketContext) {
28
+ return false;
29
+ }
30
+ const heldSessions = held.sessionNames;
31
+ if (heldSessions === null) {
32
+ return true;
33
+ }
34
+ const innerSessions = identity.sessionNames;
35
+ return innerSessions !== null && innerSessions.every((session) => heldSessions.includes(session));
36
+ }
97
37
  function scopeCovers(outer, inner) {
98
- return inner.every(identity => outer.some(held => held.socketContext === identity.socketContext
99
- && (held.sessionNames === null || identity.sessionNames !== null && identity.sessionNames.every(session => held.sessionNames.includes(session)))));
38
+ return inner.every((identity) => outer.some((held) => identityCovers(held, identity)));
39
+ }
40
+ async function acquireClaimsInOrder(identities, budget, remember) {
41
+ for (const identity of identities) {
42
+ // Acquiring sorted native socket contexts in order prevents lock-order cycles.
43
+ // oxlint-disable-next-line no-await-in-loop
44
+ const lock = await acquireExecutionClaim({
45
+ identity,
46
+ deadline: budget.deadline,
47
+ signal: budget.signal,
48
+ });
49
+ if (lock) {
50
+ remember(lock);
51
+ }
52
+ budget.check();
53
+ if (!lock) {
54
+ throw new Error("Browser execution coordination is unavailable or busy; no browser command was run.");
55
+ }
56
+ }
57
+ }
58
+ async function runInScope(identities, signal, run) {
59
+ const scope = { identities, active: true, signal, children: Promise.resolve() };
60
+ try {
61
+ return await executionScope.run(scope, () => run(signal));
62
+ }
63
+ finally {
64
+ scope.active = false;
65
+ await scope.children;
66
+ }
100
67
  }
101
- /**
102
- * Hold across every helper and action (or a complete code cell), not each CLI call.
103
- * Nested siblings are serialized; recursive inner calls and managed policy checks borrow
104
- * the claims. Declare every old/new identity up front for replacement or multi-browser cleanup;
105
- * omit sessionName for close --all. Upgrading mid-operation would allow a lock-order cycle.
106
- * Sessions sharing a socket context use ONE set-valued claim: acquiring them separately
107
- * could deadlock against a namespace-wide claimant between the first and second session.
108
- * Cancellation never releases a still-running callback. The callback must pass its signal
109
- * to subprocesses and await their termination; finally drains started children before release.
110
- */
68
+ /** Hold across helpers/actions or a complete code cell. Nested siblings serialize and recursive
69
+ * calls borrow existing claims. Declare every replacement/cleanup identity up front: upgrades
70
+ * mid-operation would permit lock-order cycles. One set-valued claim per socket context prevents
71
+ * namespace-wide contenders from deadlocking between individual session acquisitions.
72
+ * Cancellation does not release running callbacks: they must pass the signal to subprocesses
73
+ * and await termination. Finally drains started children before releasing the native claims. */
111
74
  export async function withBrowserExecutionLocks(options, run) {
112
- if (!Number.isFinite(options.deadline))
75
+ if (!Number.isFinite(options.deadline)) {
113
76
  throw new Error("Browser execution coordination requires a finite deadline.");
77
+ }
114
78
  const identities = groupExecutionIdentities(options.identities);
115
79
  const parent = executionScope.getStore();
116
- if (parent && !parent.active)
80
+ if (parent && !parent.active) {
117
81
  throw new Error("Browser execution scope has already finished.");
118
- if (parent && !scopeCovers(parent.identities, identities))
82
+ }
83
+ if (parent && !scopeCovers(parent.identities, identities)) {
119
84
  throw new Error("Cannot change or upgrade browser identity inside an execution lock; acquire every required identity before starting.");
85
+ }
120
86
  const controller = new AbortController();
121
87
  const signals = [controller.signal, options.signal, parent?.signal].filter((signal) => signal !== undefined);
122
88
  const signal = AbortSignal.any(signals);
@@ -124,264 +90,51 @@ export async function withBrowserExecutionLocks(options, run) {
124
90
  const remaining = options.deadline - Date.now();
125
91
  const timer = setTimeout(expire, Math.max(0, Math.min(remaining, 2_147_483_647)));
126
92
  const checkBudget = () => {
127
- if (Date.now() >= options.deadline)
93
+ if (Date.now() >= options.deadline) {
128
94
  expire();
95
+ }
129
96
  signal.throwIfAborted();
130
97
  };
131
98
  const locks = [];
132
99
  try {
133
100
  checkBudget();
134
101
  if (!parent) {
135
- for (const identity of identities) {
136
- const lock = await acquireExecutionClaim({ identity, deadline: options.deadline, signal });
137
- if (lock)
138
- locks.push(lock);
139
- checkBudget();
140
- if (!lock)
141
- throw new Error("Browser execution coordination is unavailable or busy; no browser command was run.");
142
- }
102
+ await acquireClaimsInOrder(identities, { deadline: options.deadline, signal, check: checkBudget }, (lock) => {
103
+ locks.push(lock);
104
+ });
143
105
  }
144
106
  const execute = async () => {
145
107
  checkBudget();
146
- if (options.waitOnly)
108
+ if (options.waitOnly === true) {
147
109
  clearTimeout(timer);
148
- const scope = { identities: parent?.identities ?? identities, active: true, signal, children: Promise.resolve() };
149
- try {
150
- return await executionScope.run(scope, () => run(signal));
151
- }
152
- finally {
153
- scope.active = false;
154
- await scope.children;
155
110
  }
111
+ return runInScope(parent?.identities ?? identities, signal, run);
156
112
  };
157
- if (!parent)
113
+ if (!parent) {
158
114
  return await execute();
115
+ }
159
116
  const result = parent.children.then(execute);
117
+ // The caller owns this result; the parent drains both outcomes before releasing claims.
160
118
  parent.children = result.then(() => undefined, () => undefined);
161
119
  return await result;
162
120
  }
163
121
  finally {
164
122
  clearTimeout(timer);
165
- await Promise.all(locks.reverse().map(lock => lock.release()));
123
+ await Promise.all(locks.reverse().map((lock) => lock.release()));
166
124
  }
167
125
  }
168
126
  export function withBrowserExecutionLock(options, run) {
169
- return withBrowserExecutionLocks({ identities: [options.identity], signal: options.signal, deadline: options.deadline, waitOnly: options.waitOnly }, run);
170
- }
171
- function parseOwner(content) {
172
- if (Buffer.byteLength(content) > POLICY_LOCK_MAX_BYTES)
173
- return undefined;
174
- try {
175
- const parsed = JSON.parse(content);
176
- return parsed.version === 4
177
- && (parsed.sessionNames === null || Array.isArray(parsed.sessionNames) && parsed.sessionNames.length > 0 && parsed.sessionNames.every(session => typeof session === "string"))
178
- && Number.isSafeInteger(parsed.pid) && (parsed.pid ?? 0) > 0
179
- && typeof parsed.startIdentity === "string" && parsed.startIdentity.length > 0
180
- && typeof parsed.token === "string" && parsed.token.length > 0
181
- && !parsed.token.includes("/") && !parsed.token.includes("\\") && !parsed.token.includes("\0")
182
- ? parsed
183
- : undefined;
184
- }
185
- catch {
186
- return undefined;
187
- }
188
- }
189
- function parseTicket(content, token) {
190
- if (Buffer.byteLength(content) > POLICY_LOCK_MAX_BYTES)
191
- return undefined;
192
- try {
193
- const parsed = JSON.parse(content);
194
- return parsed.version === 4
195
- && parsed.token === token
196
- && Number.isSafeInteger(parsed.ticket)
197
- && (parsed.ticket ?? 0) > 0
198
- ? parsed.ticket
199
- : undefined;
200
- }
201
- catch {
202
- return undefined;
203
- }
204
- }
205
- async function readClaim(path) {
206
- try {
207
- const directory = await lstat(path);
208
- const ownerPath = join(path, LOCK_OWNER_FILE);
209
- const ownerEntry = await lstat(ownerPath);
210
- if (!directory.isDirectory() || directory.isSymbolicLink() || !ownerEntry.isFile() || ownerEntry.isSymbolicLink())
211
- return undefined;
212
- if (ownerEntry.size > POLICY_LOCK_MAX_BYTES)
213
- return undefined;
214
- if (process.platform !== "win32") {
215
- const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
216
- if (uid === undefined || directory.uid !== uid || ownerEntry.uid !== uid || (directory.mode & 0o077) !== 0 || (ownerEntry.mode & 0o177) !== 0)
217
- return undefined;
218
- }
219
- const owner = parseOwner(await readFile(ownerPath, "utf8"));
220
- if (!owner)
221
- return undefined;
222
- const ticketPath = join(path, LOCK_TICKET_FILE);
223
- try {
224
- const ticketEntry = await lstat(ticketPath);
225
- if (!ticketEntry.isFile() || ticketEntry.isSymbolicLink() || ticketEntry.size > POLICY_LOCK_MAX_BYTES)
226
- return undefined;
227
- if (process.platform !== "win32") {
228
- const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
229
- if (uid === undefined || ticketEntry.uid !== uid || (ticketEntry.mode & 0o177) !== 0)
230
- return undefined;
231
- }
232
- const ticket = parseTicket(await readFile(ticketPath, "utf8"), owner.token);
233
- return ticket === undefined ? undefined : { owner, path, ticket };
234
- }
235
- catch (error) {
236
- return error.code === "ENOENT" ? { owner, path, ticket: null } : undefined;
237
- }
238
- }
239
- catch {
240
- return undefined;
241
- }
242
- }
243
- async function readClaims(basePath) {
244
- const directory = dirname(basePath);
245
- const prefix = `${basename(basePath)}.claim-`;
246
- let names;
247
- try {
248
- names = await readdir(directory);
249
- }
250
- catch {
251
- return undefined;
252
- }
253
- const claims = [];
254
- for (const name of names.filter((candidate) => candidate.startsWith(prefix))) {
255
- const path = join(directory, name);
256
- const claim = await readClaim(path);
257
- if (!claim) {
258
- try {
259
- await lstat(path);
260
- }
261
- catch (error) {
262
- if (error.code === "ENOENT")
263
- continue;
264
- }
265
- return undefined;
266
- }
267
- if (name !== `${prefix}${claim.owner.token}`)
268
- return undefined;
269
- claims.push(claim);
270
- }
271
- return claims;
272
- }
273
- async function ownerAlive(owner, budget) {
274
- try {
275
- process.kill(owner.pid, 0);
276
- }
277
- catch (error) {
278
- const code = error.code;
279
- if (code === "ESRCH")
280
- return false;
281
- if (code !== "EPERM")
282
- return undefined;
283
- }
284
- const current = await readProcessStartIdentity(owner.pid, process.platform, budget);
285
- return current === undefined ? undefined : processStartIdentitiesMatch(owner.startIdentity, current);
286
- }
287
- async function removeClaimOwnedBy(path, token, deadline = 0) {
288
- const movedPath = join(dirname(path), `.pi-agent-browser-policy-remove-${token}-${randomUUID()}`);
289
- while (true) {
290
- const current = await readClaim(path);
291
- if (current?.owner.token !== token)
292
- return false;
293
- try {
294
- await rename(path, movedPath);
295
- break;
296
- }
297
- catch (error) {
298
- const code = error.code;
299
- if (code === "ENOENT")
300
- return true;
301
- // Windows may refuse a directory move while a contender reads its
302
- // metadata. Revalidate before retrying. Owned-claim cleanup gets
303
- // its own bounded window, independent of the acquisition wait.
304
- if (process.platform !== "win32" || code !== "EPERM" || Date.now() >= deadline)
305
- return false;
306
- await waitForRetry();
307
- if (Date.now() >= deadline)
308
- return false;
309
- }
310
- }
311
- const moved = await readClaim(movedPath);
312
- if (moved?.owner.token !== token) {
313
- try {
314
- await rename(movedPath, path);
315
- }
316
- catch { }
317
- return false;
318
- }
319
- await rm(movedPath, { force: true, recursive: true });
320
- return true;
321
- }
322
- async function cleanDeadPolicyArtifacts(directory, budget) {
323
- let names;
324
- try {
325
- names = await readdir(directory);
326
- }
327
- catch {
328
- return;
329
- }
330
- // ponytail: list/sort all names; stream directories if enumeration becomes the bottleneck.
331
- const candidates = names.filter((name) => name.startsWith(".pi-agent-browser-policy-remove-")
332
- || /^\.pi-agent-browser-policy-[a-f0-9]{64}\.lock-v4\.(?:candidate|claim)-/.test(name)).sort();
333
- if (candidates.length === 0)
334
- return;
335
- const start = lastPolicyGcName === undefined ? randomInt(candidates.length)
336
- : Math.max(0, candidates.findIndex((name) => name > lastPolicyGcName));
337
- const batch = Array.from({ length: Math.min(POLICY_GC_BATCH_SIZE, candidates.length) }, (_, offset) => candidates[(start + offset) % candidates.length]);
338
- lastPolicyGcName = batch.at(-1);
339
- for (const name of batch) {
340
- if (budget.signal?.aborted || Date.now() >= (budget.deadline ?? Infinity))
341
- return;
342
- const path = join(directory, name);
343
- const published = name.includes(".lock-v4.claim-");
344
- if (published) {
345
- const entry = await lstat(path).catch(() => undefined);
346
- if (!entry || entry.mtimeMs >= Date.now() - STALE_CLAIM_MIN_AGE_MS)
347
- continue;
348
- }
349
- const claim = await readClaim(path);
350
- if (!claim || (published && !name.endsWith(`.claim-${claim.owner.token}`)))
351
- continue;
352
- if (await ownerAlive(claim.owner, budget) === false)
353
- await removeClaimOwnedBy(path, claim.owner.token).catch(() => false);
354
- }
355
- }
356
- function claimPrecedes(left, right) {
357
- if (left.ticket === null)
358
- return true;
359
- if (right.ticket === null)
360
- return false;
361
- return left.ticket < right.ticket || (left.ticket === right.ticket && left.owner.token < right.owner.token);
362
- }
363
- async function hasPublishedLaterTicket(claim, ownClaim) {
364
- if (claim.ticket !== null)
365
- return false;
366
- const current = await readClaim(claim.path);
367
- return current?.owner.token === claim.owner.token && !claimPrecedes(current, ownClaim);
368
- }
369
- function waitForRetry(signal) {
370
- return new Promise((resolve) => {
371
- if (signal?.aborted)
372
- return resolve();
373
- const timer = setTimeout(done, POLICY_LOCK_RETRY_MS);
374
- function done() {
375
- clearTimeout(timer);
376
- signal?.removeEventListener("abort", done);
377
- resolve();
378
- }
379
- signal?.addEventListener("abort", done, { once: true });
380
- });
127
+ return withBrowserExecutionLocks({
128
+ identities: [options.identity],
129
+ signal: options.signal,
130
+ deadline: options.deadline,
131
+ waitOnly: options.waitOnly,
132
+ }, run);
381
133
  }
382
134
  export async function acquireManagedSessionPolicyLock(options) {
383
- if (options.signal?.aborted)
135
+ if (options.signal?.aborted === true) {
384
136
  return undefined;
137
+ }
385
138
  let identity;
386
139
  try {
387
140
  identity = await resolveBrowserExecutionIdentity({ ...options, ownedManagedSession: true });
@@ -391,108 +144,22 @@ export async function acquireManagedSessionPolicyLock(options) {
391
144
  }
392
145
  const scope = executionScope.getStore();
393
146
  if (scope) {
394
- if (!scope.active || !scopeCovers(scope.identities, groupExecutionIdentities([identity])))
147
+ if (!scope.active || !scopeCovers(scope.identities, groupExecutionIdentities([identity]))) {
395
148
  return undefined;
396
- return { release: async () => undefined };
397
- }
398
- return acquireExecutionClaim({ identity: groupExecutionIdentities([identity])[0], signal: options.signal, timeoutMs: options.timeoutMs });
399
- }
400
- async function acquireExecutionClaim(options) {
401
- if (options.signal?.aborted)
402
- return undefined;
403
- const deadline = options.deadline ?? Date.now() + (options.timeoutMs ?? POLICY_LOCK_WAIT_MS);
404
- // timeoutMs: 0 retains the existing single-attempt policy probe contract.
405
- const budget = { signal: options.signal, deadline: options.timeoutMs === 0 ? undefined : deadline };
406
- const platform = process.platform;
407
- const directory = getCoordinationDirectory(platform);
408
- if (!await ensureCoordinationDirectory(directory, platform))
409
- return undefined;
410
- const basePath = getBrowserExecutionLockPath(options.identity);
411
- const token = randomUUID();
412
- const startIdentity = await readProcessStartIdentity(process.pid, process.platform, budget);
413
- if (!startIdentity)
414
- return undefined;
415
- const owner = { pid: process.pid, startIdentity, token, sessionNames: options.identity.sessionNames, version: 4 };
416
- const ownerContent = JSON.stringify(owner);
417
- // Never publish metadata our reader cannot validate and ownership-safely remove.
418
- if (Buffer.byteLength(ownerContent) > POLICY_LOCK_MAX_BYTES)
419
- return undefined;
420
- const candidatePath = `${basePath}.candidate-${token}`;
421
- const claimPath = `${basePath}.claim-${token}`;
422
- let claimPublished = false;
423
- let lockAcquired = false;
424
- try {
425
- await mkdir(candidatePath, { mode: 0o700 });
426
- await writeFile(join(candidatePath, LOCK_OWNER_FILE), ownerContent, { encoding: "utf8", flag: "wx", mode: 0o600 });
427
- await rename(candidatePath, claimPath);
428
- claimPublished = true;
429
- const initialClaims = await readClaims(basePath);
430
- if (!initialClaims)
431
- return undefined;
432
- const maxTicket = initialClaims.reduce((max, claim) => claim.ticket === null ? max : Math.max(max, claim.ticket), 0);
433
- if (!Number.isSafeInteger(maxTicket + 1))
434
- return undefined;
435
- const ticket = { ticket: maxTicket + 1, token, version: 4 };
436
- const ticketCandidatePath = join(claimPath, `.ticket-${token}.tmp`);
437
- await writeFile(ticketCandidatePath, JSON.stringify(ticket), { encoding: "utf8", flag: "wx", mode: 0o600 });
438
- await rename(ticketCandidatePath, join(claimPath, LOCK_TICKET_FILE));
439
- while (!options.signal?.aborted) {
440
- const claims = await readClaims(basePath);
441
- if (!claims)
442
- return undefined;
443
- const ownClaim = claims.find((claim) => claim.owner.token === token);
444
- if (!ownClaim || ownClaim.ticket !== ticket.ticket)
445
- return undefined;
446
- let blocked = false;
447
- for (const claim of claims) {
448
- const disjoint = owner.sessionNames !== null && claim.owner.sessionNames !== null
449
- && !owner.sessionNames.some(session => claim.owner.sessionNames.includes(session));
450
- if (claim.owner.token === token || disjoint || !claimPrecedes(claim, ownClaim))
451
- continue;
452
- // Choosing is transient: a later published ticket must not make
453
- // its predecessor wait on it using an earlier null snapshot.
454
- if (await hasPublishedLaterTicket(claim, ownClaim))
455
- continue;
456
- const alive = await ownerAlive(claim.owner, budget);
457
- if (alive === false) {
458
- await removeClaimOwnedBy(claim.path, claim.owner.token);
459
- continue;
460
- }
461
- // A native identity query can outlive the owner's entire critical
462
- // section. Its result (including unknown after exit) does not make
463
- // an already released immutable claim a current blocker.
464
- try {
465
- await lstat(claim.path);
466
- }
467
- catch (error) {
468
- if (error.code === "ENOENT")
469
- continue;
470
- }
471
- // Publication can also complete during the native identity query.
472
- if (await hasPublishedLaterTicket(claim, ownClaim))
473
- continue;
474
- blocked = true;
475
- break;
476
- }
477
- if (!blocked) {
478
- await cleanDeadPolicyArtifacts(directory, budget);
479
- if (options.signal?.aborted || (budget.deadline !== undefined && Date.now() >= budget.deadline))
480
- return undefined;
481
- lockAcquired = true;
482
- return { release: async () => { await removeClaimOwnedBy(claimPath, token, Date.now() + POLICY_LOCK_WAIT_MS); } };
483
- }
484
- if (Date.now() >= deadline)
485
- return undefined;
486
- await waitForRetry(options.signal);
487
149
  }
488
- return undefined;
150
+ return {
151
+ release: async () => {
152
+ /* The outer execution owns release of this borrowed claim. */
153
+ },
154
+ };
489
155
  }
490
- catch {
156
+ const grouped = groupExecutionIdentities([identity]).at(0);
157
+ if (grouped === undefined) {
491
158
  return undefined;
492
159
  }
493
- finally {
494
- await rm(candidatePath, { force: true, recursive: true }).catch(() => undefined);
495
- if (claimPublished && !lockAcquired)
496
- await removeClaimOwnedBy(claimPath, token, Date.now() + POLICY_LOCK_WAIT_MS);
497
- }
160
+ return acquireExecutionClaim({
161
+ identity: grouped,
162
+ signal: options.signal,
163
+ timeoutMs: options.timeoutMs,
164
+ });
498
165
  }
@@ -0,0 +1,58 @@
1
+ import { lstatSync } from "node:fs";
2
+ import { join, parse } from "node:path";
3
+ import { getCurrentProcessUid } from "./process-identity.js";
4
+ function androidSystemAncestor(path, entry, platform) {
5
+ return (platform === "android" &&
6
+ (path === "/data" || path === "/data/data") &&
7
+ entry.uid === 1000 &&
8
+ (entry.mode & 0o002) === 0);
9
+ }
10
+ function androidAppDirectory(entry, uid, platform) {
11
+ return (platform === "android" && entry.uid === uid && entry.gid === uid && (entry.mode & 0o002) === 0);
12
+ }
13
+ function ancestorModeTrusted(entry, android) {
14
+ const rootSticky = entry.uid === 0 && (entry.mode & 0o1000) !== 0;
15
+ return (entry.mode & 0o022) === 0 || rootSticky || android.system || android.app;
16
+ }
17
+ function ancestorTrusted(path, entry, uid, platform) {
18
+ if (entry.isSymbolicLink() || !entry.isDirectory()) {
19
+ return false;
20
+ }
21
+ const system = androidSystemAncestor(path, entry, platform);
22
+ if (!system && entry.uid !== 0 && entry.uid !== uid) {
23
+ return false;
24
+ }
25
+ return ancestorModeTrusted(entry, { system, app: androidAppDirectory(entry, uid, platform) });
26
+ }
27
+ export function isTrustedPosixDirectory(path, requireCurrentOwner, platform = process.platform) {
28
+ const uid = getCurrentProcessUid();
29
+ if (uid === undefined) {
30
+ return false;
31
+ }
32
+ const root = parse(path).root;
33
+ let cursor = root;
34
+ for (const component of path.slice(root.length).split("/").filter(Boolean)) {
35
+ cursor = join(cursor, component);
36
+ try {
37
+ if (!ancestorTrusted(cursor, lstatSync(cursor), uid, platform)) {
38
+ return false;
39
+ }
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ try {
46
+ return !requireCurrentOwner || lstatSync(path).uid === uid;
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ }
52
+ export function isTrustedCurrentFile(entry, platform, forbiddenMode) {
53
+ if (platform === "win32") {
54
+ return true;
55
+ }
56
+ const uid = getCurrentProcessUid();
57
+ return uid !== undefined && entry.uid === uid && (entry.mode & forbiddenMode) === 0;
58
+ }