pi-agent-browser-native 0.9.3 → 0.9.5
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 +106 -5
- package/README.md +58 -791
- package/dist/extensions/agent-browser/index.js +43101 -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 +231 -0
- package/dist/extensions/agent-browser/lib/config.js +20 -8
- package/dist/extensions/agent-browser/lib/electron/cdp.js +20 -8
- package/dist/extensions/agent-browser/lib/electron/cleanup.js +128 -83
- 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 +90 -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 +261 -355
- 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/fs-utils.js +1 -9
- package/dist/extensions/agent-browser/lib/input-modes/electron.js +162 -121
- package/dist/extensions/agent-browser/lib/input-modes/job.js +123 -317
- package/dist/extensions/agent-browser/lib/input-modes/lookup-network-evidence.js +116 -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 +58 -412
- package/dist/extensions/agent-browser/lib/input-modes/params.js +86 -40
- 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 +203 -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 +187 -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 +147 -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 +212 -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 +169 -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 +93 -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 +68 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-data.js +169 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-presentation.js +182 -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 +167 -0
- package/dist/extensions/agent-browser/lib/orchestration/execution-queue.js +22 -10
- 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 +109 -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 +81 -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 +211 -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 +193 -0
- package/dist/extensions/agent-browser/lib/web-search-request.js +102 -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 +124 -614
- 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 +19 -6
- package/docs/CODE_QUALITY.md +267 -0
- package/docs/COMMAND_REFERENCE.md +272 -241
- package/docs/ELECTRON.md +77 -46
- package/docs/REFERENCE.md +869 -0
- package/docs/RELEASE.md +25 -22
- package/docs/REQUIREMENTS.md +2 -1
- package/docs/SUPPORT_MATRIX.md +81 -79
- package/docs/TOOL_CONTRACT.md +158 -125
- package/docs/platform-smoke.md +8 -8
- package/package.json +144 -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 +235 -132
- package/scripts/convert-browser-session.mjs +30 -9
- package/scripts/doctor-sources.mjs +195 -0
- package/scripts/doctor.mjs +94 -249
- 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 +132 -0
- package/scripts/platform-smoke/linux-image/Dockerfile +8 -2
- package/scripts/platform-smoke/suite-checks.mjs +98 -0
- package/scripts/platform-smoke/suite-evidence.mjs +281 -0
- package/scripts/platform-smoke/targets.mjs +154 -472
- package/scripts/platform-smoke.mjs +55 -40
- package/scripts/prepare.mjs +16 -7
|
@@ -1,34 +1,35 @@
|
|
|
1
|
-
import { execFile } from "node:child_process";
|
|
2
1
|
import { lstat, rm } from "node:fs/promises";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { fetchCdpJson, parseCdpTargets, parseCdpVersion } from "./cdp.js";
|
|
6
|
-
import { ELECTRON_PROFILE_DIR_PREFIX } from "./launch.js";
|
|
2
|
+
import { fetchCdpJson, parseCdpTargets, parseCdpVersion, } from "./cdp.js";
|
|
3
|
+
import { ELECTRON_PROFILE_DIR_PREFIX } from "./launch-types.js";
|
|
7
4
|
import { pathExists } from "../fs-utils.js";
|
|
5
|
+
import { isRecord } from "../parsing.js";
|
|
6
|
+
import { readProcessStartIdentity, processStartIdentitiesMatch } from "../process-identity.js";
|
|
7
|
+
import { stringifyUnknown } from "../results/text.js";
|
|
8
8
|
import { getSecureTempChildDirectoryValidationError } from "../temp.js";
|
|
9
9
|
const ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS = 5_000;
|
|
10
10
|
const ELECTRON_CLEANUP_POLL_INTERVAL_MS = 100;
|
|
11
|
-
const RESTORED_PROCESS_COMMAND_TIMEOUT_MS = 1_000;
|
|
12
|
-
const execFileAsync = promisify(execFile);
|
|
13
11
|
function sleep(ms) {
|
|
14
|
-
return new Promise((resolve) =>
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
setTimeout(resolve, ms);
|
|
14
|
+
});
|
|
15
15
|
}
|
|
16
16
|
function isPidAlive(pid) {
|
|
17
|
-
if (
|
|
17
|
+
if (pid === undefined || !Number.isSafeInteger(pid) || pid <= 0) {
|
|
18
18
|
return undefined;
|
|
19
|
+
}
|
|
19
20
|
try {
|
|
20
21
|
process.kill(pid, 0);
|
|
21
22
|
return true;
|
|
22
23
|
}
|
|
23
24
|
catch (error) {
|
|
24
|
-
|
|
25
|
-
return code === "EPERM" ? true : false;
|
|
25
|
+
return isRecord(error) && error.code === "EPERM";
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
async function isPortAlive(port, signal) {
|
|
29
29
|
const version = parseCdpVersion(await fetchCdpJson(`http://127.0.0.1:${port}/json/version`, signal));
|
|
30
|
-
if (!version)
|
|
30
|
+
if (!version) {
|
|
31
31
|
return { targets: [] };
|
|
32
|
+
}
|
|
32
33
|
const targets = parseCdpTargets(await fetchCdpJson(`http://127.0.0.1:${port}/json/list`, signal));
|
|
33
34
|
return { targets, version };
|
|
34
35
|
}
|
|
@@ -40,7 +41,7 @@ export async function inspectElectronLaunchStatus(record, signal) {
|
|
|
40
41
|
userDataDirState = "present";
|
|
41
42
|
}
|
|
42
43
|
catch (error) {
|
|
43
|
-
userDataDirState = error.code === "ENOENT" ? "absent" : "unknown";
|
|
44
|
+
userDataDirState = isRecord(error) && error.code === "ENOENT" ? "absent" : "unknown";
|
|
44
45
|
}
|
|
45
46
|
return {
|
|
46
47
|
cleanupState: record.cleanupState,
|
|
@@ -61,52 +62,32 @@ function hasProcessExited(child, pid) {
|
|
|
61
62
|
}
|
|
62
63
|
async function waitForProcessExit(child, pid, deadlineMs) {
|
|
63
64
|
while (Date.now() <= deadlineMs) {
|
|
64
|
-
if (hasProcessExited(child, pid))
|
|
65
|
+
if (hasProcessExited(child, pid)) {
|
|
65
66
|
return true;
|
|
67
|
+
}
|
|
68
|
+
// Polling observes exit between sleeps; parallel waits cannot preserve the deadline.
|
|
69
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
66
70
|
await sleep(ELECTRON_CLEANUP_POLL_INTERVAL_MS);
|
|
67
71
|
}
|
|
68
72
|
return hasProcessExited(child, pid);
|
|
69
73
|
}
|
|
70
|
-
async function readPidCommandLine(pid) {
|
|
71
|
-
if (!pid || !Number.isSafeInteger(pid) || pid <= 0)
|
|
72
|
-
return undefined;
|
|
73
|
-
try {
|
|
74
|
-
// Win32_Process.CommandLine is the native ownership evidence; process
|
|
75
|
-
// start time (used by daemon-policy locks) cannot prove profile ownership.
|
|
76
|
-
const systemRoot = process.env.SystemRoot;
|
|
77
|
-
const windowsRoot = systemRoot && win32.isAbsolute(systemRoot) ? systemRoot : "C:\\Windows";
|
|
78
|
-
const file = process.platform === "win32"
|
|
79
|
-
? win32.join(windowsRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
|
80
|
-
: "ps";
|
|
81
|
-
const args = process.platform === "win32"
|
|
82
|
-
? ["-NoProfile", "-NonInteractive", "-Command",
|
|
83
|
-
`[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new(); $p = [wmi]"Win32_Process.Handle='${pid}'"; [Console]::WriteLine($p.CommandLine)`]
|
|
84
|
-
: ["-ww", "-p", String(pid), "-o", "command="];
|
|
85
|
-
const { stdout } = await execFileAsync(file, args, {
|
|
86
|
-
timeout: RESTORED_PROCESS_COMMAND_TIMEOUT_MS,
|
|
87
|
-
});
|
|
88
|
-
return stdout.trim() || undefined;
|
|
89
|
-
}
|
|
90
|
-
catch {
|
|
91
|
-
return undefined;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
function restoredLaunchCommandMatchesRecord(record, commandLine) {
|
|
95
|
-
return commandLine?.includes(`--user-data-dir=${record.userDataDir}`) === true;
|
|
96
|
-
}
|
|
97
74
|
async function getRestoredProcessVerificationError(record) {
|
|
98
|
-
|
|
99
|
-
|
|
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.`;
|
|
75
|
+
if (record.startIdentity === undefined || record.startIdentity.length === 0) {
|
|
76
|
+
return `PID ${String(record.pid)} is alive, but this session has no tracked child handle or recorded start identity; refusing to signal a restored PID that may have been reused.`;
|
|
101
77
|
}
|
|
102
|
-
|
|
103
|
-
|
|
78
|
+
const currentIdentity = record.pid === undefined ? undefined : await readProcessStartIdentity(record.pid);
|
|
79
|
+
if (currentIdentity === undefined) {
|
|
80
|
+
return `PID ${String(record.pid)} is alive, but its current start identity could not be inspected; refusing to signal a restored PID that may have been reused.`;
|
|
81
|
+
}
|
|
82
|
+
if (!processStartIdentitiesMatch(record.startIdentity, currentIdentity)) {
|
|
83
|
+
return `PID ${String(record.pid)} is alive, but its start identity does not match the wrapper launch record; refusing to signal a restored PID that may have been reused.`;
|
|
104
84
|
}
|
|
105
85
|
return undefined;
|
|
106
86
|
}
|
|
107
87
|
function killPid(pid, signal) {
|
|
108
|
-
if (
|
|
88
|
+
if (pid === undefined || !Number.isSafeInteger(pid) || pid <= 0) {
|
|
109
89
|
return false;
|
|
90
|
+
}
|
|
110
91
|
try {
|
|
111
92
|
process.kill(pid, signal);
|
|
112
93
|
return true;
|
|
@@ -116,8 +97,12 @@ function killPid(pid, signal) {
|
|
|
116
97
|
}
|
|
117
98
|
}
|
|
118
99
|
function killProcessGroup(processGroupId, signal) {
|
|
119
|
-
if (process.platform === "win32" ||
|
|
100
|
+
if (process.platform === "win32" ||
|
|
101
|
+
processGroupId === undefined ||
|
|
102
|
+
!Number.isSafeInteger(processGroupId) ||
|
|
103
|
+
processGroupId <= 0) {
|
|
120
104
|
return false;
|
|
105
|
+
}
|
|
121
106
|
try {
|
|
122
107
|
process.kill(-processGroupId, signal);
|
|
123
108
|
return true;
|
|
@@ -130,68 +115,122 @@ function signalRestoredLaunchProcess(record, signal) {
|
|
|
130
115
|
return killProcessGroup(record.processGroupId, signal) || killPid(record.pid, signal);
|
|
131
116
|
}
|
|
132
117
|
async function cleanupProcess(record, child, deadlineMs) {
|
|
133
|
-
if (
|
|
118
|
+
if (record.pid === undefined || record.pid === 0 || Number.isNaN(record.pid)) {
|
|
134
119
|
return { resource: "process", state: "skipped" };
|
|
135
|
-
|
|
120
|
+
}
|
|
121
|
+
if (hasProcessExited(child, record.pid)) {
|
|
136
122
|
return { resource: "process", state: "already-gone" };
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
123
|
+
}
|
|
124
|
+
return child === undefined
|
|
125
|
+
? cleanupRestoredProcess(record, deadlineMs)
|
|
126
|
+
: cleanupTrackedProcess(record, child, deadlineMs);
|
|
127
|
+
}
|
|
128
|
+
async function cleanupRestoredProcess(record, deadlineMs) {
|
|
129
|
+
const verificationError = await getRestoredProcessVerificationError(record);
|
|
130
|
+
if (verificationError !== undefined) {
|
|
131
|
+
return { error: verificationError, resource: "process", state: "failed" };
|
|
132
|
+
}
|
|
133
|
+
if (!signalRestoredLaunchProcess(record, "SIGTERM")) {
|
|
134
|
+
return {
|
|
135
|
+
error: `PID ${String(record.pid)} matched wrapper launch metadata but could not be signaled.`,
|
|
136
|
+
resource: "process",
|
|
137
|
+
state: "failed",
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (await waitForProcessExit(undefined, record.pid, deadlineMs)) {
|
|
141
|
+
return { resource: "process", state: "removed" };
|
|
142
|
+
}
|
|
143
|
+
const killVerificationError = await getRestoredProcessVerificationError(record);
|
|
144
|
+
if (killVerificationError !== undefined) {
|
|
145
|
+
return { error: killVerificationError, resource: "process", state: "failed" };
|
|
146
|
+
}
|
|
147
|
+
signalRestoredLaunchProcess(record, "SIGKILL");
|
|
148
|
+
if (await waitForProcessExit(undefined, record.pid, Date.now() + 1_000)) {
|
|
149
|
+
return { resource: "process", state: "removed" };
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
error: `PID ${String(record.pid)} remained alive after SIGTERM/SIGKILL.`,
|
|
153
|
+
resource: "process",
|
|
154
|
+
state: "failed",
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
async function cleanupTrackedProcess(record, child, deadlineMs) {
|
|
158
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
152
159
|
child.kill("SIGTERM");
|
|
153
|
-
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
154
162
|
killPid(record.pid, "SIGTERM");
|
|
155
|
-
|
|
163
|
+
}
|
|
164
|
+
if (await waitForProcessExit(child, record.pid, deadlineMs)) {
|
|
156
165
|
return { resource: "process", state: "removed" };
|
|
157
|
-
|
|
166
|
+
}
|
|
167
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
158
168
|
child.kill("SIGKILL");
|
|
159
|
-
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
160
171
|
killPid(record.pid, "SIGKILL");
|
|
161
|
-
|
|
172
|
+
}
|
|
173
|
+
if (await waitForProcessExit(child, record.pid, Date.now() + 1_000)) {
|
|
162
174
|
return { resource: "process", state: "removed" };
|
|
163
|
-
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
error: `PID ${String(record.pid)} remained alive after SIGTERM/SIGKILL.`,
|
|
178
|
+
resource: "process",
|
|
179
|
+
state: "failed",
|
|
180
|
+
};
|
|
164
181
|
}
|
|
165
182
|
async function cleanupUserDataDir(record) {
|
|
166
|
-
if (
|
|
183
|
+
if (record.userDataDir.length === 0) {
|
|
167
184
|
return { resource: "user-data-dir", state: "skipped" };
|
|
168
|
-
|
|
185
|
+
}
|
|
186
|
+
if (!(await pathExists(record.userDataDir))) {
|
|
169
187
|
return { resource: "user-data-dir", state: "already-gone" };
|
|
188
|
+
}
|
|
170
189
|
const validationError = await getSecureTempChildDirectoryValidationError(record.userDataDir, ELECTRON_PROFILE_DIR_PREFIX);
|
|
171
|
-
if (validationError)
|
|
190
|
+
if (validationError !== undefined) {
|
|
172
191
|
return { error: validationError, resource: "user-data-dir", state: "failed" };
|
|
192
|
+
}
|
|
173
193
|
try {
|
|
174
194
|
await rm(record.userDataDir, { force: true, recursive: true });
|
|
175
|
-
return {
|
|
195
|
+
return {
|
|
196
|
+
resource: "user-data-dir",
|
|
197
|
+
state: (await pathExists(record.userDataDir)) ? "failed" : "removed",
|
|
198
|
+
};
|
|
176
199
|
}
|
|
177
200
|
catch (error) {
|
|
178
|
-
return {
|
|
201
|
+
return {
|
|
202
|
+
error: error instanceof Error ? error.message : stringifyUnknown(error),
|
|
203
|
+
resource: "user-data-dir",
|
|
204
|
+
state: "failed",
|
|
205
|
+
};
|
|
179
206
|
}
|
|
180
207
|
}
|
|
181
208
|
function shouldSkipUserDataDirCleanup(processStep, debugPortStep) {
|
|
182
|
-
if (processStep.state === "failed")
|
|
209
|
+
if (processStep.state === "failed") {
|
|
183
210
|
return `Skipped because process cleanup failed: ${processStep.error ?? "process state could not be verified"}.`;
|
|
184
|
-
|
|
211
|
+
}
|
|
212
|
+
if (debugPortStep.state === "failed") {
|
|
185
213
|
return `Skipped because debug port cleanup is incomplete: ${debugPortStep.error ?? "debug port still responds"}.`;
|
|
214
|
+
}
|
|
186
215
|
return undefined;
|
|
187
216
|
}
|
|
188
217
|
async function cleanupDebugPort(record) {
|
|
189
218
|
const cdp = await isPortAlive(record.port);
|
|
190
|
-
return cdp.version
|
|
219
|
+
return cdp.version
|
|
220
|
+
? {
|
|
221
|
+
resource: "debug-port",
|
|
222
|
+
state: "failed",
|
|
223
|
+
error: `/json/version still responds on port ${record.port}.`,
|
|
224
|
+
}
|
|
225
|
+
: { resource: "debug-port", state: "already-gone" };
|
|
191
226
|
}
|
|
192
227
|
function summarizeCleanup(launchId, steps) {
|
|
193
228
|
const remainingResources = steps
|
|
194
|
-
.filter((step) => step.state === "failed" ||
|
|
229
|
+
.filter((step) => step.state === "failed" ||
|
|
230
|
+
(step.resource === "user-data-dir" &&
|
|
231
|
+
step.state === "skipped" &&
|
|
232
|
+
step.error !== undefined &&
|
|
233
|
+
step.error.length > 0))
|
|
195
234
|
.map((step) => step.resource);
|
|
196
235
|
const partial = remainingResources.length > 0;
|
|
197
236
|
return {
|
|
@@ -203,15 +242,21 @@ function summarizeCleanup(launchId, steps) {
|
|
|
203
242
|
};
|
|
204
243
|
}
|
|
205
244
|
export async function cleanupElectronLaunchResources(options) {
|
|
206
|
-
const timeoutMs =
|
|
245
|
+
const timeoutMs = typeof options.timeoutMs === "number" &&
|
|
246
|
+
Number.isSafeInteger(options.timeoutMs) &&
|
|
247
|
+
options.timeoutMs > 0
|
|
207
248
|
? options.timeoutMs
|
|
208
249
|
: ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS;
|
|
209
250
|
const deadlineMs = Date.now() + timeoutMs;
|
|
210
251
|
const processStep = await cleanupProcess(options.record, options.child, deadlineMs);
|
|
211
252
|
const debugPortStep = await cleanupDebugPort(options.record);
|
|
212
253
|
const userDataDirSkipReason = shouldSkipUserDataDirCleanup(processStep, debugPortStep);
|
|
213
|
-
const userDataDirStep = userDataDirSkipReason
|
|
214
|
-
? {
|
|
254
|
+
const userDataDirStep = userDataDirSkipReason !== undefined
|
|
255
|
+
? {
|
|
256
|
+
error: userDataDirSkipReason,
|
|
257
|
+
resource: "user-data-dir",
|
|
258
|
+
state: "skipped",
|
|
259
|
+
}
|
|
215
260
|
: await cleanupUserDataDir(options.record);
|
|
216
261
|
const steps = [processStep, debugPortStep, userDataDirStep];
|
|
217
262
|
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,90 @@
|
|
|
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 pathExists(join(resourcesDirectory, "default_app.asar"))) ||
|
|
53
|
+
(await isDirectory(join(resourcesDirectory, "app"))));
|
|
54
|
+
}
|
|
55
|
+
export async function hasLinuxElectronEvidence(executablePath) {
|
|
56
|
+
const resolved = await resolveRealPath(executablePath);
|
|
57
|
+
if (!(await isExecutableFile(resolved))) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
const directory = dirname(resolved);
|
|
61
|
+
if (!(await directoryContainsChromePak(directory))) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
for (const base of [directory, dirname(directory)]) {
|
|
65
|
+
// Ordered evidence checks avoid unnecessary filesystem work after the first match.
|
|
66
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
67
|
+
if (await hasElectronAppPayload(join(base, "resources"))) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
export async function inspectWin32Executable(executablePath) {
|
|
74
|
+
const resolved = await resolveRealPath(executablePath);
|
|
75
|
+
if (!(await isExecutableFile(resolved))) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
const directory = dirname(resolved);
|
|
79
|
+
const hasAppPayload = await hasElectronAppPayload(join(directory, "resources"));
|
|
80
|
+
const hasPak = (await directoryContainsChromePak(directory)) ||
|
|
81
|
+
(await pathExists(join(directory, "resources.pak")));
|
|
82
|
+
if (!hasAppPayload || !hasPak) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
executablePath: resolved,
|
|
87
|
+
name: basename(resolved, extname(resolved)),
|
|
88
|
+
platform: "win32",
|
|
89
|
+
};
|
|
90
|
+
}
|