@moretea-labs/forge 1.5.1 → 1.7.0
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/AGENTS.md +2 -0
- package/CHANGELOG.md +46 -0
- package/CLAUDE.md +2 -0
- package/DESIGN.md +7 -2
- package/README.md +4 -4
- package/README.zh-CN.md +2 -2
- package/SKILL.md +2 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/agents/openai.yaml +1 -1
- package/assets/hooks/hook-input.sh +11 -8
- package/assets/hooks/lib/session-state.sh +10 -7
- package/assets/hooks/lib/workflow-state.sh +13 -177
- package/assets/hooks/post-tool-observer.sh +8 -2
- package/assets/hooks/pre-edit-guard.sh +8 -39
- package/assets/hooks/prompt-guard.sh +7 -83
- package/assets/hooks/session-start-context.sh +56 -1
- package/assets/partials/05-workflow.partial.md +1 -1
- package/assets/partials-agents/03-orchestration.partial.md +1 -1
- package/assets/plugin-registry.v1.json +54 -3
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/harness-overview.md +1 -1
- package/assets/reference-configs/hook-operations.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +3 -3
- package/assets/skill-version.json +2 -2
- package/assets/templates/contract.template.md +2 -7
- package/assets/templates/helpers/capture-plan.sh +2 -2
- package/assets/templates/helpers/check-task-workflow.sh +4 -4
- package/assets/templates/helpers/contract-worktree.sh +1 -21
- package/assets/templates/helpers/ensure-task-workflow.sh +13 -38
- package/assets/templates/helpers/migrate-project-template.sh +22 -45
- package/assets/templates/helpers/new-plan.sh +1 -1
- package/assets/templates/helpers/plan-to-todo.sh +12 -37
- package/assets/templates/helpers/ship-worktrees.sh +2 -29
- package/assets/templates/helpers/sprint-backlog.sh +6 -6
- package/assets/templates/helpers/verify-contract.sh +1 -111
- package/assets/templates/helpers/verify-sprint.sh +3 -180
- package/assets/templates/plan.template.md +1 -1
- package/assets/templates/review.template.md +9 -34
- package/assets/workflow-contract.v1.json +10 -19
- package/docs/README.md +10 -10
- package/docs/architecture/CURRENT.md +170 -0
- package/docs/architecture/EVOLUTION.md +42 -0
- package/docs/architecture/current/README.md +4 -156
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
- package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
- package/docs/architecture/history/README.md +7 -0
- package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
- package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
- package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
- package/docs/architecture/history.md +3 -34
- package/docs/architecture/index.md +15 -98
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
- package/docs/architecture/versions/1.6.md +38 -0
- package/docs/architecture/versions/1.7.md +41 -0
- package/docs/forge-chatgpt-browser-engine.md +2 -2
- package/docs/forge-chatgpt-mcp-setup.md +4 -28
- package/docs/forge-chatgpt-supervised-automation.md +3 -3
- package/docs/forge-github-issue-launcher.md +1 -1
- package/docs/forge-runtime-self-healing-loop.md +1 -1
- package/docs/operations/controller-browser-plugin.md +38 -22
- package/docs/operations/controller-performance-and-502.md +124 -0
- package/docs/operations/controller-reliability-runbook.md +1 -1
- package/docs/operations/features.md +3 -3
- package/docs/operations/github-repository.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +5 -3
- package/docs/tutorials/01-install-and-start.md +1 -1
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/wiki/Architecture.md +6 -6
- package/docs/wiki/Implementation.md +2 -2
- package/docs/wiki/Installation.md +1 -1
- package/docs/wiki/Integrations.md +2 -2
- package/docs/wiki/Quick-Start.md +1 -1
- package/docs/wiki/Work-Lifecycle.md +1 -1
- package/package.json +29 -10
- package/scripts/activate-source-baseline.ts +17 -13
- package/scripts/benchmark-background-check-overlap.ts +228 -0
- package/scripts/benchmark-mcp-host.sh +117 -0
- package/scripts/benchmark-mcp-transport.ts +170 -0
- package/scripts/benchmark-quality-harness.ts +146 -0
- package/scripts/benchmark-route-session-concurrency.ts +207 -6
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
- package/scripts/benchmark-typescript-navigation.ts +186 -0
- package/scripts/benchmark-work-efficiency.ts +334 -0
- package/scripts/capture-plan.sh +3 -3
- package/scripts/check-agent-tooling.sh +8 -35
- package/scripts/check-architecture-sync.sh +17 -86
- package/scripts/check-mcp-compatibility.ts +14 -0
- package/scripts/check-public-docs.sh +14 -1
- package/scripts/check-runtime-architecture.mjs +107 -64
- package/scripts/check-stable-baseline.ts +92 -0
- package/scripts/check-task-workflow.sh +4 -4
- package/scripts/contract-worktree.sh +1 -21
- package/scripts/ensure-task-workflow.sh +22 -55
- package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
- package/scripts/install-standalone-recovery.ts +24 -0
- package/scripts/lib/project-init-lib.sh +15 -44
- package/scripts/migrate-chatgpt-automation-schedules.ts +64 -0
- package/scripts/migrate-project-template.sh +23 -1179
- package/scripts/new-plan.sh +1 -1
- package/scripts/plan-to-todo.sh +11 -36
- package/scripts/run-governed-gate.ts +2 -1
- package/scripts/ship-worktrees.sh +2 -29
- package/scripts/smoke-ios-physical-device.ts +4 -2
- package/scripts/smoke-runtime-recovery.ts +1 -35
- package/scripts/smoke-schedule-engine.ts +1 -20
- package/scripts/sprint-backlog.sh +1 -1
- package/scripts/verify-contract.sh +1 -111
- package/scripts/verify-forge-runtime.sh +0 -1
- package/scripts/verify-sprint.sh +3 -180
- package/scripts/workflow-contract.ts +1 -5
- package/src/cli/commands/chatgpt.ts +31 -2
- package/src/cli/commands/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +37 -10
- package/src/cli/commands/recovery.ts +25 -3
- package/src/cli/commands/runtime.ts +55 -3
- package/src/cli/commands/security.ts +12 -1
- package/src/cli/commands/setup-profile.ts +31 -21
- package/src/cli/controller/check-runner.ts +106 -3
- package/src/cli/controller/composite-result.ts +1 -1
- package/src/cli/controller/context/focus.ts +51 -0
- package/src/cli/controller/context/instruction-context.ts +114 -0
- package/src/cli/controller/context/known-paths.ts +76 -0
- package/src/cli/controller/context/query-planning.ts +110 -0
- package/src/cli/controller/context/rule-resolution.ts +532 -0
- package/src/cli/controller/context/source-materializer.ts +278 -0
- package/src/cli/controller/context/structural.ts +16 -0
- package/src/cli/controller/context/types.ts +286 -0
- package/src/cli/controller/context-pack.ts +898 -430
- package/src/cli/controller/launch-agents.ts +77 -2
- package/src/cli/controller/operational-plan.ts +2 -2
- package/src/cli/controller/work-mode.ts +6 -4
- package/src/cli/editing/edit-session.ts +60 -7
- package/src/cli/github/github.ts +133 -0
- package/src/cli/hook/prompt-guard-decision.ts +17 -18
- package/src/cli/hook/prompt-intents.ts +1 -1
- package/src/cli/installer/managed-entries.ts +15 -1
- package/src/cli/local-bridge/console-automations.ts +225 -67
- package/src/cli/local-bridge/console-view-models.ts +3 -35
- package/src/cli/local-bridge/facade-api.ts +2 -217
- package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +153 -3
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +183 -3
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/lib/api.ts +18 -11
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/styles.css +27 -11
- package/src/cli/local-bridge/frontend/src/types.ts +8 -7
- package/src/cli/local-bridge/job-store.ts +1 -490
- package/src/cli/local-bridge/server.ts +29 -532
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +5101 -4967
- package/src/cli/mcp/auth.ts +5 -5
- package/src/cli/mcp/instructions.ts +3 -2
- package/src/cli/mcp/legacy-tool-service.ts +0 -189
- package/src/cli/mcp/multi-repository.ts +16 -5
- package/src/cli/mcp/oauth.ts +175 -26
- package/src/cli/mcp/paths.ts +8 -2
- package/src/cli/mcp/repository-tools.ts +356 -101
- package/src/cli/mcp/server.ts +625 -54
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/toolset-selection.ts +1 -1
- package/src/cli/mcp/toolset.ts +42 -5
- package/src/cli/mcp/transports/http.ts +125 -15
- package/src/cli/mcp/transports/session-registry.ts +67 -5
- package/src/cli/mcp/types.ts +3 -3
- package/src/cli/repositories/command-classifier.ts +209 -14
- package/src/cli/repositories/command-executor.ts +55 -521
- package/src/cli/repositories/command-process.ts +108 -0
- package/src/cli/repositories/command-scope.ts +99 -41
- package/src/cli/repositories/controller-home.ts +7 -8
- package/src/cli/repositories/git-command-executor.ts +2 -0
- package/src/cli/repositories/locks.ts +53 -16
- package/src/cli/repositories/repository-snapshot.ts +121 -0
- package/src/cli/repositories/safe-patch.ts +6 -4
- package/src/cli/repositories/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +110 -10
- package/src/cli/repository/inspector.ts +565 -62
- package/src/cli/repository/session-cache.ts +58 -17
- package/src/cli/v81-entry.ts +1 -4
- package/src/effects/fs-transaction.ts +85 -17
- package/src/runtime/context/codegraph-read-provider.ts +233 -2
- package/src/runtime/context/codegraph-sidecar.cjs +74 -40
- package/src/runtime/context/generic-lsp-provider.ts +355 -0
- package/src/runtime/context/lsp-client.ts +283 -0
- package/src/runtime/context/semantic-navigation.ts +275 -0
- package/src/runtime/context/swift-navigation.ts +565 -0
- package/src/runtime/context/typescript-navigation.ts +226 -0
- package/src/runtime/control-plane/dispatch-priority.ts +28 -0
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +196 -2
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
- package/src/runtime/control-plane/execution/session-store.ts +18 -0
- package/src/runtime/control-plane/execution/validation.ts +15 -2
- package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
- package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +175 -8
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -21
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +87 -9
- package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
- package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
- package/src/runtime/control-plane/facade/controller-session-store.ts +144 -14
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +9 -2
- package/src/runtime/control-plane/facade/goal-workloop.ts +885 -105
- package/src/runtime/control-plane/facade/index.ts +1 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +211 -26
- package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
- package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
- package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
- package/src/runtime/control-plane/facade/types.ts +55 -11
- package/src/runtime/control-plane/facade/work-contract-store.ts +204 -73
- package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
- package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
- package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +145 -0
- package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +273 -542
- package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
- package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
- package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
- package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
- package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +50 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +642 -51
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
- package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +15 -11
- package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
- package/src/runtime/control-plane/release-retention.ts +62 -2
- package/src/runtime/control-plane/routing/route-policy.ts +7 -16
- package/src/runtime/control-plane/runtime-status-client.ts +0 -2
- package/src/runtime/diagnostics/mcp-timing.ts +19 -0
- package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
- package/src/runtime/diagnostics/performance.ts +24 -1
- package/src/runtime/evidence/event-ledger.ts +1 -1
- package/src/runtime/execution/jobs/store.ts +58 -4
- package/src/runtime/execution/jobs/types.ts +1 -1
- package/src/runtime/execution/managed-workspace.ts +203 -1
- package/src/runtime/execution/process-runtime/check-facade.ts +52 -14
- package/src/runtime/execution/process-runtime/check-result.ts +63 -2
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +346 -40
- package/src/runtime/execution/process-runtime/gc.ts +98 -12
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +57 -6
- package/src/runtime/execution/process-runtime/resource-claims.ts +97 -8
- package/src/runtime/execution/process-runtime/runtime.ts +59 -4
- package/src/runtime/execution/process-runtime/store.ts +7 -0
- package/src/runtime/execution/process-runtime/types.ts +2 -0
- package/src/runtime/execution/thin-harness/async-process.ts +12 -2
- package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
- package/src/runtime/execution/workers/executor.ts +0 -48
- package/src/runtime/gateway/mcp/execution-tools.ts +1219 -126
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +185 -83
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2555 -1616
- package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
- package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
- package/src/runtime/plugins/browser-adapter.ts +2925 -318
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff-host.ts +6 -31
- package/src/runtime/plugins/browser-handoff.ts +92 -5
- package/src/runtime/plugins/browser-macos-bridge.ts +586 -45
- package/src/runtime/plugins/browser-node-bridge.ts +6 -34
- package/src/runtime/plugins/browser-provider-registry.ts +109 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +152 -0
- package/src/runtime/plugins/browser-runtime.ts +183 -0
- package/src/runtime/plugins/browser-session-authority.ts +332 -0
- package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +15 -12
- package/src/runtime/plugins/external-adapter.ts +324 -3
- package/src/runtime/plugins/external-registration.ts +84 -5
- package/src/runtime/plugins/external-unix-socket.ts +7 -1
- package/src/runtime/plugins/first-party-registry.ts +4 -2
- package/src/runtime/plugins/github-adapter.ts +125 -0
- package/src/runtime/plugins/gmail-adapter.ts +28 -2
- package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
- package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
- package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
- package/src/runtime/plugins/ios-adapter.ts +106 -16
- package/src/runtime/plugins/ios-agent-device.ts +234 -64
- package/src/runtime/plugins/ios-physical-device.ts +1143 -392
- package/src/runtime/plugins/lightweight-action.ts +153 -0
- package/src/runtime/plugins/local-system-adapter.ts +125 -8
- package/src/runtime/plugins/macos-capability-broker.ts +55 -9
- package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
- package/src/runtime/plugins/plugin-management-adapter.ts +181 -0
- package/src/runtime/plugins/resend-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +366 -24
- package/src/runtime/plugins/types.ts +39 -2
- package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
- package/src/runtime/projections/git-status-sampler.ts +16 -16
- package/src/runtime/projections/materialized-view.ts +28 -10
- package/src/runtime/recovery/actions.ts +0 -10
- package/src/runtime/recovery/classifier.ts +0 -9
- package/src/runtime/recovery/maintenance-executor.ts +415 -18
- package/src/runtime/recovery/probe.ts +0 -1
- package/src/runtime/recovery/types.ts +0 -1
- package/src/runtime/root/mcp-transport.ts +180 -10
- package/src/runtime/root/package-connector-service.ts +186 -8
- package/src/runtime/root/package-runtime-release.ts +143 -17
- package/src/runtime/root/package-runtime-service.ts +430 -22
- package/src/runtime/root/release-manifest.ts +7 -2
- package/src/runtime/root/release-materialize.ts +162 -19
- package/src/runtime/root/release-store.ts +48 -11
- package/src/runtime/root/runtime.ts +23 -5
- package/src/runtime/root/service.ts +100 -27
- package/src/runtime/root/types.ts +2 -0
- package/src/runtime/safe-tooling/index.ts +0 -1
- package/src/runtime/safe-tooling/ios-development.ts +321 -63
- package/src/runtime/safe-tooling/types.ts +0 -30
- package/src/runtime/shared/trusted-executable.ts +62 -0
- package/src/runtime/shared/trusted-node-executable.ts +48 -0
- package/src/runtime/standalone-recovery/core.ts +702 -94
- package/src/runtime/standalone-recovery/entry.ts +99 -23
- package/src/runtime/standalone-recovery/installer.ts +19 -3
- package/src/runtime/standalone-recovery/service-labels.ts +2 -0
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
- package/src/runtime/workflow/schedules/browser-probe.ts +258 -0
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
- package/src/runtime/workflow/schedules/engine.ts +509 -80
- package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
- package/src/runtime/workflow/schedules/settlement.ts +48 -4
- package/src/runtime/workflow/schedules/store.ts +131 -10
- package/src/runtime/workflow/schedules/types.ts +6 -3
- package/src/runtime/workflow/schedules/work-continuation.ts +120 -34
- package/src/testing/test-governance.ts +8 -40
- package/assets/reference-configs/heartbeat-triage.md +0 -57
- package/assets/templates/helpers/harness-trace-grade.sh +0 -150
- package/assets/templates/helpers/heartbeat-triage.sh +0 -361
- package/assets/templates/helpers/maintenance-triage.sh +0 -167
- package/bin/forge-desktop-helper.mjs +0 -204
- package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
- package/docs/architecture/current/architecture-invariants.md +0 -331
- package/docs/architecture/current/automation-and-schedule-engine.md +0 -453
- package/docs/architecture/current/codegraph-context-provider.md +0 -226
- package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
- package/docs/architecture/current/controller-repository-decoupling.md +0 -148
- package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -354
- package/docs/architecture/current/entity-model.md +0 -592
- package/docs/architecture/current/external-plugin-governance.md +0 -396
- package/docs/architecture/current/failure-recovery.md +0 -447
- package/docs/architecture/current/governance.md +0 -213
- package/docs/architecture/current/human-interaction-plane.md +0 -87
- package/docs/architecture/current/implementation-status.md +0 -128
- package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
- package/docs/architecture/current/legacy-governance.md +0 -58
- package/docs/architecture/current/local-workspace-target-grants.md +0 -70
- package/docs/architecture/current/migration-roadmap.md +0 -105
- package/docs/architecture/current/multi-repository-execution.md +0 -371
- package/docs/architecture/current/operations-runbook.md +0 -45
- package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
- package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
- package/docs/architecture/current/repository-access-modes.md +0 -102
- package/docs/architecture/current/route-policy.md +0 -15
- package/docs/architecture/current/route-session-concurrency.md +0 -85
- package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
- package/docs/architecture/current/runtime-directory-map.md +0 -49
- package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
- package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
- package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
- package/docs/architecture/current/system-overview.md +0 -144
- package/docs/architecture/current/target-requirements-traceability.md +0 -202
- package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
- package/docs/architecture/current/thin-harness-v1.md +0 -311
- package/docs/architecture/current/verification-and-release-gates.md +0 -391
- package/docs/forge-autonomous-goal-loop.md +0 -9
- package/docs/forge-provider-configuration.md +0 -7
- package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -83
- package/docs/operations/controller-desktop-plugin.md +0 -112
- package/docs/operations/gmail-assistant-routines.md +0 -186
- package/docs/operations/personal-assistant-operator-guide.md +0 -61
- package/docs/operations/provider-configuration.md +0 -31
- package/scripts/harness-trace-grade.sh +0 -150
- package/scripts/heartbeat-triage.sh +0 -361
- package/scripts/maintenance-triage.sh +0 -167
- package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
- package/src/cli/repositories/goal-registry.ts +0 -239
- package/src/runtime/assistant/action-proposals.ts +0 -279
- package/src/runtime/assistant/intent.ts +0 -395
- package/src/runtime/assistant/model-provider.ts +0 -460
- package/src/runtime/assistant/openapi.ts +0 -223
- package/src/runtime/assistant/policy.ts +0 -89
- package/src/runtime/assistant/readiness.ts +0 -258
- package/src/runtime/assistant/routine-runtime.ts +0 -477
- package/src/runtime/assistant/schedule-binding.ts +0 -171
- package/src/runtime/assistant/standing-grants.ts +0 -375
- package/src/runtime/assistant/store.ts +0 -243
- package/src/runtime/assistant/types.ts +0 -135
- package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
- package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
- package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
- package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
- package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
- package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
- package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
- package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
- package/src/runtime/control-plane/goal-loop/index.ts +0 -13
- package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
- package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
- package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
- package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
- package/src/runtime/control-plane/goal-loop/types.ts +0 -378
- package/src/runtime/control-plane/startup-recovery.ts +0 -198
- package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
- package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
- package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
- package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
- package/src/runtime/plugins/desktop-adapter.ts +0 -374
- package/src/runtime/safe-tooling/browser-safe.ts +0 -133
- package/src/runtime/workflow/findings/store.ts +0 -204
- package/src/runtime/workflow/findings/types.ts +0 -58
- package/src/runtime/workflow/portfolio/engine.ts +0 -20
- package/src/runtime/workflow/portfolio/store.ts +0 -185
- package/src/runtime/workflow/portfolio/types.ts +0 -29
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import type { AssistantPluginActionExecutionInput } from './types';
|
|
6
6
|
import { AssistantPluginError } from './errors';
|
|
7
|
+
import { resolveTrustedNodeExecutable } from '../shared/trusted-node-executable';
|
|
7
8
|
|
|
8
9
|
const BRIDGE_SCHEMA_VERSION = 1;
|
|
9
10
|
const MAX_REQUEST_BYTES = 1_048_576;
|
|
@@ -43,43 +44,14 @@ interface BridgeFailure {
|
|
|
43
44
|
|
|
44
45
|
type BridgeResponse = BridgeSuccess | BridgeFailure;
|
|
45
46
|
|
|
46
|
-
function isExecutable(path: string): boolean {
|
|
47
|
-
try {
|
|
48
|
-
accessSync(path, constants.X_OK);
|
|
49
|
-
return existsSync(path);
|
|
50
|
-
} catch {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function pathCandidates(env: NodeJS.ProcessEnv): string[] {
|
|
56
|
-
const candidates = [
|
|
57
|
-
env.FORGE_NODE_EXECUTABLE,
|
|
58
|
-
env.VOLTA_HOME ? join(env.VOLTA_HOME, 'bin', 'node') : undefined,
|
|
59
|
-
'/opt/homebrew/bin/node',
|
|
60
|
-
'/usr/local/bin/node',
|
|
61
|
-
'/usr/bin/node',
|
|
62
|
-
];
|
|
63
|
-
for (const entry of (env.PATH ?? '').split(delimiter)) {
|
|
64
|
-
if (entry.trim()) candidates.push(join(entry, process.platform === 'win32' ? 'node.exe' : 'node'));
|
|
65
|
-
}
|
|
66
|
-
return candidates.filter((value): value is string => Boolean(value));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
47
|
export function resolveBrowserBridgeNodeExecutable(env: NodeJS.ProcessEnv = process.env): string {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
: resolve(env.FORGE_NODE_EXECUTABLE);
|
|
74
|
-
if (isExecutable(configured)) return configured;
|
|
48
|
+
const resolution = resolveTrustedNodeExecutable(env);
|
|
49
|
+
if (resolution.executable) return resolution.executable;
|
|
50
|
+
if (resolution.configuredInvalid) {
|
|
75
51
|
throw new AssistantPluginError('PLUGIN_BROWSER_NODE_UNAVAILABLE', 'The configured Browser bridge Node executable is not executable.', {
|
|
76
52
|
retryable: false,
|
|
77
53
|
});
|
|
78
54
|
}
|
|
79
|
-
for (const candidate of pathCandidates(env)) {
|
|
80
|
-
const absolute = isAbsolute(candidate) ? candidate : resolve(candidate);
|
|
81
|
-
if (isExecutable(absolute)) return absolute;
|
|
82
|
-
}
|
|
83
55
|
throw new AssistantPluginError('PLUGIN_BROWSER_NODE_UNAVAILABLE', 'Browser attach operations require a trusted Node executable, but none was found.', {
|
|
84
56
|
retryable: false,
|
|
85
57
|
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { AssistantPluginError } from './errors';
|
|
2
|
+
import {
|
|
3
|
+
providerSupports,
|
|
4
|
+
type BrowserForegroundRequirement,
|
|
5
|
+
type BrowserProviderCapabilities,
|
|
6
|
+
type BrowserProviderCapability,
|
|
7
|
+
} from './browser-runtime-contract';
|
|
8
|
+
|
|
9
|
+
export interface BrowserRuntimeProvider<TInput, TResult> extends BrowserProviderCapabilities {
|
|
10
|
+
/** Lower values are preferred when multiple providers satisfy the same capability contract. */
|
|
11
|
+
priority: number;
|
|
12
|
+
/** Availability is decided before execution; ordinary provider failures are never fallback signals. */
|
|
13
|
+
supportsInput(input: TInput): boolean;
|
|
14
|
+
execute(input: TInput): Promise<TResult>;
|
|
15
|
+
/** Runs only after an explicit stale/restart/configuration boundary. */
|
|
16
|
+
revalidate?: () => Promise<void> | void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface BrowserProviderState<TInput, TResult> {
|
|
20
|
+
provider: BrowserRuntimeProvider<TInput, TResult>;
|
|
21
|
+
generation: number;
|
|
22
|
+
invalidatedReason?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface BrowserProviderSelection<TInput, TResult> {
|
|
26
|
+
provider: BrowserRuntimeProvider<TInput, TResult>;
|
|
27
|
+
generation: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A typed pre-action rejection. Runtime may select another provider because this proves the action
|
|
32
|
+
* was not attempted. Arbitrary provider errors are intentionally not mapped to this signal.
|
|
33
|
+
*/
|
|
34
|
+
export class BrowserProviderUnavailableBeforeActionError extends Error {
|
|
35
|
+
readonly providerId: string;
|
|
36
|
+
readonly reason: string;
|
|
37
|
+
|
|
38
|
+
constructor(providerId: string, reason: string) {
|
|
39
|
+
super(`${providerId} unavailable before action: ${reason}`);
|
|
40
|
+
this.name = 'BrowserProviderUnavailableBeforeActionError';
|
|
41
|
+
this.providerId = providerId;
|
|
42
|
+
this.reason = reason;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function foregroundCompatible(
|
|
47
|
+
provider: BrowserProviderCapabilities,
|
|
48
|
+
requested: BrowserForegroundRequirement,
|
|
49
|
+
): boolean {
|
|
50
|
+
// Background-safe providers may execute explicit foreground transactions; foreground-only
|
|
51
|
+
// providers may not satisfy a background-safe transaction.
|
|
52
|
+
return requested === 'explicit_required' || provider.foreground === 'none';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class BrowserProviderRegistry<TInput, TResult> {
|
|
56
|
+
private readonly providers = new Map<string, BrowserProviderState<TInput, TResult>>();
|
|
57
|
+
|
|
58
|
+
register(provider: BrowserRuntimeProvider<TInput, TResult>): void {
|
|
59
|
+
const current = this.providers.get(provider.providerId);
|
|
60
|
+
if (current) {
|
|
61
|
+
// Refresh call-local closures without discarding the warm provider generation.
|
|
62
|
+
current.provider = provider;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
this.providers.set(provider.providerId, { provider, generation: 1 });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
invalidate(providerId: string, reason: string): void {
|
|
69
|
+
const state = this.providers.get(providerId);
|
|
70
|
+
if (state) state.invalidatedReason = reason;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
invalidateAll(reason: string): void {
|
|
74
|
+
for (const state of this.providers.values()) state.invalidatedReason = reason;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private async prepare(state: BrowserProviderState<TInput, TResult>): Promise<void> {
|
|
78
|
+
if (!state.invalidatedReason) return;
|
|
79
|
+
await state.provider.revalidate?.();
|
|
80
|
+
state.invalidatedReason = undefined;
|
|
81
|
+
state.generation += 1;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async select(options: {
|
|
85
|
+
input: TInput;
|
|
86
|
+
requiredCapabilities: readonly BrowserProviderCapability[];
|
|
87
|
+
foreground: BrowserForegroundRequirement;
|
|
88
|
+
excludedProviderIds?: ReadonlySet<string>;
|
|
89
|
+
}): Promise<BrowserProviderSelection<TInput, TResult>> {
|
|
90
|
+
const candidates = [...this.providers.values()]
|
|
91
|
+
.filter(({ provider }) => !options.excludedProviderIds?.has(provider.providerId))
|
|
92
|
+
.filter(({ provider }) => provider.supportsInput(options.input))
|
|
93
|
+
.filter(({ provider }) => providerSupports(provider, options.requiredCapabilities))
|
|
94
|
+
.filter(({ provider }) => foregroundCompatible(provider, options.foreground))
|
|
95
|
+
.sort((left, right) => left.provider.priority - right.provider.priority
|
|
96
|
+
|| left.provider.providerId.localeCompare(right.provider.providerId));
|
|
97
|
+
|
|
98
|
+
const selected = candidates[0];
|
|
99
|
+
if (!selected) {
|
|
100
|
+
throw new AssistantPluginError(
|
|
101
|
+
'PLUGIN_BROWSER_PROVIDER_UNAVAILABLE',
|
|
102
|
+
`No Browser provider satisfies required capabilities: ${options.requiredCapabilities.join(', ') || 'browser.transaction'}.`,
|
|
103
|
+
{ retryable: true },
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
await this.prepare(selected);
|
|
107
|
+
return { provider: selected.provider, generation: selected.generation };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
export type BrowserProviderCapability =
|
|
2
|
+
| 'dom.read'
|
|
3
|
+
| 'dom.interact'
|
|
4
|
+
| 'browser.internal_resources'
|
|
5
|
+
| 'browser.screenshot'
|
|
6
|
+
| 'browser.trusted_input'
|
|
7
|
+
| 'browser.foreground'
|
|
8
|
+
| 'browser.transaction'
|
|
9
|
+
| 'browser.persistent_handle';
|
|
10
|
+
|
|
11
|
+
export type BrowserTargetOwnership = 'plugin_owned' | 'user_owned' | 'provider_owned';
|
|
12
|
+
export type BrowserTargetKind = 'page' | 'tab' | 'browser_internal_resource';
|
|
13
|
+
export type BrowserForegroundRequirement = 'none' | 'explicit_required';
|
|
14
|
+
export type BrowserActionReplaySafety = 'read_only' | 'idempotent' | 'non_idempotent';
|
|
15
|
+
|
|
16
|
+
/** Stable resource identity. URL/title are deliberately excluded because they are mutable observations. */
|
|
17
|
+
export interface BrowserTargetIdentity {
|
|
18
|
+
providerId: string;
|
|
19
|
+
resourceKind: BrowserTargetKind;
|
|
20
|
+
resourceId: string;
|
|
21
|
+
browserProduct?: string;
|
|
22
|
+
ownership: BrowserTargetOwnership;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface BrowserObservedState {
|
|
26
|
+
url: string;
|
|
27
|
+
title?: string;
|
|
28
|
+
observedAt: string;
|
|
29
|
+
providerRevision?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface BrowserProviderCapabilities {
|
|
33
|
+
providerId: string;
|
|
34
|
+
capabilities: readonly BrowserProviderCapability[];
|
|
35
|
+
foreground: BrowserForegroundRequirement;
|
|
36
|
+
/** True only when the provider can verify postconditions in the same provider call that performs the action. */
|
|
37
|
+
verifiesPostconditions: boolean;
|
|
38
|
+
/** True only when an already-bound provider handle can be reused across bounded consecutive actions. */
|
|
39
|
+
persistentHandle: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type BrowserCondition =
|
|
43
|
+
| { kind: 'target_identity'; target: BrowserTargetIdentity }
|
|
44
|
+
| { kind: 'url_equals'; url: string }
|
|
45
|
+
| { kind: 'url_matches'; pattern: string }
|
|
46
|
+
| { kind: 'selector_exists'; selector: string }
|
|
47
|
+
| { kind: 'selector_visible'; selector: string }
|
|
48
|
+
| { kind: 'text_contains'; text: string; selector?: string }
|
|
49
|
+
| { kind: 'attribute_equals'; selector: string; attribute: string; value: string }
|
|
50
|
+
| { kind: 'provider_assertion'; assertion: string; expected: string | number | boolean };
|
|
51
|
+
|
|
52
|
+
export type BrowserTransactionAction =
|
|
53
|
+
| { kind: 'read'; operation: string; arguments?: Record<string, unknown> }
|
|
54
|
+
| { kind: 'dom'; operation: string; arguments?: Record<string, unknown> }
|
|
55
|
+
| { kind: 'internal_resource'; operation: string; arguments?: Record<string, unknown> }
|
|
56
|
+
| { kind: 'trusted_input'; operation: string; arguments?: Record<string, unknown> };
|
|
57
|
+
|
|
58
|
+
export interface BrowserTransaction {
|
|
59
|
+
transactionId: string;
|
|
60
|
+
target: BrowserTargetIdentity;
|
|
61
|
+
requiredCapabilities: readonly BrowserProviderCapability[];
|
|
62
|
+
foreground: BrowserForegroundRequirement;
|
|
63
|
+
replaySafety: BrowserActionReplaySafety;
|
|
64
|
+
preconditions?: readonly BrowserCondition[];
|
|
65
|
+
action: BrowserTransactionAction;
|
|
66
|
+
/** Writes/interactions require at least one postcondition unless the action itself returns a typed read result. */
|
|
67
|
+
postconditions?: readonly BrowserCondition[];
|
|
68
|
+
timeoutMs: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface BrowserConditionEvidence {
|
|
72
|
+
condition: BrowserCondition;
|
|
73
|
+
satisfied: boolean;
|
|
74
|
+
observed?: unknown;
|
|
75
|
+
reason?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface BrowserTransactionTiming {
|
|
79
|
+
providerCalls: number;
|
|
80
|
+
providerDurationMs: number;
|
|
81
|
+
totalDurationMs: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface BrowserTransactionResult<T = unknown> {
|
|
85
|
+
transactionId: string;
|
|
86
|
+
target: BrowserTargetIdentity;
|
|
87
|
+
transportSucceeded: boolean;
|
|
88
|
+
actionPerformed: boolean;
|
|
89
|
+
/** Authoritative success bit. AX/transport success alone must never set this true. */
|
|
90
|
+
verified: boolean;
|
|
91
|
+
result?: T;
|
|
92
|
+
observedState?: BrowserObservedState;
|
|
93
|
+
preconditionEvidence: readonly BrowserConditionEvidence[];
|
|
94
|
+
postconditionEvidence: readonly BrowserConditionEvidence[];
|
|
95
|
+
timing: BrowserTransactionTiming;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface BrowserRuntimeBudget {
|
|
99
|
+
p95Ms: number;
|
|
100
|
+
maxProviderCallsWarm: number;
|
|
101
|
+
maxProviderCallsCold: number;
|
|
102
|
+
foregroundAllowed: boolean;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Architecture targets, not per-host promises. Live V2 gates report p50/p95 and fail when a
|
|
107
|
+
* regression materially exceeds these budgets without attributable provider evidence.
|
|
108
|
+
*/
|
|
109
|
+
export const BROWSER_RUNTIME_V2_BUDGETS = {
|
|
110
|
+
read: { p95Ms: 350, maxProviderCallsWarm: 1, maxProviderCallsCold: 2, foregroundAllowed: false },
|
|
111
|
+
domInteraction: { p95Ms: 600, maxProviderCallsWarm: 1, maxProviderCallsCold: 2, foregroundAllowed: false },
|
|
112
|
+
internalResource: { p95Ms: 700, maxProviderCallsWarm: 1, maxProviderCallsCold: 2, foregroundAllowed: false },
|
|
113
|
+
physicalInput: { p95Ms: 1_500, maxProviderCallsWarm: 1, maxProviderCallsCold: 2, foregroundAllowed: true },
|
|
114
|
+
} as const satisfies Record<string, BrowserRuntimeBudget>;
|
|
115
|
+
|
|
116
|
+
export function browserTargetKey(target: BrowserTargetIdentity): string {
|
|
117
|
+
return [target.providerId, target.browserProduct ?? '', target.resourceKind, target.resourceId, target.ownership].join(':');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function providerSupports(
|
|
121
|
+
provider: BrowserProviderCapabilities,
|
|
122
|
+
required: readonly BrowserProviderCapability[],
|
|
123
|
+
): boolean {
|
|
124
|
+
const available = new Set(provider.capabilities);
|
|
125
|
+
return required.every((capability) => available.has(capability));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function browserTransactionVerified(result: BrowserTransactionResult): boolean {
|
|
129
|
+
return result.transportSucceeded
|
|
130
|
+
&& result.actionPerformed
|
|
131
|
+
&& result.verified
|
|
132
|
+
&& result.preconditionEvidence.every((entry) => entry.satisfied)
|
|
133
|
+
&& result.postconditionEvidence.every((entry) => entry.satisfied);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function browserTransactionRequiresPostcondition(transaction: BrowserTransaction): boolean {
|
|
137
|
+
return transaction.replaySafety !== 'read_only';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function validateBrowserTransaction(transaction: BrowserTransaction): string[] {
|
|
141
|
+
const errors: string[] = [];
|
|
142
|
+
if (!transaction.transactionId.trim()) errors.push('transactionId is required');
|
|
143
|
+
if (!transaction.target.providerId.trim() || !transaction.target.resourceId.trim()) errors.push('stable target identity is incomplete');
|
|
144
|
+
if (!Number.isFinite(transaction.timeoutMs) || transaction.timeoutMs <= 0) errors.push('timeoutMs must be positive');
|
|
145
|
+
if (transaction.foreground === 'none' && transaction.requiredCapabilities.includes('browser.foreground')) {
|
|
146
|
+
errors.push('foreground capability cannot be required by a foreground-free transaction');
|
|
147
|
+
}
|
|
148
|
+
if (browserTransactionRequiresPostcondition(transaction) && (transaction.postconditions?.length ?? 0) === 0) {
|
|
149
|
+
errors.push('interactive transactions require at least one postcondition');
|
|
150
|
+
}
|
|
151
|
+
return errors;
|
|
152
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { AssistantPluginError } from './errors';
|
|
2
|
+
import type { AssistantPluginActionExecutionInput } from './types';
|
|
3
|
+
import {
|
|
4
|
+
validateBrowserTransaction,
|
|
5
|
+
type BrowserActionReplaySafety,
|
|
6
|
+
type BrowserForegroundRequirement,
|
|
7
|
+
type BrowserProviderCapability,
|
|
8
|
+
type BrowserTargetIdentity,
|
|
9
|
+
type BrowserTransaction,
|
|
10
|
+
} from './browser-runtime-contract';
|
|
11
|
+
import {
|
|
12
|
+
BrowserProviderRegistry,
|
|
13
|
+
BrowserProviderUnavailableBeforeActionError,
|
|
14
|
+
type BrowserRuntimeProvider,
|
|
15
|
+
} from './browser-provider-registry';
|
|
16
|
+
|
|
17
|
+
export const ALL_BROWSER_PROVIDER_CAPABILITIES = [
|
|
18
|
+
'dom.read',
|
|
19
|
+
'dom.interact',
|
|
20
|
+
'browser.internal_resources',
|
|
21
|
+
'browser.screenshot',
|
|
22
|
+
'browser.trusted_input',
|
|
23
|
+
'browser.foreground',
|
|
24
|
+
'browser.transaction',
|
|
25
|
+
'browser.persistent_handle',
|
|
26
|
+
] as const satisfies readonly BrowserProviderCapability[];
|
|
27
|
+
|
|
28
|
+
const READ_ACTIONS = new Set([
|
|
29
|
+
'list_sessions', 'reconcile_sessions', 'get_handoff_status',
|
|
30
|
+
'get_text', 'get_html', 'query_selector', 'query_all', 'get_attribute', 'list_frames', 'verify_state',
|
|
31
|
+
'extract_links', 'extract_tables', 'extract_forms', 'snapshot_interactive', 'get_console_errors', 'get_failed_requests',
|
|
32
|
+
'wait_for_load_state', 'wait_for_selector', 'await_file_transfer',
|
|
33
|
+
]);
|
|
34
|
+
const SCREENSHOT_ACTIONS = new Set(['screenshot']);
|
|
35
|
+
const TRUSTED_INPUT_ACTIONS = new Set(['trusted_input', 'activate_page']);
|
|
36
|
+
const DOM_INTERACTION_ACTIONS = new Set([
|
|
37
|
+
'create_session', 'open_page', 'navigate', 'reload', 'go_back',
|
|
38
|
+
'click', 'click_text', 'double_click', 'hover', 'focus', 'type', 'fill', 'select_option', 'check', 'uncheck',
|
|
39
|
+
'press', 'keyboard_shortcut', 'dispatch_event', 'attach_local_file', 'close_page',
|
|
40
|
+
]);
|
|
41
|
+
const IDEMPOTENT_ACTIONS = new Set(['configure', 'close_session', 'clear_session', 'request_human_handoff', 'resolve_handoff']);
|
|
42
|
+
|
|
43
|
+
interface BrowserRuntimeActionPolicy {
|
|
44
|
+
requiredCapabilities: readonly BrowserProviderCapability[];
|
|
45
|
+
foreground: BrowserForegroundRequirement;
|
|
46
|
+
replaySafety: BrowserActionReplaySafety;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const registries = new Map<string, BrowserProviderRegistry<AssistantPluginActionExecutionInput, Record<string, unknown>>>();
|
|
50
|
+
|
|
51
|
+
function registryFor(runtimeKey: string): BrowserProviderRegistry<AssistantPluginActionExecutionInput, Record<string, unknown>> {
|
|
52
|
+
let registry = registries.get(runtimeKey);
|
|
53
|
+
if (!registry) {
|
|
54
|
+
registry = new BrowserProviderRegistry();
|
|
55
|
+
registries.set(runtimeKey, registry);
|
|
56
|
+
}
|
|
57
|
+
return registry;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function invalidateBrowserRuntime(runtimeKey: string, reason: string): void {
|
|
61
|
+
registries.get(runtimeKey)?.invalidateAll(reason);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function browserRuntimeActionPolicy(actionId: string): BrowserRuntimeActionPolicy {
|
|
65
|
+
if (SCREENSHOT_ACTIONS.has(actionId)) {
|
|
66
|
+
return { requiredCapabilities: ['browser.screenshot', 'browser.transaction'], foreground: 'none', replaySafety: 'read_only' };
|
|
67
|
+
}
|
|
68
|
+
if (TRUSTED_INPUT_ACTIONS.has(actionId)) {
|
|
69
|
+
return {
|
|
70
|
+
requiredCapabilities: ['browser.trusted_input', 'browser.foreground', 'browser.transaction'],
|
|
71
|
+
foreground: 'explicit_required',
|
|
72
|
+
replaySafety: 'non_idempotent',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (READ_ACTIONS.has(actionId)) {
|
|
76
|
+
return { requiredCapabilities: ['dom.read', 'browser.transaction'], foreground: 'none', replaySafety: 'read_only' };
|
|
77
|
+
}
|
|
78
|
+
if (DOM_INTERACTION_ACTIONS.has(actionId)) {
|
|
79
|
+
return { requiredCapabilities: ['dom.interact', 'browser.transaction'], foreground: 'none', replaySafety: 'non_idempotent' };
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
requiredCapabilities: ['browser.transaction'],
|
|
83
|
+
foreground: 'none',
|
|
84
|
+
replaySafety: IDEMPOTENT_ACTIONS.has(actionId) ? 'idempotent' : 'non_idempotent',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function stringArgument(args: Record<string, unknown>, key: string): string | undefined {
|
|
89
|
+
const value = args[key];
|
|
90
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function stableTargetFor(input: AssistantPluginActionExecutionInput, providerId: string): BrowserTargetIdentity {
|
|
94
|
+
const sessionId = stringArgument(input.args, 'session_id');
|
|
95
|
+
const nativeProduct = stringArgument(input.args, 'native_browser_product');
|
|
96
|
+
const nativeWindowId = stringArgument(input.args, 'native_window_id');
|
|
97
|
+
const nativeTabId = stringArgument(input.args, 'native_tab_id');
|
|
98
|
+
if (nativeWindowId && nativeTabId) {
|
|
99
|
+
return {
|
|
100
|
+
providerId,
|
|
101
|
+
resourceKind: 'tab',
|
|
102
|
+
resourceId: `window:${nativeWindowId}/tab:${nativeTabId}`,
|
|
103
|
+
...(nativeProduct ? { browserProduct: nativeProduct } : {}),
|
|
104
|
+
ownership: 'user_owned',
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (sessionId) {
|
|
108
|
+
return {
|
|
109
|
+
providerId,
|
|
110
|
+
resourceKind: 'page',
|
|
111
|
+
resourceId: `session:${sessionId}`,
|
|
112
|
+
ownership: 'provider_owned',
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
providerId,
|
|
117
|
+
resourceKind: 'page',
|
|
118
|
+
resourceId: `request:${input.requestId}:${input.actionId}`,
|
|
119
|
+
ownership: 'plugin_owned',
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function transactionFor(
|
|
124
|
+
input: AssistantPluginActionExecutionInput,
|
|
125
|
+
providerId: string,
|
|
126
|
+
policy: BrowserRuntimeActionPolicy,
|
|
127
|
+
): BrowserTransaction {
|
|
128
|
+
return {
|
|
129
|
+
transactionId: input.requestId,
|
|
130
|
+
target: stableTargetFor(input, providerId),
|
|
131
|
+
requiredCapabilities: policy.requiredCapabilities,
|
|
132
|
+
foreground: policy.foreground,
|
|
133
|
+
replaySafety: policy.replaySafety,
|
|
134
|
+
action: {
|
|
135
|
+
kind: policy.replaySafety === 'read_only' ? 'read' : policy.foreground === 'explicit_required' ? 'trusted_input' : 'dom',
|
|
136
|
+
operation: input.actionId,
|
|
137
|
+
arguments: input.args,
|
|
138
|
+
},
|
|
139
|
+
...(policy.replaySafety === 'read_only'
|
|
140
|
+
? {}
|
|
141
|
+
: { postconditions: [{ kind: 'provider_assertion', assertion: 'semantic_action_result', expected: true }] as const }),
|
|
142
|
+
timeoutMs: typeof input.args.timeout_ms === 'number' && Number.isFinite(input.args.timeout_ms)
|
|
143
|
+
? Math.max(1, Math.trunc(input.args.timeout_ms))
|
|
144
|
+
: 60_000,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export async function executeBrowserRuntimeAction(options: {
|
|
149
|
+
runtimeKey: string;
|
|
150
|
+
input: AssistantPluginActionExecutionInput;
|
|
151
|
+
providers: readonly BrowserRuntimeProvider<AssistantPluginActionExecutionInput, Record<string, unknown>>[];
|
|
152
|
+
}): Promise<Record<string, unknown>> {
|
|
153
|
+
const registry = registryFor(options.runtimeKey);
|
|
154
|
+
for (const provider of options.providers) registry.register(provider);
|
|
155
|
+
|
|
156
|
+
const policy = browserRuntimeActionPolicy(options.input.actionId);
|
|
157
|
+
const excluded = new Set<string>();
|
|
158
|
+
while (true) {
|
|
159
|
+
const selection = await registry.select({
|
|
160
|
+
input: options.input,
|
|
161
|
+
requiredCapabilities: policy.requiredCapabilities,
|
|
162
|
+
foreground: policy.foreground,
|
|
163
|
+
excludedProviderIds: excluded,
|
|
164
|
+
});
|
|
165
|
+
const transaction = transactionFor(options.input, selection.provider.providerId, policy);
|
|
166
|
+
const validationErrors = validateBrowserTransaction(transaction);
|
|
167
|
+
if (validationErrors.length > 0) {
|
|
168
|
+
throw new AssistantPluginError('PLUGIN_BROWSER_TRANSACTION_INVALID', validationErrors[0]!, {
|
|
169
|
+
retryable: false,
|
|
170
|
+
details: { transactionId: transaction.transactionId, errors: validationErrors },
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
return await selection.provider.execute(options.input);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
if (!(error instanceof BrowserProviderUnavailableBeforeActionError)) throw error;
|
|
178
|
+
excluded.add(selection.provider.providerId);
|
|
179
|
+
// This is provider reselection, not action replay: the typed error proves the rejected provider
|
|
180
|
+
// never attempted the action. Unknown outcomes from non-idempotent actions always propagate.
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|