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.
- package/CHANGELOG.md +77 -5
- package/README.md +103 -81
- package/dist/extensions/agent-browser/index.js +43057 -2031
- package/dist/extensions/agent-browser/lib/argv-descriptor.js +49 -26
- package/dist/extensions/agent-browser/lib/argv-grammar.js +82 -93
- package/dist/extensions/agent-browser/lib/bash-guard.js +129 -126
- package/dist/extensions/agent-browser/lib/batch-lifecycle.js +112 -51
- package/dist/extensions/agent-browser/lib/browser-execution-claim-codec.js +61 -0
- package/dist/extensions/agent-browser/lib/browser-execution-claim-storage.js +232 -0
- package/dist/extensions/agent-browser/lib/browser-execution-claims.js +202 -0
- package/dist/extensions/agent-browser/lib/browser-execution-identity.js +77 -0
- package/dist/extensions/agent-browser/lib/browser-journal-branch.js +98 -0
- package/dist/extensions/agent-browser/lib/browser-journal-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/browser-journal-projection.js +221 -0
- package/dist/extensions/agent-browser/lib/browser-journal-reader.js +89 -0
- package/dist/extensions/agent-browser/lib/browser-journal-replay.js +246 -0
- package/dist/extensions/agent-browser/lib/browser-journal.js +103 -394
- package/dist/extensions/agent-browser/lib/browser-legacy-pages.js +220 -0
- package/dist/extensions/agent-browser/lib/browser-legacy-projection.js +282 -0
- package/dist/extensions/agent-browser/lib/browser-legacy-types.js +1 -0
- package/dist/extensions/agent-browser/lib/browser-session-conversion-stream.js +217 -0
- package/dist/extensions/agent-browser/lib/browser-session-conversion.js +80 -335
- package/dist/extensions/agent-browser/lib/browser-transcript-contracts.js +35 -0
- package/dist/extensions/agent-browser/lib/browser-transcript-validation.js +166 -0
- package/dist/extensions/agent-browser/lib/browser-transcript.js +137 -82
- package/dist/extensions/agent-browser/lib/browser-value-parsing.js +15 -0
- package/dist/extensions/agent-browser/lib/command-capabilities.js +340 -0
- package/dist/extensions/agent-browser/lib/command-policy.js +107 -88
- package/dist/extensions/agent-browser/lib/command-taxonomy.js +49 -322
- package/dist/extensions/agent-browser/lib/config-policy.js +138 -343
- package/dist/extensions/agent-browser/lib/config-providers.js +71 -0
- package/dist/extensions/agent-browser/lib/config-validation.js +218 -0
- package/dist/extensions/agent-browser/lib/config.js +19 -7
- package/dist/extensions/agent-browser/lib/electron/cdp.js +15 -7
- package/dist/extensions/agent-browser/lib/electron/cleanup.js +134 -55
- package/dist/extensions/agent-browser/lib/electron/discovery-darwin.js +109 -0
- package/dist/extensions/agent-browser/lib/electron/discovery-desktop.js +136 -0
- package/dist/extensions/agent-browser/lib/electron/discovery-evidence.js +89 -0
- package/dist/extensions/agent-browser/lib/electron/discovery-linux.js +93 -0
- package/dist/extensions/agent-browser/lib/electron/discovery-packages.js +162 -0
- package/dist/extensions/agent-browser/lib/electron/discovery-types.js +2 -0
- package/dist/extensions/agent-browser/lib/electron/discovery.js +140 -549
- package/dist/extensions/agent-browser/lib/electron/launch-monitor.js +102 -0
- package/dist/extensions/agent-browser/lib/electron/launch-process.js +209 -0
- package/dist/extensions/agent-browser/lib/electron/launch-types.js +2 -0
- package/dist/extensions/agent-browser/lib/electron/launch.js +249 -354
- package/dist/extensions/agent-browser/lib/executable-path.js +21 -12
- package/dist/extensions/agent-browser/lib/execution-cwd.js +35 -18
- package/dist/extensions/agent-browser/lib/input-modes/electron.js +162 -121
- package/dist/extensions/agent-browser/lib/input-modes/job.js +116 -313
- package/dist/extensions/agent-browser/lib/input-modes/lookup-network-evidence.js +104 -0
- package/dist/extensions/agent-browser/lib/input-modes/lookup-plan.js +132 -0
- package/dist/extensions/agent-browser/lib/input-modes/lookup-redaction.js +57 -0
- package/dist/extensions/agent-browser/lib/input-modes/lookup-source-evidence.js +151 -0
- package/dist/extensions/agent-browser/lib/input-modes/lookup-workspace.js +142 -0
- package/dist/extensions/agent-browser/lib/input-modes/lookups.js +57 -412
- package/dist/extensions/agent-browser/lib/input-modes/params.js +63 -17
- package/dist/extensions/agent-browser/lib/input-modes/qa-analysis.js +268 -0
- package/dist/extensions/agent-browser/lib/input-modes/qa-presentation.js +117 -0
- package/dist/extensions/agent-browser/lib/input-modes/script-child.js +396 -0
- package/dist/extensions/agent-browser/lib/input-modes/script-protocol.js +86 -0
- package/dist/extensions/agent-browser/lib/input-modes/script-types.js +1 -0
- package/dist/extensions/agent-browser/lib/input-modes/script-validation.js +60 -0
- package/dist/extensions/agent-browser/lib/input-modes/script.js +60 -409
- package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +218 -128
- package/dist/extensions/agent-browser/lib/input-modes/shared.js +15 -4
- package/dist/extensions/agent-browser/lib/input-modes/types.js +56 -7
- package/dist/extensions/agent-browser/lib/json-schema.js +22 -10
- package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +17 -5
- package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +92 -425
- package/dist/extensions/agent-browser/lib/managed-session-posix-storage.js +58 -0
- package/dist/extensions/agent-browser/lib/managed-session-project-identity.js +244 -0
- package/dist/extensions/agent-browser/lib/managed-session-restore-context.js +84 -0
- package/dist/extensions/agent-browser/lib/managed-session-restore-policy.js +119 -0
- package/dist/extensions/agent-browser/lib/managed-session-restore-state.js +83 -0
- package/dist/extensions/agent-browser/lib/managed-session-restore.js +168 -300
- package/dist/extensions/agent-browser/lib/managed-session-snapshot-records.js +277 -0
- package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +128 -305
- package/dist/extensions/agent-browser/lib/managed-session-storage.js +56 -253
- package/dist/extensions/agent-browser/lib/native-confirmation.js +140 -0
- package/dist/extensions/agent-browser/lib/native-output.js +43 -9
- package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +106 -59
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-merge.js +14 -6
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +109 -57
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/browser-observation-result.js +82 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +164 -60
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostic-values.js +31 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +152 -781
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-observation.js +202 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-text-diagnostics.js +109 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/fill-diagnostics.js +119 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-action-recovery.js +147 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-actions.js +144 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-content.js +123 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-details.js +156 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-electron.js +179 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-evidence.js +39 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-missing-binary.js +89 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-recovery.js +97 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-redaction.js +106 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-timeout.js +110 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +41 -538
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +199 -154
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/interaction-diagnostics.js +290 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-close.js +167 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-inspection.js +108 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +127 -205
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/native-helper-observation.js +65 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/observation-types.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/overlay-diagnostics.js +120 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +113 -30
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +109 -28
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter-data.js +150 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +138 -253
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-rendered-text.js +147 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +59 -24
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-artifacts.js +159 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-command.js +131 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-daemon.js +93 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-failure.js +42 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-guards.js +242 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-input.js +75 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-observations.js +92 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-page-selection.js +254 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-page-state.js +121 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-refs.js +130 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-resources.js +114 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-semantic.js +121 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-session-plan.js +222 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-timeouts.js +68 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +176 -1123
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-analysis.js +191 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-confirmation.js +152 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-diagnostics.js +182 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-electron.js +150 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-phase-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-phase.js +115 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle.js +256 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-managed-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-managed.js +256 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native-phase-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native-phase.js +93 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native.js +113 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-navigation-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-navigation.js +316 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-ownership.js +28 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-page-phase-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-page-phase.js +142 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-presentation-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-presentation.js +333 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication-phase-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication-phase.js +71 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication.js +201 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-receipts.js +183 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-refs.js +200 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-tabs.js +142 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +18 -968
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +23 -13
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-receipt-reconciliation.js +198 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery-presentation.js +154 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery.js +68 -151
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-capture.js +14 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-observation.js +169 -46
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-commands.js +130 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-electron.js +210 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-observations.js +61 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-outcomes.js +187 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-refs.js +171 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-tabs.js +228 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +77 -765
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/text-visibility-diagnostics.js +182 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-diagnostics.js +256 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-progress.js +108 -0
- package/dist/extensions/agent-browser/lib/orchestration/code-artifact-observation.js +39 -0
- package/dist/extensions/agent-browser/lib/orchestration/code-image-observation.js +119 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/branch.js +92 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/cleanup-result.js +58 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/cleanup.js +78 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/discovery.js +106 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +48 -821
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/policy.js +86 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-collection.js +69 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-data.js +167 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-presentation.js +164 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe.js +161 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/status.js +165 -0
- package/dist/extensions/agent-browser/lib/orchestration/execution-queue.js +21 -9
- package/dist/extensions/agent-browser/lib/orchestration/extension-artifact-preflight.js +211 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-artifacts.js +23 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-attachment-replay.js +99 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-branch-restore.js +275 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-code.js +280 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-command-admission.js +303 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-command-output.js +36 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-command-result.js +335 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-command-run.js +227 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-command-state.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-electron-ownership.js +204 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-execution-locks.js +139 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-execution-queue.js +24 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-host-coordination.js +98 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-host-run.js +295 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-intent-replay.js +41 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-invocation.js +7 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-lifecycle.js +102 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-managed-ownership.js +133 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-observation.js +120 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-prompt.js +180 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-recording.js +290 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-resource-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-resource-replay.js +269 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-result-state.js +113 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-runtime.js +146 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-script-leases.js +58 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-tool-boundary.js +62 -0
- package/dist/extensions/agent-browser/lib/orchestration/extension-version-check.js +54 -0
- package/dist/extensions/agent-browser/lib/orchestration/input-plan-types.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +261 -185
- package/dist/extensions/agent-browser/lib/orchestration/input-redaction.js +62 -0
- package/dist/extensions/agent-browser/lib/orchestration/native-config.js +144 -0
- package/dist/extensions/agent-browser/lib/orchestration/native-root-launch.js +77 -0
- package/dist/extensions/agent-browser/lib/orchestration/native-session-defaults.js +210 -157
- package/dist/extensions/agent-browser/lib/orchestration/operation-paths.js +124 -58
- package/dist/extensions/agent-browser/lib/orchestration/output-file.js +197 -99
- package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +199 -96
- package/dist/extensions/agent-browser/lib/owned-managed-session-context.js +55 -0
- package/dist/extensions/agent-browser/lib/page-target-batch.js +118 -0
- package/dist/extensions/agent-browser/lib/page-target-guards.js +50 -0
- package/dist/extensions/agent-browser/lib/page-target-navigation.js +104 -0
- package/dist/extensions/agent-browser/lib/page-target-validation.js +55 -246
- package/dist/extensions/agent-browser/lib/parsing.js +13 -4
- package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +133 -68
- package/dist/extensions/agent-browser/lib/playbook.js +16 -12
- package/dist/extensions/agent-browser/lib/process-child.js +284 -0
- package/dist/extensions/agent-browser/lib/process-environment.js +13 -6
- package/dist/extensions/agent-browser/lib/process-errors.js +23 -0
- package/dist/extensions/agent-browser/lib/process-identity.js +47 -15
- package/dist/extensions/agent-browser/lib/process-socket-storage.js +256 -0
- package/dist/extensions/agent-browser/lib/process-stdout.js +74 -0
- package/dist/extensions/agent-browser/lib/process.js +145 -536
- package/dist/extensions/agent-browser/lib/prompt-artifacts.js +287 -0
- package/dist/extensions/agent-browser/lib/prompt-policy.js +15 -194
- package/dist/extensions/agent-browser/lib/read-command.js +41 -0
- package/dist/extensions/agent-browser/lib/read-confirmation.js +131 -68
- package/dist/extensions/agent-browser/lib/recording-reservations.js +118 -45
- package/dist/extensions/agent-browser/lib/redaction-fields.js +75 -0
- package/dist/extensions/agent-browser/lib/redaction-json.js +149 -0
- package/dist/extensions/agent-browser/lib/redaction-url.js +88 -0
- package/dist/extensions/agent-browser/lib/results/action-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/results/action-recommendations.js +28 -271
- package/dist/extensions/agent-browser/lib/results/artifact-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/results/artifact-manifest-validation.js +133 -0
- package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +96 -94
- package/dist/extensions/agent-browser/lib/results/artifact-recommendations.js +73 -0
- package/dist/extensions/agent-browser/lib/results/categories.js +111 -54
- package/dist/extensions/agent-browser/lib/results/confirmation.js +29 -13
- package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +62 -27
- package/dist/extensions/agent-browser/lib/results/electron-recommendations.js +83 -0
- package/dist/extensions/agent-browser/lib/results/envelope-decoding.js +48 -0
- package/dist/extensions/agent-browser/lib/results/envelope.js +90 -67
- package/dist/extensions/agent-browser/lib/results/evidence-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/results/failure-recommendations.js +180 -0
- package/dist/extensions/agent-browser/lib/results/network-routes.js +86 -45
- package/dist/extensions/agent-browser/lib/results/network.js +35 -12
- package/dist/extensions/agent-browser/lib/results/next-actions.js +49 -19
- package/dist/extensions/agent-browser/lib/results/presentation/artifact-files.js +320 -0
- package/dist/extensions/agent-browser/lib/results/presentation/artifact-format.js +138 -0
- package/dist/extensions/agent-browser/lib/results/presentation/artifact-images.js +113 -0
- package/dist/extensions/agent-browser/lib/results/presentation/artifact-verification.js +145 -0
- package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +99 -555
- package/dist/extensions/agent-browser/lib/results/presentation/batch-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/results/presentation/batch-recording.js +118 -0
- package/dist/extensions/agent-browser/lib/results/presentation/batch-redaction.js +68 -0
- package/dist/extensions/agent-browser/lib/results/presentation/batch-rendering.js +135 -0
- package/dist/extensions/agent-browser/lib/results/presentation/batch-step.js +227 -0
- package/dist/extensions/agent-browser/lib/results/presentation/batch-summary.js +91 -0
- package/dist/extensions/agent-browser/lib/results/presentation/batch.js +91 -460
- package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +9 -5
- package/dist/extensions/agent-browser/lib/results/presentation/command-presenters.js +216 -0
- package/dist/extensions/agent-browser/lib/results/presentation/common.js +26 -9
- package/dist/extensions/agent-browser/lib/results/presentation/content.js +86 -29
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-a11y.js +67 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-health.js +79 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-identity.js +199 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-logs.js +75 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-network-actions.js +216 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-network.js +124 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-redaction.js +64 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-storage.js +209 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-stream.js +69 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-summary.js +222 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +103 -1052
- package/dist/extensions/agent-browser/lib/results/presentation/early-result.js +70 -0
- package/dist/extensions/agent-browser/lib/results/presentation/errors.js +130 -60
- package/dist/extensions/agent-browser/lib/results/presentation/input-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +60 -145
- package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +147 -88
- package/dist/extensions/agent-browser/lib/results/presentation/notices.js +75 -0
- package/dist/extensions/agent-browser/lib/results/presentation/observation-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/results/presentation/observation-rendering.js +127 -0
- package/dist/extensions/agent-browser/lib/results/presentation/outcomes.js +120 -0
- package/dist/extensions/agent-browser/lib/results/presentation/output-completion.js +77 -0
- package/dist/extensions/agent-browser/lib/results/presentation/output-spill.js +51 -0
- package/dist/extensions/agent-browser/lib/results/presentation/registry.js +116 -240
- package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +35 -21
- package/dist/extensions/agent-browser/lib/results/presentation/skills.js +104 -73
- package/dist/extensions/agent-browser/lib/results/presentation/source.js +109 -0
- package/dist/extensions/agent-browser/lib/results/presentation.js +17 -261
- package/dist/extensions/agent-browser/lib/results/recommendation-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/results/recording.js +52 -14
- package/dist/extensions/agent-browser/lib/results/recovery-actions.js +14 -5
- package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +30 -22
- package/dist/extensions/agent-browser/lib/results/selector-recovery-target.js +83 -0
- package/dist/extensions/agent-browser/lib/results/selector-recovery.js +119 -119
- package/dist/extensions/agent-browser/lib/results/snapshot-compact.js +266 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-content.js +32 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +104 -71
- package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +31 -11
- package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +125 -66
- package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +26 -7
- package/dist/extensions/agent-browser/lib/results/snapshot.js +28 -248
- package/dist/extensions/agent-browser/lib/results/text.js +16 -5
- package/dist/extensions/agent-browser/lib/runtime-args-validation.js +133 -0
- package/dist/extensions/agent-browser/lib/runtime-compatibility.js +81 -0
- package/dist/extensions/agent-browser/lib/runtime-contracts.js +1 -0
- package/dist/extensions/agent-browser/lib/runtime-redaction.js +118 -0
- package/dist/extensions/agent-browser/lib/runtime-replay-events.js +144 -0
- package/dist/extensions/agent-browser/lib/runtime-session-identity.js +76 -0
- package/dist/extensions/agent-browser/lib/runtime-session-plan.js +114 -0
- package/dist/extensions/agent-browser/lib/runtime-session-replay.js +123 -0
- package/dist/extensions/agent-browser/lib/runtime-tab-correction.js +65 -0
- package/dist/extensions/agent-browser/lib/runtime-timeouts.js +28 -0
- package/dist/extensions/agent-browser/lib/runtime.js +137 -1041
- package/dist/extensions/agent-browser/lib/session-identity.js +51 -0
- package/dist/extensions/agent-browser/lib/session-page-observation.js +357 -0
- package/dist/extensions/agent-browser/lib/session-page-state.js +178 -333
- package/dist/extensions/agent-browser/lib/session-page-types.js +1 -0
- package/dist/extensions/agent-browser/lib/temp-artifact-budget.js +78 -0
- package/dist/extensions/agent-browser/lib/temp-mutation-queue.js +7 -0
- package/dist/extensions/agent-browser/lib/temp-root-ownership.js +234 -0
- package/dist/extensions/agent-browser/lib/temp-root.js +207 -0
- package/dist/extensions/agent-browser/lib/temp.js +33 -446
- package/dist/extensions/agent-browser/lib/tool-surface.js +94 -24
- package/dist/extensions/agent-browser/lib/upstream-version.js +3 -2
- package/dist/extensions/agent-browser/lib/web-search-providers.js +229 -0
- package/dist/extensions/agent-browser/lib/web-search-request.js +108 -0
- package/dist/extensions/agent-browser/lib/web-search-results.js +281 -0
- package/dist/extensions/agent-browser/lib/web-search-schema.js +82 -0
- package/dist/extensions/agent-browser/lib/web-search.js +109 -617
- package/dist/extensions/agent-browser/lib/webmcp-observation.js +13 -6
- package/dist/extensions/agent-browser/lib/windows-stock-launcher.js +63 -37
- package/dist/extensions/agent-browser/script-worker.js +80 -43
- package/dist/scripts/agent-browser-target.mjs +4 -2
- package/docs/ARCHITECTURE.md +17 -5
- package/docs/CODE_QUALITY.md +242 -0
- package/docs/COMMAND_REFERENCE.md +251 -220
- package/docs/ELECTRON.md +53 -44
- package/docs/RELEASE.md +18 -15
- package/docs/REQUIREMENTS.md +1 -0
- package/docs/SUPPORT_MATRIX.md +76 -75
- package/docs/TOOL_CONTRACT.md +145 -116
- package/docs/platform-smoke.md +5 -5
- package/package.json +143 -120
- package/scripts/agent-browser-capability-baseline.mjs +361 -957
- package/scripts/agent-browser-target.mjs +6 -2
- package/scripts/build.mjs +37 -8
- package/scripts/capability-core-commands.mjs +193 -0
- package/scripts/capability-options.mjs +283 -0
- package/scripts/capability-samples.mjs +133 -0
- package/scripts/capability-section.mjs +11 -0
- package/scripts/config.mjs +213 -114
- package/scripts/convert-browser-session.mjs +30 -9
- package/scripts/doctor-sources.mjs +195 -0
- package/scripts/doctor.mjs +92 -247
- package/scripts/platform-smoke/artifacts.mjs +38 -11
- package/scripts/platform-smoke/commands.mjs +104 -0
- package/scripts/platform-smoke/crabbox-runner.mjs +167 -80
- package/scripts/platform-smoke/doctor-support.mjs +157 -0
- package/scripts/platform-smoke/doctor-windows.mjs +230 -0
- package/scripts/platform-smoke/doctor.mjs +212 -320
- package/scripts/platform-smoke/lease-evidence.mjs +134 -0
- package/scripts/platform-smoke/suite-checks.mjs +98 -0
- package/scripts/platform-smoke/suite-evidence.mjs +281 -0
- package/scripts/platform-smoke/targets.mjs +158 -472
- package/scripts/platform-smoke.mjs +55 -40
- package/scripts/prepare.mjs +16 -7
|
@@ -1,122 +1,88 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
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
|
|
99
|
-
|
|
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
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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({
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
|
150
|
+
return {
|
|
151
|
+
release: async () => {
|
|
152
|
+
/* The outer execution owns release of this borrowed claim. */
|
|
153
|
+
},
|
|
154
|
+
};
|
|
489
155
|
}
|
|
490
|
-
|
|
156
|
+
const grouped = groupExecutionIdentities([identity]).at(0);
|
|
157
|
+
if (grouped === undefined) {
|
|
491
158
|
return undefined;
|
|
492
159
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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
|
+
}
|