pi-agent-browser-native 0.9.2 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +91 -5
- package/README.md +120 -86
- package/dist/extensions/agent-browser/index.js +43065 -2016
- 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 +113 -49
- 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 -81
- 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 +44 -9
- package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +107 -66
- 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 +171 -57
- 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 +204 -108
- 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 -199
- 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 -1114
- 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 -910
- 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 -753
- 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 -816
- 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 -139
- package/dist/extensions/agent-browser/lib/orchestration/operation-paths.js +124 -58
- package/dist/extensions/agent-browser/lib/orchestration/output-file.js +198 -98
- 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 +59 -243
- package/dist/extensions/agent-browser/lib/parsing.js +13 -4
- package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +134 -68
- package/dist/extensions/agent-browser/lib/playbook.js +18 -14
- package/dist/extensions/agent-browser/lib/process-child.js +284 -0
- package/dist/extensions/agent-browser/lib/process-environment.js +22 -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 +146 -537
- 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 +138 -35
- 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 -10
- 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 +93 -66
- 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 -552
- 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 -1019
- 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 +117 -237
- 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 -248
- 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 +123 -123
- 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 -1037
- 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 +188 -324
- 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 +22 -10
- package/docs/CODE_QUALITY.md +242 -0
- package/docs/COMMAND_REFERENCE.md +264 -229
- package/docs/ELECTRON.md +53 -44
- package/docs/RELEASE.md +21 -17
- package/docs/REQUIREMENTS.md +2 -0
- package/docs/SESSION_STORAGE.md +1 -1
- package/docs/SUPPORT_MATRIX.md +84 -77
- package/docs/TOOL_CONTRACT.md +165 -130
- 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
|
@@ -2,33 +2,40 @@ import { execFile } from "node:child_process";
|
|
|
2
2
|
import { lstat, rm } from "node:fs/promises";
|
|
3
3
|
import { win32 } from "node:path";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
|
-
import { fetchCdpJson, parseCdpTargets, parseCdpVersion } from "./cdp.js";
|
|
6
|
-
import { ELECTRON_PROFILE_DIR_PREFIX } from "./launch.js";
|
|
5
|
+
import { fetchCdpJson, parseCdpTargets, parseCdpVersion, } from "./cdp.js";
|
|
6
|
+
import { ELECTRON_PROFILE_DIR_PREFIX } from "./launch-types.js";
|
|
7
7
|
import { pathExists } from "../fs-utils.js";
|
|
8
|
+
import { isRecord } from "../parsing.js";
|
|
9
|
+
import { stringifyUnknown } from "../results/text.js";
|
|
8
10
|
import { getSecureTempChildDirectoryValidationError } from "../temp.js";
|
|
9
11
|
const ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS = 5_000;
|
|
10
12
|
const ELECTRON_CLEANUP_POLL_INTERVAL_MS = 100;
|
|
11
13
|
const RESTORED_PROCESS_COMMAND_TIMEOUT_MS = 1_000;
|
|
14
|
+
// Node's callback-style execFile returns a ChildProcess; promisify owns its completion callback, not that return value.
|
|
15
|
+
// oxlint-disable-next-line typescript/strict-void-return
|
|
12
16
|
const execFileAsync = promisify(execFile);
|
|
13
17
|
function sleep(ms) {
|
|
14
|
-
return new Promise((resolve) =>
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
setTimeout(resolve, ms);
|
|
20
|
+
});
|
|
15
21
|
}
|
|
16
22
|
function isPidAlive(pid) {
|
|
17
|
-
if (
|
|
23
|
+
if (pid === undefined || !Number.isSafeInteger(pid) || pid <= 0) {
|
|
18
24
|
return undefined;
|
|
25
|
+
}
|
|
19
26
|
try {
|
|
20
27
|
process.kill(pid, 0);
|
|
21
28
|
return true;
|
|
22
29
|
}
|
|
23
30
|
catch (error) {
|
|
24
|
-
|
|
25
|
-
return code === "EPERM" ? true : false;
|
|
31
|
+
return isRecord(error) && error.code === "EPERM";
|
|
26
32
|
}
|
|
27
33
|
}
|
|
28
34
|
async function isPortAlive(port, signal) {
|
|
29
35
|
const version = parseCdpVersion(await fetchCdpJson(`http://127.0.0.1:${port}/json/version`, signal));
|
|
30
|
-
if (!version)
|
|
36
|
+
if (!version) {
|
|
31
37
|
return { targets: [] };
|
|
38
|
+
}
|
|
32
39
|
const targets = parseCdpTargets(await fetchCdpJson(`http://127.0.0.1:${port}/json/list`, signal));
|
|
33
40
|
return { targets, version };
|
|
34
41
|
}
|
|
@@ -40,7 +47,7 @@ export async function inspectElectronLaunchStatus(record, signal) {
|
|
|
40
47
|
userDataDirState = "present";
|
|
41
48
|
}
|
|
42
49
|
catch (error) {
|
|
43
|
-
userDataDirState = error.code === "ENOENT" ? "absent" : "unknown";
|
|
50
|
+
userDataDirState = isRecord(error) && error.code === "ENOENT" ? "absent" : "unknown";
|
|
44
51
|
}
|
|
45
52
|
return {
|
|
46
53
|
cleanupState: record.cleanupState,
|
|
@@ -61,31 +68,42 @@ function hasProcessExited(child, pid) {
|
|
|
61
68
|
}
|
|
62
69
|
async function waitForProcessExit(child, pid, deadlineMs) {
|
|
63
70
|
while (Date.now() <= deadlineMs) {
|
|
64
|
-
if (hasProcessExited(child, pid))
|
|
71
|
+
if (hasProcessExited(child, pid)) {
|
|
65
72
|
return true;
|
|
73
|
+
}
|
|
74
|
+
// Polling observes exit between sleeps; parallel waits cannot preserve the deadline.
|
|
75
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
66
76
|
await sleep(ELECTRON_CLEANUP_POLL_INTERVAL_MS);
|
|
67
77
|
}
|
|
68
78
|
return hasProcessExited(child, pid);
|
|
69
79
|
}
|
|
70
80
|
async function readPidCommandLine(pid) {
|
|
71
|
-
if (!
|
|
81
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) {
|
|
72
82
|
return undefined;
|
|
83
|
+
}
|
|
73
84
|
try {
|
|
74
85
|
// Win32_Process.CommandLine is the native ownership evidence; process
|
|
75
86
|
// start time (used by daemon-policy locks) cannot prove profile ownership.
|
|
76
87
|
const systemRoot = process.env.SystemRoot;
|
|
77
|
-
const windowsRoot = systemRoot && win32.isAbsolute(systemRoot)
|
|
88
|
+
const windowsRoot = systemRoot !== undefined && systemRoot.length > 0 && win32.isAbsolute(systemRoot)
|
|
89
|
+
? systemRoot
|
|
90
|
+
: "C:\\Windows";
|
|
78
91
|
const file = process.platform === "win32"
|
|
79
92
|
? win32.join(windowsRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
|
80
93
|
: "ps";
|
|
81
94
|
const args = process.platform === "win32"
|
|
82
|
-
? [
|
|
83
|
-
|
|
95
|
+
? [
|
|
96
|
+
"-NoProfile",
|
|
97
|
+
"-NonInteractive",
|
|
98
|
+
"-Command",
|
|
99
|
+
`[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new(); $p = [wmi]"Win32_Process.Handle='${pid}'"; [Console]::WriteLine($p.CommandLine)`,
|
|
100
|
+
]
|
|
84
101
|
: ["-ww", "-p", String(pid), "-o", "command="];
|
|
85
102
|
const { stdout } = await execFileAsync(file, args, {
|
|
86
103
|
timeout: RESTORED_PROCESS_COMMAND_TIMEOUT_MS,
|
|
87
104
|
});
|
|
88
|
-
|
|
105
|
+
const commandLine = stdout.trim();
|
|
106
|
+
return commandLine.length === 0 ? undefined : commandLine;
|
|
89
107
|
}
|
|
90
108
|
catch {
|
|
91
109
|
return undefined;
|
|
@@ -95,18 +113,19 @@ function restoredLaunchCommandMatchesRecord(record, commandLine) {
|
|
|
95
113
|
return commandLine?.includes(`--user-data-dir=${record.userDataDir}`) === true;
|
|
96
114
|
}
|
|
97
115
|
async function getRestoredProcessVerificationError(record) {
|
|
98
|
-
const commandLine = await readPidCommandLine(record.pid);
|
|
99
|
-
if (
|
|
100
|
-
return `PID ${record.pid} is alive, but this session has no tracked child handle and its command line could not be inspected; refusing to signal a restored PID that may have been reused.`;
|
|
116
|
+
const commandLine = record.pid === undefined ? undefined : await readPidCommandLine(record.pid);
|
|
117
|
+
if (commandLine === undefined || commandLine.length === 0) {
|
|
118
|
+
return `PID ${String(record.pid)} is alive, but this session has no tracked child handle and its command line could not be inspected; refusing to signal a restored PID that may have been reused.`;
|
|
101
119
|
}
|
|
102
120
|
if (!restoredLaunchCommandMatchesRecord(record, commandLine)) {
|
|
103
|
-
return `PID ${record.pid} is alive, but this session has no tracked child handle and its command line does not include wrapper-owned user data dir ${record.userDataDir}; refusing to signal a restored PID that may have been reused.`;
|
|
121
|
+
return `PID ${String(record.pid)} is alive, but this session has no tracked child handle and its command line does not include wrapper-owned user data dir ${record.userDataDir}; refusing to signal a restored PID that may have been reused.`;
|
|
104
122
|
}
|
|
105
123
|
return undefined;
|
|
106
124
|
}
|
|
107
125
|
function killPid(pid, signal) {
|
|
108
|
-
if (
|
|
126
|
+
if (pid === undefined || !Number.isSafeInteger(pid) || pid <= 0) {
|
|
109
127
|
return false;
|
|
128
|
+
}
|
|
110
129
|
try {
|
|
111
130
|
process.kill(pid, signal);
|
|
112
131
|
return true;
|
|
@@ -116,8 +135,12 @@ function killPid(pid, signal) {
|
|
|
116
135
|
}
|
|
117
136
|
}
|
|
118
137
|
function killProcessGroup(processGroupId, signal) {
|
|
119
|
-
if (process.platform === "win32" ||
|
|
138
|
+
if (process.platform === "win32" ||
|
|
139
|
+
processGroupId === undefined ||
|
|
140
|
+
!Number.isSafeInteger(processGroupId) ||
|
|
141
|
+
processGroupId <= 0) {
|
|
120
142
|
return false;
|
|
143
|
+
}
|
|
121
144
|
try {
|
|
122
145
|
process.kill(-processGroupId, signal);
|
|
123
146
|
return true;
|
|
@@ -130,68 +153,118 @@ function signalRestoredLaunchProcess(record, signal) {
|
|
|
130
153
|
return killProcessGroup(record.processGroupId, signal) || killPid(record.pid, signal);
|
|
131
154
|
}
|
|
132
155
|
async function cleanupProcess(record, child, deadlineMs) {
|
|
133
|
-
if (
|
|
156
|
+
if (record.pid === undefined || record.pid === 0 || Number.isNaN(record.pid)) {
|
|
134
157
|
return { resource: "process", state: "skipped" };
|
|
135
|
-
|
|
158
|
+
}
|
|
159
|
+
if (hasProcessExited(child, record.pid)) {
|
|
136
160
|
return { resource: "process", state: "already-gone" };
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
161
|
+
}
|
|
162
|
+
return child === undefined
|
|
163
|
+
? cleanupRestoredProcess(record, deadlineMs)
|
|
164
|
+
: cleanupTrackedProcess(record, child, deadlineMs);
|
|
165
|
+
}
|
|
166
|
+
async function cleanupRestoredProcess(record, deadlineMs) {
|
|
167
|
+
const verificationError = await getRestoredProcessVerificationError(record);
|
|
168
|
+
if (verificationError !== undefined) {
|
|
169
|
+
return { error: verificationError, resource: "process", state: "failed" };
|
|
170
|
+
}
|
|
171
|
+
if (!signalRestoredLaunchProcess(record, "SIGTERM")) {
|
|
172
|
+
return {
|
|
173
|
+
error: `PID ${String(record.pid)} matched wrapper launch metadata but could not be signaled.`,
|
|
174
|
+
resource: "process",
|
|
175
|
+
state: "failed",
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
if (await waitForProcessExit(undefined, record.pid, deadlineMs)) {
|
|
179
|
+
return { resource: "process", state: "removed" };
|
|
180
|
+
}
|
|
181
|
+
signalRestoredLaunchProcess(record, "SIGKILL");
|
|
182
|
+
if (await waitForProcessExit(undefined, record.pid, Date.now() + 1_000)) {
|
|
183
|
+
return { resource: "process", state: "removed" };
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
error: `PID ${String(record.pid)} remained alive after SIGTERM/SIGKILL.`,
|
|
187
|
+
resource: "process",
|
|
188
|
+
state: "failed",
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
async function cleanupTrackedProcess(record, child, deadlineMs) {
|
|
192
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
152
193
|
child.kill("SIGTERM");
|
|
153
|
-
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
154
196
|
killPid(record.pid, "SIGTERM");
|
|
155
|
-
|
|
197
|
+
}
|
|
198
|
+
if (await waitForProcessExit(child, record.pid, deadlineMs)) {
|
|
156
199
|
return { resource: "process", state: "removed" };
|
|
157
|
-
|
|
200
|
+
}
|
|
201
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
158
202
|
child.kill("SIGKILL");
|
|
159
|
-
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
160
205
|
killPid(record.pid, "SIGKILL");
|
|
161
|
-
|
|
206
|
+
}
|
|
207
|
+
if (await waitForProcessExit(child, record.pid, Date.now() + 1_000)) {
|
|
162
208
|
return { resource: "process", state: "removed" };
|
|
163
|
-
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
error: `PID ${String(record.pid)} remained alive after SIGTERM/SIGKILL.`,
|
|
212
|
+
resource: "process",
|
|
213
|
+
state: "failed",
|
|
214
|
+
};
|
|
164
215
|
}
|
|
165
216
|
async function cleanupUserDataDir(record) {
|
|
166
|
-
if (
|
|
217
|
+
if (record.userDataDir.length === 0) {
|
|
167
218
|
return { resource: "user-data-dir", state: "skipped" };
|
|
168
|
-
|
|
219
|
+
}
|
|
220
|
+
if (!(await pathExists(record.userDataDir))) {
|
|
169
221
|
return { resource: "user-data-dir", state: "already-gone" };
|
|
222
|
+
}
|
|
170
223
|
const validationError = await getSecureTempChildDirectoryValidationError(record.userDataDir, ELECTRON_PROFILE_DIR_PREFIX);
|
|
171
|
-
if (validationError)
|
|
224
|
+
if (validationError !== undefined) {
|
|
172
225
|
return { error: validationError, resource: "user-data-dir", state: "failed" };
|
|
226
|
+
}
|
|
173
227
|
try {
|
|
174
228
|
await rm(record.userDataDir, { force: true, recursive: true });
|
|
175
|
-
return {
|
|
229
|
+
return {
|
|
230
|
+
resource: "user-data-dir",
|
|
231
|
+
state: (await pathExists(record.userDataDir)) ? "failed" : "removed",
|
|
232
|
+
};
|
|
176
233
|
}
|
|
177
234
|
catch (error) {
|
|
178
|
-
return {
|
|
235
|
+
return {
|
|
236
|
+
error: error instanceof Error ? error.message : stringifyUnknown(error),
|
|
237
|
+
resource: "user-data-dir",
|
|
238
|
+
state: "failed",
|
|
239
|
+
};
|
|
179
240
|
}
|
|
180
241
|
}
|
|
181
242
|
function shouldSkipUserDataDirCleanup(processStep, debugPortStep) {
|
|
182
|
-
if (processStep.state === "failed")
|
|
243
|
+
if (processStep.state === "failed") {
|
|
183
244
|
return `Skipped because process cleanup failed: ${processStep.error ?? "process state could not be verified"}.`;
|
|
184
|
-
|
|
245
|
+
}
|
|
246
|
+
if (debugPortStep.state === "failed") {
|
|
185
247
|
return `Skipped because debug port cleanup is incomplete: ${debugPortStep.error ?? "debug port still responds"}.`;
|
|
248
|
+
}
|
|
186
249
|
return undefined;
|
|
187
250
|
}
|
|
188
251
|
async function cleanupDebugPort(record) {
|
|
189
252
|
const cdp = await isPortAlive(record.port);
|
|
190
|
-
return cdp.version
|
|
253
|
+
return cdp.version
|
|
254
|
+
? {
|
|
255
|
+
resource: "debug-port",
|
|
256
|
+
state: "failed",
|
|
257
|
+
error: `/json/version still responds on port ${record.port}.`,
|
|
258
|
+
}
|
|
259
|
+
: { resource: "debug-port", state: "already-gone" };
|
|
191
260
|
}
|
|
192
261
|
function summarizeCleanup(launchId, steps) {
|
|
193
262
|
const remainingResources = steps
|
|
194
|
-
.filter((step) => step.state === "failed" ||
|
|
263
|
+
.filter((step) => step.state === "failed" ||
|
|
264
|
+
(step.resource === "user-data-dir" &&
|
|
265
|
+
step.state === "skipped" &&
|
|
266
|
+
step.error !== undefined &&
|
|
267
|
+
step.error.length > 0))
|
|
195
268
|
.map((step) => step.resource);
|
|
196
269
|
const partial = remainingResources.length > 0;
|
|
197
270
|
return {
|
|
@@ -203,15 +276,21 @@ function summarizeCleanup(launchId, steps) {
|
|
|
203
276
|
};
|
|
204
277
|
}
|
|
205
278
|
export async function cleanupElectronLaunchResources(options) {
|
|
206
|
-
const timeoutMs =
|
|
279
|
+
const timeoutMs = typeof options.timeoutMs === "number" &&
|
|
280
|
+
Number.isSafeInteger(options.timeoutMs) &&
|
|
281
|
+
options.timeoutMs > 0
|
|
207
282
|
? options.timeoutMs
|
|
208
283
|
: ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS;
|
|
209
284
|
const deadlineMs = Date.now() + timeoutMs;
|
|
210
285
|
const processStep = await cleanupProcess(options.record, options.child, deadlineMs);
|
|
211
286
|
const debugPortStep = await cleanupDebugPort(options.record);
|
|
212
287
|
const userDataDirSkipReason = shouldSkipUserDataDirCleanup(processStep, debugPortStep);
|
|
213
|
-
const userDataDirStep = userDataDirSkipReason
|
|
214
|
-
? {
|
|
288
|
+
const userDataDirStep = userDataDirSkipReason !== undefined
|
|
289
|
+
? {
|
|
290
|
+
error: userDataDirSkipReason,
|
|
291
|
+
resource: "user-data-dir",
|
|
292
|
+
state: "skipped",
|
|
293
|
+
}
|
|
215
294
|
: await cleanupUserDataDir(options.record);
|
|
216
295
|
const steps = [processStep, debugPortStep, userDataDirStep];
|
|
217
296
|
const summary = summarizeCleanup(options.record.launchId, steps);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { basename, join } from "node:path";
|
|
3
|
+
import { pathExists } from "../fs-utils.js";
|
|
4
|
+
import { hasElectronAppPayload, isDirectory } from "./discovery-evidence.js";
|
|
5
|
+
function readPlistString(plist, key) {
|
|
6
|
+
const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7
|
+
const match = new RegExp(`<key>\\s*${escapedKey}\\s*</key>\\s*<string>([\\s\\S]*?)</string>`, "i").exec(plist);
|
|
8
|
+
return match?.[1]
|
|
9
|
+
?.trim()
|
|
10
|
+
.replaceAll("&", "&")
|
|
11
|
+
.replaceAll("<", "<")
|
|
12
|
+
.replaceAll(">", ">")
|
|
13
|
+
.replaceAll(""", '"')
|
|
14
|
+
.replaceAll("'", "'");
|
|
15
|
+
}
|
|
16
|
+
async function readMacInfoPlist(appPath) {
|
|
17
|
+
try {
|
|
18
|
+
const plist = await readFile(join(appPath, "Contents", "Info.plist"), "utf8");
|
|
19
|
+
return {
|
|
20
|
+
CFBundleDisplayName: readPlistString(plist, "CFBundleDisplayName") ?? "",
|
|
21
|
+
CFBundleExecutable: readPlistString(plist, "CFBundleExecutable") ?? "",
|
|
22
|
+
CFBundleIdentifier: readPlistString(plist, "CFBundleIdentifier") ?? "",
|
|
23
|
+
CFBundleName: readPlistString(plist, "CFBundleName") ?? "",
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function resolveMacExecutablePath(appPath, executableName, fallbackName) {
|
|
31
|
+
const directory = join(appPath, "Contents", "MacOS");
|
|
32
|
+
if (executableName !== undefined && executableName.trim().length > 0) {
|
|
33
|
+
const path = join(directory, executableName);
|
|
34
|
+
return (await pathExists(path)) ? path : undefined;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
38
|
+
const candidate = entries.find((entry) => entry.isFile() && entry.name === fallbackName) ??
|
|
39
|
+
entries.find((entry) => entry.isFile());
|
|
40
|
+
return candidate ? join(directory, candidate.name) : undefined;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function firstNonempty(values) {
|
|
47
|
+
return values.find((value) => value !== undefined && value.length > 0);
|
|
48
|
+
}
|
|
49
|
+
export async function inspectDarwinApp(appPath) {
|
|
50
|
+
const framework = join(appPath, "Contents", "Frameworks", "Electron Framework.framework");
|
|
51
|
+
const hasFramework = await isDirectory(framework);
|
|
52
|
+
const hasPayload = await hasElectronAppPayload(join(appPath, "Contents", "Resources"));
|
|
53
|
+
if (!hasFramework || !hasPayload) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const info = await readMacInfoPlist(appPath);
|
|
57
|
+
const directoryName = basename(appPath, ".app");
|
|
58
|
+
const executablePath = await resolveMacExecutablePath(appPath, info.CFBundleExecutable, directoryName);
|
|
59
|
+
if (executablePath === undefined) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
appPath,
|
|
64
|
+
bundleId: firstNonempty([info.CFBundleIdentifier]),
|
|
65
|
+
executablePath,
|
|
66
|
+
name: firstNonempty([info.CFBundleDisplayName, info.CFBundleName]) ?? directoryName,
|
|
67
|
+
platform: "darwin",
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async function inspectDirectory(directory) {
|
|
71
|
+
let entries;
|
|
72
|
+
try {
|
|
73
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return { apps: [], skippedCount: 0 };
|
|
77
|
+
}
|
|
78
|
+
const apps = [];
|
|
79
|
+
let skippedCount = 0;
|
|
80
|
+
for (const entry of entries) {
|
|
81
|
+
if (!entry.name.endsWith(".app")) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
// Inspect in filesystem order and count failures without overlapping app reads.
|
|
86
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
87
|
+
const app = await inspectDarwinApp(join(directory, entry.name));
|
|
88
|
+
if (app) {
|
|
89
|
+
apps.push(app);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
skippedCount += 1;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return { apps, skippedCount };
|
|
97
|
+
}
|
|
98
|
+
export async function discoverDarwinApps(directories) {
|
|
99
|
+
const apps = [];
|
|
100
|
+
let skippedCount = 0;
|
|
101
|
+
for (const directory of directories) {
|
|
102
|
+
// Location priority is observable when duplicate bundles are discovered.
|
|
103
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
104
|
+
const scan = await inspectDirectory(directory);
|
|
105
|
+
apps.push(...scan.apps);
|
|
106
|
+
skippedCount += scan.skippedCount;
|
|
107
|
+
}
|
|
108
|
+
return { apps, skippedCount };
|
|
109
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
function unescapeDesktopValue(value) {
|
|
3
|
+
return value
|
|
4
|
+
.replace(/\\s/g, " ")
|
|
5
|
+
.replace(/\\n/g, "\n")
|
|
6
|
+
.replace(/\\r/g, "\r")
|
|
7
|
+
.replace(/\\t/g, "\t")
|
|
8
|
+
.replace(/\\\\/g, "\\");
|
|
9
|
+
}
|
|
10
|
+
function parseDesktopFields(text) {
|
|
11
|
+
const fields = new Map();
|
|
12
|
+
let inDesktopEntry = false;
|
|
13
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
14
|
+
const line = rawLine.trim();
|
|
15
|
+
if (line.length === 0 || line.startsWith("#")) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (line.startsWith("[") && line.endsWith("]")) {
|
|
19
|
+
inDesktopEntry = line === "[Desktop Entry]";
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const separator = line.indexOf("=");
|
|
23
|
+
if (inDesktopEntry && separator > 0) {
|
|
24
|
+
fields.set(line.slice(0, separator), unescapeDesktopValue(line.slice(separator + 1)));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return fields;
|
|
28
|
+
}
|
|
29
|
+
function nonempty(value) {
|
|
30
|
+
return value !== undefined && value.length > 0 ? value : undefined;
|
|
31
|
+
}
|
|
32
|
+
export function parseDesktopFile(text, filePath) {
|
|
33
|
+
const fields = parseDesktopFields(text);
|
|
34
|
+
if (fields.get("Type") !== "Application") {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
if (["NoDisplay", "Hidden"].some((key) => fields.get(key)?.trim().toLowerCase() === "true")) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const exec = nonempty(fields.get("Exec")?.trim());
|
|
41
|
+
if (exec === undefined) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
const desktopId = basename(filePath, ".desktop");
|
|
45
|
+
return {
|
|
46
|
+
comment: nonempty(fields.get("Comment")),
|
|
47
|
+
desktopId,
|
|
48
|
+
exec,
|
|
49
|
+
filePath,
|
|
50
|
+
icon: nonempty(fields.get("Icon")),
|
|
51
|
+
name: nonempty(fields.get("Name")) ?? desktopId,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function stripDesktopExecFieldCodes(exec) {
|
|
55
|
+
const placeholder = "\u0000PERCENT\u0000";
|
|
56
|
+
return exec
|
|
57
|
+
.replaceAll("%%", placeholder)
|
|
58
|
+
.replace(/%[A-Za-z]/g, "")
|
|
59
|
+
.replaceAll(placeholder, "%");
|
|
60
|
+
}
|
|
61
|
+
class DesktopExecWords {
|
|
62
|
+
tokens = [];
|
|
63
|
+
current = "";
|
|
64
|
+
quote;
|
|
65
|
+
escaped = false;
|
|
66
|
+
parse(exec) {
|
|
67
|
+
for (const char of stripDesktopExecFieldCodes(exec)) {
|
|
68
|
+
this.accept(char);
|
|
69
|
+
}
|
|
70
|
+
if (this.escaped) {
|
|
71
|
+
this.current += "\\";
|
|
72
|
+
}
|
|
73
|
+
this.flush();
|
|
74
|
+
return this.tokens;
|
|
75
|
+
}
|
|
76
|
+
flush() {
|
|
77
|
+
if (this.current.length > 0) {
|
|
78
|
+
this.tokens.push(this.current);
|
|
79
|
+
this.current = "";
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
accept(char) {
|
|
83
|
+
if (this.escaped) {
|
|
84
|
+
this.current += char;
|
|
85
|
+
this.escaped = false;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (char === "\\") {
|
|
89
|
+
this.escaped = true;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (this.quote !== undefined) {
|
|
93
|
+
if (char === this.quote) {
|
|
94
|
+
this.quote = undefined;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.current += char;
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (char === '"' || char === "'") {
|
|
102
|
+
this.quote = char;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (/\s/.test(char)) {
|
|
106
|
+
this.flush();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
this.current += char;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export function tokenizeDesktopExec(exec) {
|
|
113
|
+
return new DesktopExecWords().parse(exec);
|
|
114
|
+
}
|
|
115
|
+
function envOptionWidth(token) {
|
|
116
|
+
return ["-u", "--unset", "--chdir"].includes(token) ? 2 : 1;
|
|
117
|
+
}
|
|
118
|
+
export function stripEnvLauncher(tokens) {
|
|
119
|
+
if (tokens.length === 0 || basename(tokens[0] ?? "") !== "env") {
|
|
120
|
+
return tokens;
|
|
121
|
+
}
|
|
122
|
+
let index = 1;
|
|
123
|
+
while (index < tokens.length) {
|
|
124
|
+
const token = tokens[index] ?? "";
|
|
125
|
+
if (token.startsWith("-")) {
|
|
126
|
+
index += envOptionWidth(token);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*=.*/.test(token)) {
|
|
130
|
+
index += 1;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
return tokens.slice(index);
|
|
136
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { constants as fsConstants } from "node:fs";
|
|
2
|
+
import { access, readdir, realpath, stat } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, extname, join } from "node:path";
|
|
4
|
+
import { pathExists } from "../fs-utils.js";
|
|
5
|
+
export async function isDirectory(path) {
|
|
6
|
+
try {
|
|
7
|
+
return (await stat(path)).isDirectory();
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function isFile(path) {
|
|
14
|
+
try {
|
|
15
|
+
return (await stat(path)).isFile();
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export async function isExecutableFile(path) {
|
|
22
|
+
try {
|
|
23
|
+
if (!(await stat(path)).isFile()) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
await access(path, fsConstants.X_OK);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export async function resolveRealPath(path) {
|
|
34
|
+
try {
|
|
35
|
+
return await realpath(path);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return path;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export async function directoryContainsChromePak(directory) {
|
|
42
|
+
try {
|
|
43
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
44
|
+
return entries.some((entry) => entry.isFile() && /^chrome_.*\.pak$/i.test(entry.name));
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function hasElectronAppPayload(resourcesDirectory) {
|
|
51
|
+
return ((await pathExists(join(resourcesDirectory, "app.asar"))) ||
|
|
52
|
+
(await isDirectory(join(resourcesDirectory, "app"))));
|
|
53
|
+
}
|
|
54
|
+
export async function hasLinuxElectronEvidence(executablePath) {
|
|
55
|
+
const resolved = await resolveRealPath(executablePath);
|
|
56
|
+
if (!(await isExecutableFile(resolved))) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const directory = dirname(resolved);
|
|
60
|
+
if (!(await directoryContainsChromePak(directory))) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
for (const base of [directory, dirname(directory)]) {
|
|
64
|
+
// Ordered evidence checks avoid unnecessary filesystem work after the first match.
|
|
65
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
66
|
+
if (await hasElectronAppPayload(join(base, "resources"))) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
export async function inspectWin32Executable(executablePath) {
|
|
73
|
+
const resolved = await resolveRealPath(executablePath);
|
|
74
|
+
if (!(await isExecutableFile(resolved))) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
const directory = dirname(resolved);
|
|
78
|
+
const hasAppPayload = await hasElectronAppPayload(join(directory, "resources"));
|
|
79
|
+
const hasPak = (await directoryContainsChromePak(directory)) ||
|
|
80
|
+
(await pathExists(join(directory, "resources.pak")));
|
|
81
|
+
if (!hasAppPayload || !hasPak) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
executablePath: resolved,
|
|
86
|
+
name: basename(resolved, extname(resolved)),
|
|
87
|
+
platform: "win32",
|
|
88
|
+
};
|
|
89
|
+
}
|