@moretea-labs/forge 1.7.1 → 1.8.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 +58 -62
- package/CHANGELOG.md +39 -0
- package/CLAUDE.md +42 -62
- package/README.md +2 -2
- package/SKILL.md +0 -1
- package/THIRD_PARTY_NOTICES.md +5 -2
- package/adapters/browser/index.ts +2 -0
- package/adapters/chatgpt/browser-delivery-host.ts +71 -0
- package/adapters/chatgpt/browser-delivery-runtime.ts +783 -0
- package/adapters/chatgpt/controller-binding-store.ts +55 -0
- package/adapters/chatgpt/controller-host.ts +119 -0
- package/adapters/chatgpt/controller-round-host.ts +78 -0
- package/adapters/chatgpt/controller-round-settlement-store.ts +45 -0
- package/adapters/chatgpt/provider-delivery.ts +113 -0
- package/adapters/chatgpt/work-conversation-binding-store.ts +192 -0
- package/adapters/chatgpt/wsl-bridge-delivery-host.ts +63 -0
- package/adapters/computer/desktop-operator-contract.ts +7 -0
- package/adapters/computer/desktop-operator-discovery.ts +201 -0
- package/adapters/computer/desktop-operator-negotiation.ts +174 -0
- package/adapters/computer/desktop-operator-provider.ts +312 -0
- package/adapters/computer/index.ts +1 -0
- package/adapters/computer/interaction-target-authority.ts +944 -0
- package/adapters/controller-process/binding-store.ts +34 -0
- package/adapters/controller-process/controller-host.ts +26 -0
- package/adapters/mcp/access-mode.ts +132 -0
- package/adapters/mcp/audit.ts +32 -0
- package/adapters/mcp/auth.ts +407 -0
- package/adapters/mcp/controller-round-compatibility.ts +184 -0
- package/adapters/mcp/frozen-client-semantic-compatibility.ts +292 -0
- package/adapters/mcp/instructions.ts +36 -0
- package/adapters/mcp/legacy-context.ts +18 -0
- package/adapters/mcp/multi-repository.ts +437 -0
- package/adapters/mcp/oauth.ts +391 -0
- package/adapters/mcp/paths.ts +140 -0
- package/adapters/mcp/policy.ts +232 -0
- package/adapters/mcp/proxy-env.ts +62 -0
- package/adapters/mcp/readiness-projection.ts +24 -0
- package/adapters/mcp/redaction.ts +21 -0
- package/adapters/mcp/repo.ts +24 -0
- package/adapters/mcp/runtime-gateway/artifact-adapter.ts +52 -0
- package/adapters/mcp/runtime-gateway/context-adapter.ts +829 -0
- package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +191 -0
- package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +147 -0
- package/adapters/mcp/runtime-gateway/execution-control-adapter.ts +28 -0
- package/adapters/mcp/runtime-gateway/execution-tools.ts +207 -0
- package/adapters/mcp/runtime-gateway/filesystem-adapter.ts +38 -0
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +411 -0
- package/adapters/mcp/runtime-gateway/legacy-ios-tool-adapter.ts +105 -0
- package/adapters/mcp/runtime-gateway/maintenance-adapter.ts +44 -0
- package/adapters/mcp/runtime-gateway/model-adapter.ts +63 -0
- package/adapters/mcp/runtime-gateway/persisted-check-process.ts +3 -0
- package/adapters/mcp/runtime-gateway/plugin-adapter.ts +308 -0
- package/adapters/mcp/runtime-gateway/process-tools.ts +289 -0
- package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +76 -0
- package/adapters/mcp/runtime-gateway/recovery-adapter.ts +268 -0
- package/adapters/mcp/runtime-gateway/recovery-client-adapter.ts +70 -0
- package/adapters/mcp/runtime-gateway/recovery-tool-contract.ts +99 -0
- package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +110 -0
- package/adapters/mcp/runtime-gateway/result-adapter.ts +108 -0
- package/adapters/mcp/runtime-gateway/router.ts +728 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +1251 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +634 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-shared.ts +27 -0
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +68 -0
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +186 -0
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +25 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +870 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +3186 -0
- package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +502 -0
- package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +1 -0
- package/adapters/mcp/server.ts +1048 -0
- package/adapters/mcp/setup.ts +791 -0
- package/adapters/mcp/tool-capability-cache.ts +87 -0
- package/adapters/mcp/tool-mapping/access-tools.ts +387 -0
- package/adapters/mcp/tool-mapping/legacy-tool-service.ts +5265 -0
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +150 -0
- package/adapters/mcp/tool-mapping/repository-tools.ts +1691 -0
- package/adapters/mcp/tool-mapping/tools.ts +9 -0
- package/adapters/mcp/tool-mapping/umbrella-tools.ts +117 -0
- package/adapters/mcp/toolset-names.ts +74 -0
- package/adapters/mcp/toolset-selection.ts +41 -0
- package/adapters/mcp/toolset.ts +336 -0
- package/adapters/mcp/transports/http.ts +1456 -0
- package/adapters/mcp/transports/session-registry.ts +513 -0
- package/adapters/mcp/transports/stdio.ts +8 -0
- package/adapters/mcp/tunnels/openai-secure-tunnel.ts +139 -0
- package/adapters/mcp/types.ts +41 -0
- package/assets/AGENTS.md +2 -16
- package/assets/CLAUDE.md +2 -16
- package/assets/hooks/AGENTS.md +3 -14
- package/assets/hooks/CLAUDE.md +3 -14
- package/assets/hooks/hook-input.sh +9 -2
- package/assets/hooks/lib/workflow-state.sh +28 -10
- package/assets/hooks/prompt-guard.sh +63 -37
- package/assets/hooks/security-sentinel.sh +2 -1
- package/assets/hooks/session-start-context.sh +7 -5
- package/assets/hooks/stop-orchestrator.sh +13 -3
- package/assets/initializer-question-pack.v4.json +11 -7
- package/assets/partials/05-workflow.partial.md +18 -73
- package/assets/partials/07-footer.partial.md +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +1 -2
- package/assets/partials-agents/04-task-protocol.partial.md +14 -59
- package/assets/partials-agents/06-quality-safety.partial.md +11 -16
- package/assets/partials-agents/08-deep-docs.partial.md +1 -2
- package/assets/plan-map.json +11 -11
- package/assets/plugin-registry.v1.json +9 -3
- package/assets/plugin-trust-policy.v1.json +6 -0
- package/assets/recovery/ForgeRecovery.ps1 +100 -0
- package/assets/recovery/forge-wsl-rescue +271 -0
- package/assets/reference-configs/development-protocol.md +11 -15
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/global-working-rules.md +9 -1
- package/assets/reference-configs/harness-overview.md +22 -112
- package/assets/reference-configs/hook-operations.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +2 -2
- package/assets/skill-version.json +2 -2
- package/assets/templates/helpers/architecture-event.ts +3 -34
- package/assets/templates/helpers/architecture-queue.sh +61 -10
- package/assets/templates/helpers/archive-workflow.sh +90 -180
- package/assets/templates/helpers/capability-config.ts +8 -11
- package/assets/templates/helpers/capability-resolver.ts +37 -19
- package/assets/templates/helpers/capture-plan.sh +2 -2
- package/assets/templates/helpers/check-architecture-sync.sh +1 -9
- package/assets/templates/helpers/check-task-sync.sh +82 -11
- package/assets/templates/helpers/check-task-workflow.sh +1 -3
- package/assets/templates/helpers/context-contract-sync.sh +1 -12
- package/assets/templates/helpers/contract-worktree.sh +26 -24
- package/assets/templates/helpers/ensure-task-workflow.sh +6 -8
- package/assets/templates/helpers/inspect-project-state.ts +1 -1
- package/assets/templates/helpers/migrate-project-template.sh +1 -1
- package/assets/templates/helpers/migrate-workflow-docs.ts +53 -239
- package/assets/templates/helpers/new-plan.sh +2 -2
- package/assets/templates/helpers/plan-to-todo.sh +3 -31
- package/assets/templates/helpers/sprint-backlog.sh +1 -1
- package/assets/templates/helpers/switch-plan.sh +1 -1
- package/assets/templates/helpers/workflow-contract.ts +1 -0
- package/assets/workflow-contract.v1.json +63 -171
- package/assets/workflows/xiaohongshu/xiaohongshu.collect-metrics.v1.draft.json +118 -0
- package/assets/workflows/xiaohongshu/xiaohongshu.publish-image-note.v1.draft.json +316 -0
- package/assets/workflows/xiaohongshu/xiaohongshu.publish-long-text.v1.draft.json +324 -0
- package/docs/architecture/CURRENT.md +148 -13
- package/docs/architecture/EVOLUTION.md +13 -0
- package/docs/architecture/decisions/20260801-controller-home-sqlite-state.md +2 -1
- package/docs/architecture/decisions/20260831-independent-windows-wsl-host-rescue.md +59 -0
- package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +120 -0
- package/docs/architecture/decisions/20260904-repository-runtime-data-boundary.md +42 -0
- package/docs/architecture/decisions/20260907-assistant-learning-loop.md +35 -0
- package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +296 -0
- package/docs/architecture/decisions/20260907-maintenance-diagnosis-bounded-read.md +39 -0
- package/docs/architecture/domains/verification.md +7 -0
- package/docs/architecture/domains/workflow-engine.md +1 -1
- package/docs/architecture/index.md +3 -3
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +19 -8
- package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +124 -0
- package/docs/forge-chatgpt-mcp-setup.md +5 -3
- package/docs/forge-plugin-management.md +20 -4
- package/docs/forge-runtime-self-healing-loop.md +2 -0
- package/docs/operations/benchmark-cross-version-freeze.md +38 -0
- package/docs/operations/controller-browser-plugin.md +3 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/platform-support.md +16 -8
- package/docs/operations/platform-support.zh-CN.md +2 -2
- package/docs/operations/standalone-disaster-recovery.md +26 -1
- package/docs/operations/uu-remote-rescue.md +41 -0
- package/docs/operations/windows-wsl-host-rescue.md +133 -0
- package/docs/public-usage-guide.md +1 -1
- package/docs/public-usage-guide.zh-CN.md +1 -1
- package/docs/tutorials/01-install-and-start.md +1 -1
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/tutorials/02-connect-chatgpt.md +4 -4
- package/docs/tutorials/02-connect-chatgpt.zh-CN.md +4 -4
- package/docs/wiki/Implementation.md +1 -1
- package/package.json +23 -14
- package/packages/kernel/controller/api/index.ts +2 -0
- package/packages/kernel/controller/application/controller-round-service.ts +29 -0
- package/packages/kernel/controller/application/controller-service.ts +30 -0
- package/packages/kernel/controller/domain/controller-round-transition-policy.ts +308 -0
- package/packages/kernel/controller/domain/controller-round.ts +107 -0
- package/packages/kernel/controller/domain/execution-quality.ts +133 -0
- package/packages/kernel/controller/domain/types.ts +56 -0
- package/packages/kernel/controller/index.ts +1 -0
- package/packages/kernel/controller/infrastructure/controller-binding-store.ts +84 -0
- package/packages/kernel/controller/infrastructure/controller-round-store.ts +1384 -0
- package/packages/kernel/controller/infrastructure/controller-session-store.ts +578 -0
- package/packages/kernel/controller/ports/controller-host.ts +16 -0
- package/packages/kernel/goal/api/index.ts +1 -0
- package/packages/kernel/goal/domain/types.ts +40 -0
- package/packages/kernel/goal/index.ts +1 -0
- package/packages/kernel/identity/api/index.ts +5 -0
- package/packages/kernel/identity/application/identity-service.ts +67 -0
- package/packages/kernel/identity/domain/scope.ts +63 -0
- package/packages/kernel/identity/domain/semantic-sync.ts +81 -0
- package/packages/kernel/identity/domain/types.ts +44 -0
- package/packages/kernel/identity/domain/workspace.ts +56 -0
- package/packages/kernel/identity/index.ts +1 -0
- package/packages/kernel/identity/infrastructure/identity-store.ts +75 -0
- package/packages/kernel/memory/api/index.ts +5 -0
- package/packages/kernel/memory/application/experience-service.ts +118 -0
- package/packages/kernel/memory/application/outcome-service.ts +77 -0
- package/packages/kernel/memory/domain/experience.ts +103 -0
- package/packages/kernel/memory/domain/operational-prior.ts +92 -0
- package/packages/kernel/memory/index.ts +1 -0
- package/packages/kernel/progression/api/index.ts +2 -0
- package/packages/kernel/progression/application/projector.ts +211 -0
- package/packages/kernel/progression/domain/types.ts +116 -0
- package/packages/kernel/progression/index.ts +1 -0
- package/packages/kernel/scheduler/api/index.ts +6 -0
- package/packages/kernel/scheduler/application/continuation-service.ts +212 -0
- package/packages/kernel/scheduler/application/eligibility.ts +252 -0
- package/packages/kernel/scheduler/application/schedule-service.ts +24 -0
- package/packages/kernel/scheduler/application/settlement.ts +197 -0
- package/packages/kernel/scheduler/domain/continuation.ts +38 -0
- package/packages/kernel/scheduler/domain/schedule.ts +149 -0
- package/packages/kernel/scheduler/index.ts +1 -0
- package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +38 -0
- package/packages/kernel/scheduler/infrastructure/schedule-store.ts +785 -0
- package/packages/kernel/work/api/index.ts +15 -0
- package/packages/kernel/work/application/work-service.ts +148 -0
- package/packages/kernel/work/domain/admission-policy.ts +34 -0
- package/packages/kernel/work/domain/check-receipt.ts +43 -0
- package/packages/kernel/work/domain/context-closure-receipt.ts +32 -0
- package/packages/kernel/work/domain/engineering-contracts.ts +157 -0
- package/packages/kernel/work/domain/engineering-design.ts +281 -0
- package/packages/kernel/work/domain/engineering-profile.ts +242 -0
- package/packages/kernel/work/domain/execution-concurrency.ts +254 -0
- package/packages/kernel/work/domain/execution-snapshot.ts +33 -0
- package/packages/kernel/work/domain/implementation-review.ts +510 -0
- package/packages/kernel/work/domain/project-engineering-contract.ts +202 -0
- package/packages/kernel/work/domain/repository-completion-receipt.ts +73 -0
- package/packages/kernel/work/domain/state-machine.ts +259 -0
- package/packages/kernel/work/domain/types.ts +528 -0
- package/packages/kernel/work/index.ts +1 -0
- package/packages/kernel/work/infrastructure/work-contract-store.ts +1876 -0
- package/packages/kernel/work/ports/work-contract-store.ts +18 -0
- package/packages/plugin-runtime/browser/index.ts +3 -0
- package/packages/plugin-runtime/browser/provider-registry.ts +110 -0
- package/packages/plugin-runtime/browser/runtime-contract.ts +150 -0
- package/packages/plugin-runtime/browser/session-authority.ts +61 -0
- package/packages/plugin-runtime/computer/index.ts +6 -0
- package/packages/plugin-runtime/computer/provider-error.ts +26 -0
- package/packages/plugin-runtime/computer/provider-registration.ts +52 -0
- package/packages/plugin-runtime/computer/provider-registry.ts +63 -0
- package/packages/plugin-runtime/computer/provider.ts +19 -0
- package/packages/plugin-runtime/computer/target-authority.ts +190 -0
- package/packages/plugin-runtime/computer/target-persistence.ts +54 -0
- package/packages/plugin-runtime/external/index.ts +1 -0
- package/packages/plugin-runtime/external/unix-jsonl-transport.ts +457 -0
- package/packages/plugin-runtime/index.ts +3 -0
- package/packages/protocols/browser/index.ts +1 -0
- package/packages/protocols/browser/session.ts +98 -0
- package/packages/protocols/computer/contract.ts +199 -0
- package/packages/protocols/computer/index.ts +1 -0
- package/packages/protocols/failure/contract.ts +158 -0
- package/packages/protocols/failure/index.ts +1 -0
- package/packages/protocols/handoff/index.ts +1 -0
- package/packages/protocols/handoff/status.ts +22 -0
- package/packages/protocols/mcp/execution-context.ts +11 -0
- package/packages/protocols/mcp/index.ts +2 -0
- package/packages/protocols/mcp/tool-contract.ts +42 -0
- package/packages/workflow-runtime/api/index.ts +2 -0
- package/packages/workflow-runtime/application/interpreter.ts +342 -0
- package/packages/workflow-runtime/domain/workflow-asset.ts +223 -0
- package/packages/workflow-runtime/index.ts +1 -0
- package/scripts/assemble-template.ts +1 -1
- package/scripts/benchmark-computer-hotpath.ts +255 -0
- package/scripts/benchmark-controller-round2.ts +54 -2
- package/scripts/benchmark-ios-agent-device.ts +3 -6
- package/scripts/benchmark-mcp-transport.ts +3 -4
- package/scripts/benchmark-operational-memory-activation.ts +235 -0
- package/scripts/benchmark-operational-shadow.ts +28 -0
- package/scripts/bootstrap-runtime-maintenance-recovery.sh +4 -1
- package/scripts/canary-chatgpt-provider-delivery.ts +97 -0
- package/scripts/canary-controller-semantic-wait.ts +195 -0
- package/scripts/canary-global-hook.sh +2 -2
- package/scripts/check-mcp-compatibility.ts +173 -7
- package/scripts/check-platform-support.mjs +28 -2
- package/scripts/check-public-docs.sh +1 -1
- package/scripts/check-release-readiness.sh +1 -1
- package/scripts/check-repository-hygiene.mjs +92 -0
- package/scripts/check-runtime-architecture.mjs +1206 -95
- package/scripts/check-source-duplication.mjs +9 -1
- package/scripts/check-tarball-install-smoke.sh +98 -15
- package/scripts/controller-ngrok-rotation.sh +5 -4
- package/scripts/create-project-dirs.sh +10 -74
- package/scripts/forge-local-recovery-helper.mjs +204 -0
- package/scripts/forge-uu-remote-rescue-helper.d.mts +31 -0
- package/scripts/forge-uu-remote-rescue-helper.mjs +409 -0
- package/scripts/forge-windows-host-recovery-helper.mjs +136 -0
- package/scripts/hook-shim.sh +2 -2
- package/scripts/init-project.sh +12 -70
- package/scripts/install-desktop-operator-registration.ts +4 -2
- package/scripts/install-independent-windows-wsl-recovery.ts +125 -0
- package/scripts/install-standalone-recovery.ts +122 -10
- package/scripts/install-uu-remote-rescue-registration.ts +74 -0
- package/scripts/install-windows-host-recovery-registration.ts +22 -0
- package/scripts/lib/controller-home-env.sh +6 -3
- package/scripts/lib/project-init-lib.sh +39 -582
- package/scripts/migrate-chatgpt-automation-schedules.ts +2 -2
- package/scripts/migrate-windows-wsl-controller-home.ts +306 -0
- package/scripts/open-source-audit-allowlist.txt +12 -1
- package/scripts/portability-bindings.mjs +70 -0
- package/scripts/run-bounded-command.mjs +55 -0
- package/scripts/run-bun-test-file.ts +22 -6
- package/scripts/run-governed-gate.ts +4 -1
- package/scripts/smoke-mcp-http-runtime.ts +1 -1
- package/scripts/smoke-runtime-recovery.ts +34 -1
- package/scripts/smoke-schedule-engine.ts +1 -1
- package/scripts/stage-runtime-release.ts +6 -1
- package/scripts/test-governance.ts +51 -2
- package/src/cli/agent-jobs/job-manager.ts +10 -1
- package/src/cli/chatgpt-browser/bind-server.ts +2 -1
- package/src/cli/chatgpt-browser/binding.ts +20 -10
- package/src/cli/chatgpt-browser/bridge-extension.ts +75 -0
- package/src/cli/chatgpt-browser/bridge-provider.ts +376 -11
- package/src/cli/chatgpt-browser/engine.ts +10 -11
- package/src/cli/chatgpt-browser/native-provider.ts +24 -83
- package/src/cli/chatgpt-browser/oracle-provider.ts +5 -3
- package/src/cli/chatgpt-browser/types.ts +1 -0
- package/src/cli/commands/bootstrap-control.ts +334 -0
- package/src/cli/commands/brain-assistant.ts +38 -0
- package/src/cli/commands/brain.ts +193 -40
- package/src/cli/commands/chatgpt.ts +127 -0
- package/src/cli/commands/computer.ts +437 -0
- package/src/cli/commands/doctor.ts +18 -1
- package/src/cli/commands/init-hook.ts +71 -61
- package/src/cli/commands/init.ts +3 -1
- package/src/cli/commands/mcp.ts +16 -10
- package/src/cli/commands/plugin.ts +38 -12
- package/src/cli/commands/recovery.ts +493 -80
- package/src/cli/commands/runtime.ts +9 -4
- package/src/cli/commands/setup-profile.ts +89 -39
- package/src/cli/commands/status.ts +2 -1
- package/src/cli/controller/check-runner.ts +487 -98
- package/src/cli/controller/context/types.ts +7 -1
- package/src/cli/controller/context-pack.ts +23 -3
- package/src/cli/controller/issue-store.ts +1 -1
- package/src/cli/controller/systemd-user.ts +110 -0
- package/src/cli/controller/types.ts +10 -70
- package/src/cli/controller/worklog.ts +67 -13
- package/src/cli/editing/edit-operation-contract.ts +92 -0
- package/src/cli/editing/edit-session.ts +289 -13
- package/src/cli/github/plugin.ts +17 -12
- package/src/cli/hook/route-registry.ts +3 -5
- package/src/cli/hook/runtime.ts +49 -3
- package/src/cli/index.ts +3 -0
- package/src/cli/local-bridge/connector-freshness.ts +2 -2
- package/src/cli/local-bridge/console-automations.ts +2 -2
- package/src/cli/local-bridge/facade-api.ts +41 -14
- package/src/cli/local-bridge/job-store.ts +1 -1
- package/src/cli/local-bridge/server.ts +24 -27
- package/src/cli/mcp/access-mode.ts +2 -132
- package/src/cli/mcp/access-tools.ts +2 -387
- package/src/cli/mcp/audit.ts +2 -32
- package/src/cli/mcp/auth.ts +2 -404
- package/src/cli/mcp/instructions.ts +2 -34
- package/src/cli/mcp/legacy-context.ts +2 -16
- package/src/cli/mcp/legacy-tool-service.ts +2 -5308
- package/src/cli/mcp/multi-repository.ts +2 -436
- package/src/cli/mcp/oauth.ts +2 -375
- package/src/cli/mcp/openai-secure-tunnel.ts +2 -0
- package/src/cli/mcp/paths.ts +2 -140
- package/src/cli/mcp/policy.ts +2 -232
- package/src/cli/mcp/post-finalize-work-attribution.ts +2 -150
- package/src/cli/mcp/proxy-env.ts +2 -62
- package/src/cli/mcp/readiness-projection.ts +2 -24
- package/src/cli/mcp/redaction.ts +2 -21
- package/src/cli/mcp/repo.ts +2 -24
- package/src/cli/mcp/repository-tools.ts +2 -1585
- package/src/cli/mcp/server.ts +2 -951
- package/src/cli/mcp/setup.ts +2 -737
- package/src/cli/mcp/tool-capability-cache.ts +2 -87
- package/src/cli/mcp/tool-contract.ts +2 -14
- package/src/cli/mcp/tools.ts +2 -9
- package/src/cli/mcp/toolset-names.ts +2 -70
- package/src/cli/mcp/toolset-selection.ts +2 -41
- package/src/cli/mcp/toolset.ts +2 -336
- package/src/cli/mcp/transports/AGENTS.md +1 -10
- package/src/cli/mcp/transports/CLAUDE.md +1 -10
- package/src/cli/mcp/transports/http.ts +2 -1414
- package/src/cli/mcp/transports/session-registry.ts +2 -490
- package/src/cli/mcp/transports/stdio.ts +2 -8
- package/src/cli/mcp/types.ts +2 -41
- package/src/cli/mcp/umbrella-tools.ts +2 -117
- package/src/cli/repositories/command-executor.ts +64 -18
- package/src/cli/repositories/command-scope.ts +117 -1
- package/src/cli/repositories/controller-home.ts +119 -1
- package/src/cli/repositories/identity.ts +13 -0
- package/src/cli/repositories/registry.ts +68 -49
- package/src/cli/repositories/repository-snapshot.ts +53 -7
- package/src/cli/repositories/runtime-storage.ts +27 -2
- package/src/cli/repositories/safe-patch.ts +34 -38
- package/src/cli/repositories/selected-path-actions.ts +22 -2
- package/src/cli/repositories/structured-git.ts +105 -25
- package/src/cli/runtime/helper-runner.ts +7 -0
- package/src/cli/runtime-invocation.ts +8 -1
- package/src/cli/tools/codegraph.ts +44 -25
- package/src/core/adoption/manifest-templates.ts +1 -1
- package/src/core/adoption/plan.ts +3 -26
- package/src/core/adoption/workflow-contract-plan.ts +17 -9
- package/src/effects/process-runner.ts +8 -14
- package/src/runtime/context/assistant-context.ts +154 -0
- package/src/runtime/context/assistant-work-context.ts +147 -0
- package/src/runtime/context/codegraph-cache-boundary.ts +255 -0
- package/src/runtime/context/codegraph-read-provider.ts +55 -22
- package/src/runtime/context/codegraph-sidecar.cjs +8 -1
- package/src/runtime/context/context-closure.ts +268 -0
- package/src/runtime/context/context-plane.ts +211 -0
- package/src/runtime/context/project-engineering-contract.ts +60 -0
- package/src/runtime/control-plane/bootstrap/capability-provider.ts +74 -0
- package/src/runtime/control-plane/bootstrap/control-api.ts +57 -0
- package/src/runtime/control-plane/bootstrap/index.ts +5 -0
- package/src/runtime/control-plane/bootstrap/state-machine.ts +141 -0
- package/src/runtime/control-plane/bootstrap/store.ts +21 -0
- package/src/runtime/control-plane/bootstrap/types.ts +87 -0
- package/src/runtime/control-plane/cleanup-artifact-retention.ts +328 -0
- package/src/runtime/control-plane/codegraph-cache-retention.ts +164 -0
- package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +320 -0
- package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +169 -0
- package/src/runtime/control-plane/execution/controller-authority-recovery.ts +350 -0
- package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +85 -0
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +417 -100
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +103 -15
- package/src/runtime/control-plane/execution/implementation-review-content.ts +95 -0
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +2 -2
- package/src/runtime/control-plane/execution/retained-work-resume.ts +336 -6
- package/src/runtime/control-plane/execution/validation.ts +28 -3
- package/src/runtime/control-plane/execution/work-authority-reconciler.ts +116 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +44 -2
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +34 -3
- package/src/runtime/control-plane/execution/work-execution-support.ts +42 -22
- package/src/runtime/control-plane/execution/work-finalization-service.ts +1103 -166
- package/src/runtime/control-plane/execution/work-handle-authority.ts +267 -16
- package/src/runtime/control-plane/execution/work-handle-store.ts +77 -0
- package/src/runtime/control-plane/execution/work-head-settlement.ts +75 -0
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +145 -23
- package/src/runtime/control-plane/execution/work-operation-service.ts +49 -13
- package/src/runtime/control-plane/execution/work-preparation-service.ts +31 -15
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +1 -1
- package/src/runtime/control-plane/execution/work-task-receipt.ts +20 -1
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +407 -76
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +88 -18
- package/src/runtime/control-plane/execution/work-verification-context.ts +1 -1
- package/src/runtime/control-plane/execution/work-verification-service.ts +258 -4
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +200 -15
- package/src/runtime/control-plane/facade/capability-registry.ts +21 -10
- package/src/runtime/control-plane/facade/controller-round-relay.ts +3 -1118
- package/src/runtime/control-plane/facade/controller-session-store.ts +2 -488
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +6 -3
- package/src/runtime/control-plane/facade/goal-workloop.ts +972 -137
- package/src/runtime/control-plane/facade/handoff-inbox-application.ts +158 -0
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +10 -0
- package/src/runtime/control-plane/facade/index.ts +4 -2
- package/src/runtime/control-plane/facade/operation-digest.ts +22 -58
- package/src/runtime/control-plane/facade/plan-contract-store.ts +1004 -38
- package/src/runtime/control-plane/facade/repository-work-admission.ts +19 -1
- package/src/runtime/control-plane/facade/requirement-authority.ts +218 -0
- package/src/runtime/control-plane/facade/requirement-board.ts +6 -1
- package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +48 -0
- package/src/runtime/control-plane/facade/semantic-admission.ts +8 -16
- package/src/runtime/control-plane/facade/suggested-actions.ts +4 -1
- package/src/runtime/control-plane/facade/types.ts +189 -532
- package/src/runtime/control-plane/facade/work-admission-policy.ts +84 -35
- package/src/runtime/control-plane/facade/work-contract-store.ts +2 -1043
- package/src/runtime/control-plane/facade/work-implementation-review.ts +2 -0
- package/src/runtime/control-plane/facade/work-state-machine.ts +2 -250
- package/src/runtime/control-plane/generated-cache-retention.ts +239 -18
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +12 -1
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +76 -13
- package/src/runtime/control-plane/global-scheduler/periodic-cleanup-entry.ts +55 -0
- package/src/runtime/control-plane/global-scheduler/periodic-cleanup-process.ts +98 -0
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +1 -1
- package/src/runtime/control-plane/global-scheduler/scheduler-worker-entry.ts +10 -0
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +173 -81
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +18 -6
- package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +397 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +2 -177
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +301 -560
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +20 -4
- package/src/runtime/control-plane/launcher/thin-launcher.ts +50 -4
- package/src/runtime/control-plane/lifecycle-retention-metrics.ts +60 -0
- package/src/runtime/control-plane/persistence/experience-store.ts +169 -0
- package/src/runtime/control-plane/persistence/operational-prior-store.ts +348 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +30 -22
- package/src/runtime/control-plane/persistence/sqlite-store.ts +545 -76
- package/src/runtime/control-plane/persistence/workflow-content-store.ts +98 -0
- package/src/runtime/control-plane/persistence/workflow-registry-store.ts +186 -0
- package/src/runtime/control-plane/persistence/workflow-run-store.ts +123 -0
- package/src/runtime/control-plane/release-retention.ts +56 -16
- package/src/runtime/control-plane/repository-namespace-retention.ts +208 -0
- package/src/runtime/control-plane/routing/route-policy.ts +19 -0
- package/src/runtime/control-plane/runtime-cleanup.ts +574 -37
- package/src/runtime/control-plane/runtime-generation.ts +6 -0
- package/src/runtime/control-plane/workspace/semantic-sync-service.ts +465 -0
- package/src/runtime/control-plane/workspace/workspace-store.ts +80 -0
- package/src/runtime/diagnostics/incident-repair.ts +406 -0
- package/src/runtime/diagnostics/mcp-timing.ts +125 -6
- package/src/runtime/diagnostics/performance.ts +6 -14
- package/src/runtime/diagnostics/read-only-tool.ts +1 -1
- package/src/runtime/evidence/artifact-store.ts +65 -2
- package/src/runtime/evidence/operational-shadow.ts +38 -0
- package/src/runtime/evidence/process-check-receipt.ts +5 -43
- package/src/runtime/evidence/sensitive-output.ts +4 -4
- package/src/runtime/execution/jobs/receipt-recovery.ts +1 -1
- package/src/runtime/execution/jobs/store.ts +121 -2
- package/src/runtime/execution/managed-workspace.ts +55 -5
- package/src/runtime/execution/process-runtime/canary.ts +19 -5
- package/src/runtime/execution/process-runtime/check-classification.ts +48 -0
- package/src/runtime/execution/process-runtime/check-facade.ts +23 -9
- package/src/runtime/execution/process-runtime/check-receipt.ts +1 -1
- package/src/runtime/execution/process-runtime/check-result-retention.ts +132 -0
- package/src/runtime/execution/process-runtime/check-result.ts +73 -2
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +42 -3
- package/src/runtime/execution/process-runtime/check-storage.ts +187 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +38 -87
- package/src/runtime/execution/process-runtime/index.ts +1 -0
- package/src/runtime/execution/process-runtime/interactive-admission.ts +2 -1
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +32 -1
- package/src/runtime/execution/process-runtime/persisted-check.ts +128 -21
- package/src/runtime/execution/process-runtime/resource-claims.ts +60 -3
- package/src/runtime/execution/process-runtime/runtime.ts +132 -15
- package/src/runtime/execution/process-runtime/types.ts +22 -0
- package/src/runtime/execution/workers/executor.ts +16 -13
- package/src/runtime/execution/workers/worker-entry.ts +1 -1
- package/src/runtime/gateway/mcp/execution-tools.ts +2 -207
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +2 -61
- package/src/runtime/gateway/mcp/persisted-check-process.ts +2 -3
- package/src/runtime/gateway/mcp/process-tools.ts +2 -289
- package/src/runtime/gateway/mcp/router.ts +2 -1125
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +2 -565
- package/src/runtime/gateway/mcp/runtime-tools.ts +2 -6651
- package/src/runtime/gateway/mcp/work-validation-reconciler.ts +2 -1
- package/src/runtime/maintenance/cleanup.ts +38 -24
- package/src/runtime/platform/browser-product-discovery.ts +174 -0
- package/src/runtime/platform/computer-platform.ts +14 -0
- package/src/runtime/platform/executable-discovery.ts +54 -0
- package/src/runtime/platform/fetch-http-server.ts +90 -0
- package/src/runtime/platform/service-manager.ts +138 -0
- package/src/runtime/platform/windows-host-discovery.ts +118 -0
- package/src/runtime/platform/windows-recovery-deployment.ts +67 -0
- package/src/runtime/plugins/action-application.ts +135 -0
- package/src/runtime/plugins/app-store-connect-adapter.ts +9 -21
- package/src/runtime/plugins/browser-adapter.ts +140 -100
- package/src/runtime/plugins/browser-automation-service.ts +15 -36
- package/src/runtime/plugins/browser-macos-bridge.ts +69 -21
- package/src/runtime/plugins/browser-manifest-surface.ts +30 -6
- package/src/runtime/plugins/browser-native-session-service.ts +1 -1
- package/src/runtime/plugins/browser-provider-registry.ts +2 -109
- package/src/runtime/plugins/browser-registration.ts +16 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +2 -154
- package/src/runtime/plugins/browser-runtime.ts +41 -9
- package/src/runtime/plugins/browser-session-authority.ts +101 -291
- package/src/runtime/plugins/browser-session-legacy-migration.ts +203 -0
- package/src/runtime/plugins/browser-session-store.ts +229 -36
- package/src/runtime/plugins/browser-session-types.ts +2 -98
- package/src/runtime/plugins/capability-authorization-grants.ts +17 -0
- package/src/runtime/plugins/catalog-trust.ts +82 -0
- package/src/runtime/plugins/computer-registration.ts +839 -0
- package/src/runtime/plugins/config-store.ts +119 -0
- package/src/runtime/plugins/desktop-operator-external-policy.ts +932 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +111 -8
- package/src/runtime/plugins/errors.ts +8 -1
- package/src/runtime/plugins/external-adapter.ts +45 -322
- package/src/runtime/plugins/external-provider-policy.ts +48 -0
- package/src/runtime/plugins/external-registration.ts +9 -1
- package/src/runtime/plugins/external-unix-socket-probe.cjs +9 -3
- package/src/runtime/plugins/external-unix-socket.ts +64 -193
- package/src/runtime/plugins/first-party-external-registration.ts +163 -0
- package/src/runtime/plugins/first-party-registry.ts +3 -1
- package/src/runtime/plugins/github-adapter.ts +1 -2
- package/src/runtime/plugins/gmail-adapter.ts +6 -6
- package/src/runtime/plugins/google-calendar-adapter.ts +6 -6
- package/src/runtime/plugins/google-shared.ts +31 -46
- package/src/runtime/plugins/google-tasks-adapter.ts +6 -6
- package/src/runtime/plugins/ios-adapter.ts +1 -2
- package/src/runtime/plugins/local-system-adapter.ts +180 -0
- package/src/runtime/plugins/macos-capability-broker.ts +15 -105
- package/src/runtime/plugins/resend-adapter.ts +15 -24
- package/src/runtime/plugins/store.ts +493 -51
- package/src/runtime/plugins/types.ts +8 -1
- package/src/runtime/plugins/uu-remote-rescue-registration.ts +155 -0
- package/src/runtime/plugins/windows-host-recovery-install.ts +68 -0
- package/src/runtime/plugins/windows-host-recovery-registration.ts +85 -0
- package/src/runtime/plugins/xiaohongshu-publish.ts +86 -430
- package/src/runtime/projections/controller-context.ts +12 -6
- package/src/runtime/projections/git-status-sampler.ts +73 -22
- package/src/runtime/projections/materialized-view.ts +14 -8
- package/src/runtime/recovery/capability-action-application.ts +228 -0
- package/src/runtime/recovery/index.ts +3 -0
- package/src/runtime/recovery/lifecycle-inventory.ts +338 -0
- package/src/runtime/recovery/local-jobs-repair.ts +14 -14
- package/src/runtime/recovery/maintenance-executor.ts +358 -76
- package/src/runtime/recovery/quarantine-retention.ts +256 -0
- package/src/runtime/release/identity.ts +6 -0
- package/src/runtime/resources/leases/store.ts +1 -1
- package/src/runtime/root/active-execution-power-assertion.ts +139 -0
- package/src/runtime/root/assistant-learning-loop.ts +45 -0
- package/src/runtime/root/browser-session-composition.ts +59 -0
- package/src/runtime/root/computer-composition.ts +191 -0
- package/src/runtime/root/computer-target-composition.ts +16 -0
- package/src/runtime/root/computer-target-persistence.ts +39 -0
- package/src/runtime/root/controller-round-composition.ts +107 -0
- package/src/runtime/root/controller-services.ts +2 -0
- package/src/runtime/root/entry.ts +4 -3
- package/src/runtime/root/gateway-adapter.ts +3 -3
- package/src/runtime/root/local-bridge.ts +5 -2
- package/src/runtime/root/mcp-transport.ts +5 -5
- package/src/runtime/root/package-connector-service.ts +108 -56
- package/src/runtime/root/package-runtime-release.ts +86 -18
- package/src/runtime/root/package-runtime-service.ts +63 -86
- package/src/runtime/root/release-execution-canary.ts +71 -0
- package/src/runtime/root/release-loader.ts +68 -0
- package/src/runtime/root/release-manifest.ts +106 -2
- package/src/runtime/root/release-materialize.ts +103 -4
- package/src/runtime/root/release-store.ts +31 -2
- package/src/runtime/root/runtime.ts +240 -25
- package/src/runtime/root/scheduled-controller-composition.ts +51 -0
- package/src/runtime/root/scheduler.ts +12 -4
- package/src/runtime/root/service-runner.ts +1 -1
- package/src/runtime/root/service.ts +41 -16
- package/src/runtime/root/status.ts +1 -0
- package/src/runtime/root/types.ts +24 -1
- package/src/runtime/shared/local-bridge-surface.ts +1 -1
- package/src/runtime/shared/process-environment.ts +19 -4
- package/src/runtime/shared/storage-capacity.ts +68 -0
- package/src/runtime/standalone-recovery/controller-home-migration.ts +1116 -0
- package/src/runtime/standalone-recovery/core.ts +984 -230
- package/src/runtime/standalone-recovery/entry.ts +182 -51
- package/src/runtime/standalone-recovery/independent-host-rescue.ts +172 -0
- package/src/runtime/standalone-recovery/installer.ts +212 -104
- package/src/runtime/standalone-recovery/mcp-server.ts +243 -0
- package/src/runtime/standalone-recovery/mutation-identity-contract.ts +21 -0
- package/src/runtime/standalone-recovery/operation-lock.ts +160 -0
- package/src/runtime/standalone-recovery/performance.ts +135 -0
- package/src/runtime/standalone-recovery/release.ts +5 -0
- package/src/runtime/watchdog/workflow-watchdog.ts +1 -1
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +1 -1
- package/src/runtime/workflow/schedules/engine.ts +191 -343
- package/src/runtime/workflow/schedules/pending-activation.ts +1 -1
- package/src/runtime/workflow/schedules/settlement.ts +2 -191
- package/src/runtime/workflow/schedules/store.ts +2 -607
- package/src/runtime/workflow/schedules/types.ts +2 -127
- package/src/runtime/workflow/schedules/work-continuation.ts +180 -15
- package/src/runtime/workflows/first-party/xiaohongshu.ts +122 -0
- package/src/runtime/workflows/runtime.ts +486 -0
- package/src/testing/test-governance.ts +90 -29
- package/assets/templates/helpers/archive-architecture-request.sh +0 -244
- package/docs/architecture/history/README.md +0 -7
- package/docs/architecture/history/chatgpt-handoff-facade.md +0 -397
- package/docs/architecture/history/global-hook-runtime.md +0 -166
- package/docs/architecture/history/ios-semantic-automation-provider-v2.md +0 -170
- package/docs/architecture/requests/archive/2026/20260528-154740-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-154816-assets-hooks-assets-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-161851-ai-harness-workflow-contract-json-ai-harness-workflow-contract-json.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-161853-scripts-check-task-workflow-sh-scripts-check-task-workflow-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-161911-assets-workflow-contract-v1-json-assets-workflow-contract-v1-json.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222416-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222444-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222457-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222648-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222705-ai-hooks-ai-hooks-worktree-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222726-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222727-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-224736-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233259-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233335-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233456-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233457-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233637-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233638-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260529-000322-root-package-json.md +0 -59
- package/docs/architecture/requests/archive/2026/20260529-004238-ai-hooks-ai-hooks-lib-workflow-state-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260529-020654-ai-harness-policy-json-ai-harness-policy-json.md +0 -63
- package/docs/architecture/requests/archive/2026/20260529-094236-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094323-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094331-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094339-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094430-assets-hooks-assets-hooks-session-start-context-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094446-ai-hooks-ai-hooks-session-start-context-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260613-002040-runtime-harness-hook-adapters.md +0 -68
- package/docs/architecture/requests/archive/2026/root.md +0 -68
- package/docs/architecture/requests/archive/2026/runtime-harness-hook-adapters.md +0 -76
- package/docs/architecture/requests/archive/2026/verification-evals-checks.md +0 -68
- package/docs/architecture/requests/archive/2026/workflow-engine-contract-assets.md +0 -69
- package/scripts/archive-architecture-request.sh +0 -4
- package/scripts/run-skill-evals.ts +0 -1022
|
@@ -0,0 +1,839 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'crypto';
|
|
2
|
+
import type {
|
|
3
|
+
ComputerApplicationTarget,
|
|
4
|
+
ComputerApplicationStableIdentity,
|
|
5
|
+
ComputerApplicationTargetLease,
|
|
6
|
+
} from '../../../packages/plugin-runtime/computer/target-authority';
|
|
7
|
+
import {
|
|
8
|
+
COMPUTER_CAPTURE_CAPABILITY,
|
|
9
|
+
COMPUTER_CONSOLE_UNLOCK_CAPABILITY,
|
|
10
|
+
COMPUTER_ELEMENT_ACTION_CAPABILITY,
|
|
11
|
+
COMPUTER_ELEMENT_OBSERVE_CAPABILITY,
|
|
12
|
+
COMPUTER_INPUT_CAPABILITY,
|
|
13
|
+
COMPUTER_OBSERVE_CAPABILITY,
|
|
14
|
+
type ComputerConsoleUnlockPrepareRequest,
|
|
15
|
+
type ComputerConsoleUnlockRequest,
|
|
16
|
+
type ComputerElementSemanticAction,
|
|
17
|
+
type ComputerElementTarget,
|
|
18
|
+
type ComputerRuntimeExecutionRequest,
|
|
19
|
+
type ComputerSemanticSelector,
|
|
20
|
+
} from '../../../packages/protocols/computer/index';
|
|
21
|
+
import { executeRuntimeComputer, executeRuntimeComputerConsoleUnlock } from '../root/computer-composition';
|
|
22
|
+
import { runtimeComputerInteractionTargetAuthority } from '../root/computer-target-composition';
|
|
23
|
+
import { currentComputerPlatform } from '../platform/computer-platform';
|
|
24
|
+
import {
|
|
25
|
+
buildBrowserPluginManifest,
|
|
26
|
+
executeBrowserPluginAction,
|
|
27
|
+
resolveBrowserPluginAuthorizationContext,
|
|
28
|
+
} from './browser-adapter';
|
|
29
|
+
import { desktopOperatorActions } from './desktop-operator-registration';
|
|
30
|
+
import { getExternalPluginAdapter } from './external-adapter';
|
|
31
|
+
import { AssistantPluginError } from './errors';
|
|
32
|
+
import type {
|
|
33
|
+
AssistantPluginActionDescriptor,
|
|
34
|
+
AssistantPluginActionExecutionInput,
|
|
35
|
+
AssistantPluginAdapter,
|
|
36
|
+
AssistantPluginAuthorizationContext,
|
|
37
|
+
AssistantPluginBuildContext,
|
|
38
|
+
AssistantPluginCapability,
|
|
39
|
+
AssistantPluginManifest,
|
|
40
|
+
AssistantPluginPermissionScope,
|
|
41
|
+
} from './types';
|
|
42
|
+
|
|
43
|
+
const DESKTOP_PROVIDER_ID = 'desktop_operator';
|
|
44
|
+
const computerTargetAuthority = runtimeComputerInteractionTargetAuthority();
|
|
45
|
+
const DESKTOP_TARGET_OPEN_ACTION = 'desktop_target_open';
|
|
46
|
+
const DESKTOP_TARGET_CLOSE_ACTION = 'desktop_target_close';
|
|
47
|
+
const DESKTOP_ELEMENT_OBSERVE_ACTION = 'desktop_element_observe';
|
|
48
|
+
const DESKTOP_ELEMENT_ACTION_ACTION = 'desktop_element_action';
|
|
49
|
+
export const COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION = 'console_unlock_prepare';
|
|
50
|
+
export const COMPUTER_CONSOLE_UNLOCK_ACTION = 'console_unlock';
|
|
51
|
+
const DEFAULT_CONSOLE_UNLOCK_TIMEOUT_MS = 15_000;
|
|
52
|
+
const MAX_CONSOLE_UNLOCK_TIMEOUT_MS = 30_000;
|
|
53
|
+
const CONSOLE_CREDENTIAL_HANDLE_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
54
|
+
const COMPUTER_ELEMENT_SEMANTIC_ACTIONS = ['invoke', 'focus', 'set_value', 'toggle', 'expand', 'collapse', 'select', 'open', 'show_menu', 'scroll_page_down', 'scroll_page_up'] as const;
|
|
55
|
+
const DESKTOP_SEMANTIC_ACTION_IDS = new Set([
|
|
56
|
+
'desktop_observe',
|
|
57
|
+
'desktop_press',
|
|
58
|
+
'desktop_select_rows',
|
|
59
|
+
'desktop_type_text',
|
|
60
|
+
'desktop_key',
|
|
61
|
+
'desktop_open_url',
|
|
62
|
+
'desktop_screenshot',
|
|
63
|
+
]);
|
|
64
|
+
const DESKTOP_PRODUCT_ACTION_IDS = new Set([
|
|
65
|
+
DESKTOP_TARGET_OPEN_ACTION,
|
|
66
|
+
DESKTOP_TARGET_CLOSE_ACTION,
|
|
67
|
+
...DESKTOP_SEMANTIC_ACTION_IDS,
|
|
68
|
+
DESKTOP_ELEMENT_OBSERVE_ACTION,
|
|
69
|
+
DESKTOP_ELEMENT_ACTION_ACTION,
|
|
70
|
+
COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION,
|
|
71
|
+
COMPUTER_CONSOLE_UNLOCK_ACTION,
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
function providerActionDescriptor(actionId: string): AssistantPluginActionDescriptor {
|
|
75
|
+
const descriptor = desktopOperatorActions().find((action) => action.actionId === actionId);
|
|
76
|
+
if (!descriptor) throw new Error(`COMPUTER_DESKTOP_ACTION_DESCRIPTOR_MISSING: ${actionId}`);
|
|
77
|
+
return structuredClone(descriptor);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function targetBoundDescriptor(actionId: string): AssistantPluginActionDescriptor {
|
|
81
|
+
const descriptor = providerActionDescriptor(actionId);
|
|
82
|
+
const schema = structuredClone(descriptor.argumentsSchema) as Record<string, unknown>;
|
|
83
|
+
const properties = schema.properties && typeof schema.properties === 'object'
|
|
84
|
+
? { ...(schema.properties as Record<string, unknown>) }
|
|
85
|
+
: {};
|
|
86
|
+
if ('interaction_id' in properties) {
|
|
87
|
+
delete properties.interaction_id;
|
|
88
|
+
properties.target_id = { type: 'string', description: 'Forge-owned durable Computer target id.' };
|
|
89
|
+
schema.properties = properties;
|
|
90
|
+
if (Array.isArray(schema.required)) {
|
|
91
|
+
schema.required = schema.required.map((value) => value === 'interaction_id' ? 'target_id' : value);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return { ...descriptor, argumentsSchema: schema };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface ProtectedConsoleUnlockPreparationInput {
|
|
98
|
+
confirmAuthorization: boolean;
|
|
99
|
+
timeoutMs?: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface ProtectedConsoleUnlockInvocationInput {
|
|
103
|
+
credentialHandle: string;
|
|
104
|
+
confirmAuthorization: boolean;
|
|
105
|
+
timeoutMs?: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function boundedConsoleUnlockTimeoutMs(value: number | undefined): number {
|
|
109
|
+
if (!Number.isFinite(value)) return DEFAULT_CONSOLE_UNLOCK_TIMEOUT_MS;
|
|
110
|
+
return Math.min(MAX_CONSOLE_UNLOCK_TIMEOUT_MS, Math.max(1_000, Math.trunc(value!)));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function requireConsoleUnlockAuthorization(confirmed: boolean): void {
|
|
114
|
+
if (confirmed !== true) {
|
|
115
|
+
throw new Error('COMPUTER_CONSOLE_UNLOCK_EXPLICIT_AUTHORIZATION_REQUIRED: confirm_authorization=true is required for this one invocation.');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function executeProtectedConsoleUnlockPreparation(
|
|
120
|
+
input: ProtectedConsoleUnlockPreparationInput,
|
|
121
|
+
controllerHome: string,
|
|
122
|
+
): Promise<Record<string, unknown>> {
|
|
123
|
+
requireConsoleUnlockAuthorization(input.confirmAuthorization);
|
|
124
|
+
const invocationId = randomUUID();
|
|
125
|
+
const request: ComputerConsoleUnlockPrepareRequest = {
|
|
126
|
+
capability: COMPUTER_CONSOLE_UNLOCK_CAPABILITY,
|
|
127
|
+
action: 'prepare_unlock_console',
|
|
128
|
+
};
|
|
129
|
+
const providerResult = await executeRuntimeComputerConsoleUnlock(
|
|
130
|
+
request,
|
|
131
|
+
{ kind: 'explicit_single_use', confirmed: true, invocationId },
|
|
132
|
+
boundedConsoleUnlockTimeoutMs(input.timeoutMs),
|
|
133
|
+
controllerHome,
|
|
134
|
+
);
|
|
135
|
+
const credentialHandle = typeof providerResult.credential_handle === 'string'
|
|
136
|
+
? providerResult.credential_handle
|
|
137
|
+
: undefined;
|
|
138
|
+
if (!credentialHandle || !CONSOLE_CREDENTIAL_HANDLE_PATTERN.test(credentialHandle)) {
|
|
139
|
+
throw new Error('COMPUTER_CONSOLE_UNLOCK_PREPARATION_INVALID: provider did not return a valid opaque credential handle.');
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
capability: COMPUTER_CONSOLE_UNLOCK_CAPABILITY,
|
|
143
|
+
action: 'prepare_unlock_console',
|
|
144
|
+
invocationId,
|
|
145
|
+
prepared: providerResult.prepared === true,
|
|
146
|
+
credentialHandle,
|
|
147
|
+
...(typeof providerResult.expires_in_ms === 'number' ? { expiresInMs: providerResult.expires_in_ms } : {}),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export async function executeProtectedConsoleUnlockInvocation(
|
|
152
|
+
input: ProtectedConsoleUnlockInvocationInput,
|
|
153
|
+
controllerHome: string,
|
|
154
|
+
): Promise<Record<string, unknown>> {
|
|
155
|
+
requireConsoleUnlockAuthorization(input.confirmAuthorization);
|
|
156
|
+
if (!CONSOLE_CREDENTIAL_HANDLE_PATTERN.test(input.credentialHandle)) {
|
|
157
|
+
throw new Error('COMPUTER_CONSOLE_UNLOCK_CREDENTIAL_HANDLE_REQUIRED: a provider-local opaque credential handle is required.');
|
|
158
|
+
}
|
|
159
|
+
const invocationId = randomUUID();
|
|
160
|
+
const request: ComputerConsoleUnlockRequest = {
|
|
161
|
+
capability: COMPUTER_CONSOLE_UNLOCK_CAPABILITY,
|
|
162
|
+
action: 'unlock_console',
|
|
163
|
+
credentialHandle: input.credentialHandle,
|
|
164
|
+
};
|
|
165
|
+
const providerResult = await executeRuntimeComputerConsoleUnlock(
|
|
166
|
+
request,
|
|
167
|
+
{ kind: 'explicit_single_use', confirmed: true, invocationId },
|
|
168
|
+
boundedConsoleUnlockTimeoutMs(input.timeoutMs),
|
|
169
|
+
controllerHome,
|
|
170
|
+
);
|
|
171
|
+
return {
|
|
172
|
+
capability: COMPUTER_CONSOLE_UNLOCK_CAPABILITY,
|
|
173
|
+
action: 'unlock_console',
|
|
174
|
+
invocationId,
|
|
175
|
+
unlocked: providerResult.unlocked === true,
|
|
176
|
+
verified: providerResult.verified === true,
|
|
177
|
+
...(typeof providerResult.postcondition === 'string' ? { postcondition: providerResult.postcondition } : {}),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function desktopProductActions(): AssistantPluginActionDescriptor[] {
|
|
182
|
+
const open = providerActionDescriptor('desktop_session_open');
|
|
183
|
+
const close = providerActionDescriptor('desktop_session_close');
|
|
184
|
+
return [
|
|
185
|
+
{
|
|
186
|
+
...open,
|
|
187
|
+
actionId: DESKTOP_TARGET_OPEN_ACTION,
|
|
188
|
+
title: 'Open Computer desktop target',
|
|
189
|
+
description: 'Bind one application as a Forge-owned durable Computer target. Native provider session ids remain internal rebuildable bindings.',
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
...close,
|
|
193
|
+
actionId: DESKTOP_TARGET_CLOSE_ACTION,
|
|
194
|
+
title: 'Close Computer desktop target',
|
|
195
|
+
description: 'Retire one Forge-owned Computer target after its live provider binding is closed or confirmed absent.',
|
|
196
|
+
argumentsSchema: {
|
|
197
|
+
type: 'object',
|
|
198
|
+
properties: { target_id: { type: 'string' } },
|
|
199
|
+
required: ['target_id'],
|
|
200
|
+
additionalProperties: false,
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
...[...DESKTOP_SEMANTIC_ACTION_IDS].map(targetBoundDescriptor),
|
|
204
|
+
{
|
|
205
|
+
actionId: COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION,
|
|
206
|
+
title: 'Prepare protected console unlock',
|
|
207
|
+
description: 'Ask the native Computer provider to collect a console credential locally and return only a short-lived opaque single-use handle.',
|
|
208
|
+
readOnly: false,
|
|
209
|
+
risk: 'workspace_write',
|
|
210
|
+
confirmation: 'authorization',
|
|
211
|
+
defaultTimeoutMs: DEFAULT_CONSOLE_UNLOCK_TIMEOUT_MS,
|
|
212
|
+
cancellable: true,
|
|
213
|
+
idempotent: false,
|
|
214
|
+
executionMode: 'direct_non_persistent',
|
|
215
|
+
foregroundEffect: 'required',
|
|
216
|
+
scopes: ['console.unlock'],
|
|
217
|
+
resourceClaims: [],
|
|
218
|
+
argumentsSchema: { type: 'object', properties: {}, additionalProperties: false },
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
actionId: COMPUTER_CONSOLE_UNLOCK_ACTION,
|
|
222
|
+
title: 'Unlock protected console',
|
|
223
|
+
description: 'Consume one provider-local opaque credential handle to perform and verify one console unlock without durable replay state.',
|
|
224
|
+
readOnly: false,
|
|
225
|
+
risk: 'workspace_write',
|
|
226
|
+
confirmation: 'authorization',
|
|
227
|
+
defaultTimeoutMs: DEFAULT_CONSOLE_UNLOCK_TIMEOUT_MS,
|
|
228
|
+
cancellable: true,
|
|
229
|
+
idempotent: false,
|
|
230
|
+
executionMode: 'direct_non_persistent',
|
|
231
|
+
foregroundEffect: 'required',
|
|
232
|
+
scopes: ['console.unlock'],
|
|
233
|
+
resourceClaims: [],
|
|
234
|
+
argumentsSchema: {
|
|
235
|
+
type: 'object',
|
|
236
|
+
properties: {
|
|
237
|
+
credential_handle: { type: 'string', minLength: 36, maxLength: 64, description: 'Opaque short-lived single-use handle returned by console_unlock_prepare.' },
|
|
238
|
+
},
|
|
239
|
+
required: ['credential_handle'],
|
|
240
|
+
additionalProperties: false,
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
actionId: DESKTOP_ELEMENT_OBSERVE_ACTION,
|
|
245
|
+
title: 'Observe Computer elements',
|
|
246
|
+
description: 'Observe provider-neutral semantic elements for one Forge-owned desktop target. Returned refs and target context are valid only for the returned observation epoch.',
|
|
247
|
+
readOnly: true,
|
|
248
|
+
risk: 'readonly',
|
|
249
|
+
confirmation: 'none',
|
|
250
|
+
defaultTimeoutMs: 10_000,
|
|
251
|
+
cancellable: true,
|
|
252
|
+
idempotent: true,
|
|
253
|
+
foregroundEffect: 'none',
|
|
254
|
+
scopes: ['desktop.observe'],
|
|
255
|
+
resourceClaims: [],
|
|
256
|
+
argumentsSchema: {
|
|
257
|
+
type: 'object',
|
|
258
|
+
properties: {
|
|
259
|
+
target_id: { type: 'string', description: 'Forge-owned durable Computer target id.' },
|
|
260
|
+
max_depth: { type: 'integer', minimum: 1, maximum: 20 },
|
|
261
|
+
max_nodes: { type: 'integer', minimum: 1, maximum: 5_000 },
|
|
262
|
+
include_values: { type: 'boolean' },
|
|
263
|
+
root_selector: {
|
|
264
|
+
type: 'object',
|
|
265
|
+
properties: { ref: { type: 'string' }, role: { type: 'string' }, title: { type: 'string' }, identifier: { type: 'string' } },
|
|
266
|
+
anyOf: [{ required: ['ref'] }, { required: ['role'] }, { required: ['title'] }, { required: ['identifier'] }],
|
|
267
|
+
additionalProperties: false,
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
required: ['target_id'],
|
|
271
|
+
additionalProperties: false,
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
actionId: DESKTOP_ELEMENT_ACTION_ACTION,
|
|
276
|
+
title: 'Act on observed Computer element',
|
|
277
|
+
description: 'Perform one provider-neutral semantic action against an exact element ref and observation target returned by desktop_element_observe. Stale or rebound observations fail closed.',
|
|
278
|
+
readOnly: false,
|
|
279
|
+
risk: 'workspace_write',
|
|
280
|
+
confirmation: 'authorization',
|
|
281
|
+
defaultTimeoutMs: 10_000,
|
|
282
|
+
cancellable: true,
|
|
283
|
+
idempotent: false,
|
|
284
|
+
foregroundEffect: 'none',
|
|
285
|
+
scopes: ['desktop.interact'],
|
|
286
|
+
resourceClaims: [],
|
|
287
|
+
argumentsSchema: {
|
|
288
|
+
type: 'object',
|
|
289
|
+
properties: {
|
|
290
|
+
target_id: { type: 'string', description: 'Forge-owned durable Computer target id.' },
|
|
291
|
+
target: {
|
|
292
|
+
type: 'object',
|
|
293
|
+
properties: {
|
|
294
|
+
interactionId: { type: 'string' },
|
|
295
|
+
pid: { type: 'integer' },
|
|
296
|
+
bundleIdentifier: { type: 'string' },
|
|
297
|
+
appName: { type: 'string' },
|
|
298
|
+
windowRef: { type: 'string' },
|
|
299
|
+
snapshotRevision: { type: 'integer', minimum: 1 },
|
|
300
|
+
},
|
|
301
|
+
required: ['interactionId', 'pid', 'appName', 'snapshotRevision'],
|
|
302
|
+
additionalProperties: false,
|
|
303
|
+
},
|
|
304
|
+
ref: { type: 'string' },
|
|
305
|
+
action: { type: 'string', enum: [...COMPUTER_ELEMENT_SEMANTIC_ACTIONS] },
|
|
306
|
+
value: { anyOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }, { type: 'null' }] },
|
|
307
|
+
},
|
|
308
|
+
required: ['target_id', 'target', 'ref', 'action'],
|
|
309
|
+
additionalProperties: false,
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function desktopProductPermissions(ready: boolean): AssistantPluginPermissionScope[] {
|
|
316
|
+
return [
|
|
317
|
+
{ scope: 'desktop.session', mode: 'write', description: 'Bind a desktop application target for Computer interaction.', granted: ready, required: false },
|
|
318
|
+
{ scope: 'desktop.observe', mode: 'read', description: 'Observe bounded desktop accessibility state.', granted: ready, required: false },
|
|
319
|
+
{ scope: 'desktop.interact', mode: 'write', description: 'Perform bounded semantic desktop interaction.', granted: ready, required: false },
|
|
320
|
+
{ scope: 'desktop.capture', mode: 'read', description: 'Capture an authorized desktop target.', granted: ready, required: false },
|
|
321
|
+
{ scope: 'console.unlock', mode: 'write', description: 'Prepare and consume a provider-local console unlock handle.', granted: ready, required: false },
|
|
322
|
+
];
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function desktopProductCapabilities(): AssistantPluginCapability[] {
|
|
326
|
+
return [
|
|
327
|
+
{ capabilityId: 'computer.desktop_target.v1', title: 'Desktop targets', description: 'Bind and retire Forge-owned desktop application targets.', scopes: ['desktop.session'], actions: [DESKTOP_TARGET_OPEN_ACTION, DESKTOP_TARGET_CLOSE_ACTION] },
|
|
328
|
+
{ capabilityId: 'computer.observe.v1', title: 'Computer observation', description: 'Observe bounded desktop semantic state.', scopes: ['desktop.observe'], actions: ['desktop_observe'] },
|
|
329
|
+
{ capabilityId: 'computer.input.v1', title: 'Computer input', description: 'Perform bounded semantic desktop input.', scopes: ['desktop.interact'], actions: ['desktop_press', 'desktop_select_rows', 'desktop_type_text', 'desktop_key', 'desktop_open_url'] },
|
|
330
|
+
{ capabilityId: 'computer.capture.v1', title: 'Computer capture', description: 'Capture authorized desktop state.', scopes: ['desktop.capture'], actions: ['desktop_screenshot'] },
|
|
331
|
+
{ capabilityId: COMPUTER_ELEMENT_OBSERVE_CAPABILITY, title: 'Computer element observation', description: 'Observe exact provider-neutral semantic element snapshots for a Forge-owned target.', scopes: ['desktop.observe'], actions: [DESKTOP_ELEMENT_OBSERVE_ACTION] },
|
|
332
|
+
{ capabilityId: COMPUTER_ELEMENT_ACTION_CAPABILITY, title: 'Computer element action', description: 'Act on exact observed element refs with observation-epoch fencing.', scopes: ['desktop.interact'], actions: [DESKTOP_ELEMENT_ACTION_ACTION] },
|
|
333
|
+
{ capabilityId: COMPUTER_CONSOLE_UNLOCK_CAPABILITY, title: 'Protected console unlock', description: 'Collect console credential material only inside the native provider and consume an opaque one-shot handle without durable replay state.', scopes: ['console.unlock'], actions: [COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION, COMPUTER_CONSOLE_UNLOCK_ACTION] },
|
|
334
|
+
];
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function desktopProviderManifest(context: AssistantPluginBuildContext | undefined): AssistantPluginManifest | undefined {
|
|
338
|
+
if (!context) return undefined;
|
|
339
|
+
const adapter = getExternalPluginAdapter(context.controllerHome, DESKTOP_PROVIDER_ID);
|
|
340
|
+
return adapter?.buildManifest(0, undefined, context.repoRoot, context);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function buildComputerManifest(
|
|
344
|
+
previousRevision = 0,
|
|
345
|
+
previousUpdatedAt?: string,
|
|
346
|
+
repoRoot?: string,
|
|
347
|
+
context?: AssistantPluginBuildContext,
|
|
348
|
+
): AssistantPluginManifest {
|
|
349
|
+
const browser = buildBrowserPluginManifest(previousRevision, previousUpdatedAt, repoRoot, context);
|
|
350
|
+
const desktop = desktopProviderManifest(context);
|
|
351
|
+
const platform = currentComputerPlatform();
|
|
352
|
+
const desktopSupported = platform === 'darwin';
|
|
353
|
+
const browserReady = browser.enabled && browser.health.ready;
|
|
354
|
+
const desktopReady = desktopSupported && desktop?.enabled === true && desktop.health.ready;
|
|
355
|
+
const ready = browserReady && desktopReady;
|
|
356
|
+
const partial = browserReady || desktopReady;
|
|
357
|
+
const checkedAt = new Date().toISOString();
|
|
358
|
+
return {
|
|
359
|
+
...browser,
|
|
360
|
+
pluginId: 'computer',
|
|
361
|
+
provider: 'forge-computer',
|
|
362
|
+
displayName: 'Forge Computer',
|
|
363
|
+
pluginVersion: '1.0.0',
|
|
364
|
+
authority: {
|
|
365
|
+
strategy: 'derived',
|
|
366
|
+
duplicateStateAllowed: false,
|
|
367
|
+
sourceOfTruth: [
|
|
368
|
+
...browser.authority.sourceOfTruth,
|
|
369
|
+
'controllerHome:sqlite/computer_interaction_target',
|
|
370
|
+
'controllerHome:system/plugins/external/registrations/desktop_operator.json',
|
|
371
|
+
],
|
|
372
|
+
},
|
|
373
|
+
enabled: browser.enabled || desktop?.enabled === true,
|
|
374
|
+
lifecycle: {
|
|
375
|
+
state: ready ? 'enabled' : partial ? 'degraded' : 'error',
|
|
376
|
+
reason: ready
|
|
377
|
+
? 'Computer Browser and native Desktop semantic capabilities are ready.'
|
|
378
|
+
: desktopSupported
|
|
379
|
+
? 'Computer is only partially ready; inspect Browser and native Desktop capability health.'
|
|
380
|
+
: `Computer has partial Browser-only support on ${platform}; native Desktop capabilities are unsupported on this platform.`,
|
|
381
|
+
},
|
|
382
|
+
health: {
|
|
383
|
+
state: ready ? 'ready' : partial ? 'degraded' : 'error',
|
|
384
|
+
checkedAt,
|
|
385
|
+
ready,
|
|
386
|
+
probed: browser.health.probed || desktop?.health.probed === true,
|
|
387
|
+
errors: ready ? [] : [...browser.health.errors, ...(desktopSupported ? (desktop?.health.errors ?? (desktop ? [] : ['Native Computer provider is not installed.'])) : [])],
|
|
388
|
+
warnings: [
|
|
389
|
+
...browser.health.warnings,
|
|
390
|
+
...(desktopSupported ? (desktop?.health.warnings ?? []) : [`Native Desktop Computer capabilities are unsupported on ${platform}.`]),
|
|
391
|
+
],
|
|
392
|
+
details: {
|
|
393
|
+
partial: !ready && partial,
|
|
394
|
+
browser: { ready: browserReady, state: browser.health.state },
|
|
395
|
+
desktop: { supported: desktopSupported, ready: desktopReady, state: desktop?.health.state ?? (desktopSupported ? 'not_installed' : 'unsupported'), provider: DESKTOP_PROVIDER_ID },
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
permissions: [...browser.permissions, ...desktopProductPermissions(desktopReady)],
|
|
399
|
+
capabilities: [...browser.capabilities, ...desktopProductCapabilities()],
|
|
400
|
+
actions: [...browser.actions, ...desktopProductActions()],
|
|
401
|
+
updatedAt: previousUpdatedAt ?? checkedAt,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function isDesktopProductAction(actionId: string): boolean {
|
|
406
|
+
return DESKTOP_PRODUCT_ACTION_IDS.has(actionId);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function optionalDesktopProvider(input: AssistantPluginActionExecutionInput): AssistantPluginAdapter | undefined {
|
|
410
|
+
return getExternalPluginAdapter(input.controllerHome, DESKTOP_PROVIDER_ID);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function desktopProvider(input: AssistantPluginActionExecutionInput): AssistantPluginAdapter {
|
|
414
|
+
const platform = currentComputerPlatform();
|
|
415
|
+
if (platform !== 'darwin') {
|
|
416
|
+
throw new AssistantPluginError(
|
|
417
|
+
'PLUGIN_COMPUTER_DESKTOP_PLATFORM_UNSUPPORTED',
|
|
418
|
+
`Computer native Desktop capabilities are unavailable on ${platform} until a platform provider is installed.`,
|
|
419
|
+
{ retryable: false, details: { platform, actionId: input.actionId } },
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
const provider = optionalDesktopProvider(input);
|
|
423
|
+
if (!provider) {
|
|
424
|
+
throw new AssistantPluginError(
|
|
425
|
+
'PLUGIN_COMPUTER_DESKTOP_PROVIDER_UNAVAILABLE',
|
|
426
|
+
'Computer native Desktop capabilities require the registered platform provider.',
|
|
427
|
+
{ retryable: true, details: { providerId: DESKTOP_PROVIDER_ID, actionId: input.actionId } },
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
return provider;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function firstString(value: unknown, ...keys: string[]): string | undefined {
|
|
434
|
+
if (!value || typeof value !== 'object') return undefined;
|
|
435
|
+
const record = value as Record<string, unknown>;
|
|
436
|
+
for (const key of keys) {
|
|
437
|
+
const candidate = record[key];
|
|
438
|
+
if (typeof candidate === 'string' && candidate.trim()) return candidate.trim();
|
|
439
|
+
}
|
|
440
|
+
return undefined;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function stableIdentityFromArgs(args: Record<string, unknown>): ComputerApplicationStableIdentity {
|
|
444
|
+
const bundleId = typeof args.bundle_id === 'string' ? args.bundle_id.trim() : '';
|
|
445
|
+
const appName = typeof args.app_name === 'string' ? args.app_name.trim() : '';
|
|
446
|
+
if (!bundleId && !appName) throw new AssistantPluginError('PLUGIN_COMPUTER_TARGET_IDENTITY_REQUIRED', 'Desktop target requires bundle_id or app_name.', { retryable: false });
|
|
447
|
+
return { ...(bundleId ? { bundleId } : {}), ...(appName ? { appName } : {}) };
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function targetMatchesProviderSession(target: ComputerApplicationTarget, session: Record<string, unknown>): boolean {
|
|
451
|
+
const bundleId = firstString(session, 'bundleIdentifier', 'bundle_id');
|
|
452
|
+
const appName = firstString(session, 'appName', 'app_name');
|
|
453
|
+
if (target.stableIdentity.bundleId) return bundleId === target.stableIdentity.bundleId;
|
|
454
|
+
return Boolean(target.stableIdentity.appName && appName === target.stableIdentity.appName);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function providerInput(
|
|
458
|
+
input: AssistantPluginActionExecutionInput,
|
|
459
|
+
actionId: string,
|
|
460
|
+
args: Record<string, unknown>,
|
|
461
|
+
suffix = actionId,
|
|
462
|
+
): AssistantPluginActionExecutionInput {
|
|
463
|
+
return { ...input, pluginId: DESKTOP_PROVIDER_ID, actionId, args, requestId: `${input.requestId}:${suffix}` };
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function providerSessionId(result: Record<string, unknown>): string {
|
|
467
|
+
const interactionId = firstString(result, 'interactionId', 'interaction_id');
|
|
468
|
+
if (!interactionId) throw new AssistantPluginError('PLUGIN_COMPUTER_PROVIDER_BINDING_MISSING', 'Native Computer provider did not return a live interaction binding.', { retryable: true });
|
|
469
|
+
return interactionId;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function desktopComputerRequest(
|
|
473
|
+
actionId: string,
|
|
474
|
+
args: Record<string, unknown>,
|
|
475
|
+
interactionId?: string,
|
|
476
|
+
): ComputerRuntimeExecutionRequest {
|
|
477
|
+
const requireInteractionId = (): string => {
|
|
478
|
+
if (interactionId) return interactionId;
|
|
479
|
+
throw new AssistantPluginError('PLUGIN_COMPUTER_PROVIDER_BINDING_MISSING', `${actionId} requires a live provider interaction binding.`, { retryable: true });
|
|
480
|
+
};
|
|
481
|
+
if (actionId === 'desktop_observe') {
|
|
482
|
+
return {
|
|
483
|
+
capability: COMPUTER_OBSERVE_CAPABILITY,
|
|
484
|
+
action: 'observe',
|
|
485
|
+
interactionId: requireInteractionId(),
|
|
486
|
+
...(typeof args.max_depth === 'number' ? { maxDepth: args.max_depth } : {}),
|
|
487
|
+
...(typeof args.max_nodes === 'number' ? { maxNodes: args.max_nodes } : {}),
|
|
488
|
+
...(typeof args.include_values === 'boolean' ? { includeValues: args.include_values } : {}),
|
|
489
|
+
...(typeof args.include_actions === 'boolean' ? { includeActions: args.include_actions } : {}),
|
|
490
|
+
...(typeof args.include_windows === 'boolean' ? { includeWindows: args.include_windows } : {}),
|
|
491
|
+
...(args.root_selector && typeof args.root_selector === 'object' ? { rootSelector: args.root_selector as ComputerSemanticSelector } : {}),
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
if (actionId === 'desktop_press') {
|
|
495
|
+
return {
|
|
496
|
+
capability: COMPUTER_INPUT_CAPABILITY,
|
|
497
|
+
action: 'press',
|
|
498
|
+
interactionId: requireInteractionId(),
|
|
499
|
+
selector: args.selector as ComputerSemanticSelector,
|
|
500
|
+
...(typeof args.semantic_action === 'string' ? { semanticAction: args.semantic_action } : {}),
|
|
501
|
+
} as ComputerRuntimeExecutionRequest;
|
|
502
|
+
}
|
|
503
|
+
if (actionId === 'desktop_select_rows') {
|
|
504
|
+
return {
|
|
505
|
+
capability: COMPUTER_INPUT_CAPABILITY,
|
|
506
|
+
action: 'select_rows',
|
|
507
|
+
interactionId: requireInteractionId(),
|
|
508
|
+
selector: args.selector as ComputerSemanticSelector,
|
|
509
|
+
startIndex: args.start_index as number,
|
|
510
|
+
...(typeof args.end_index === 'number' ? { endIndex: args.end_index } : {}),
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
if (actionId === 'desktop_type_text') {
|
|
514
|
+
return {
|
|
515
|
+
capability: COMPUTER_INPUT_CAPABILITY,
|
|
516
|
+
action: 'type_text',
|
|
517
|
+
interactionId: requireInteractionId(),
|
|
518
|
+
selector: args.selector as ComputerSemanticSelector,
|
|
519
|
+
text: String(args.text ?? ''),
|
|
520
|
+
...(typeof args.replace === 'boolean' ? { replace: args.replace } : {}),
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
if (actionId === 'desktop_key') {
|
|
524
|
+
return {
|
|
525
|
+
capability: COMPUTER_INPUT_CAPABILITY,
|
|
526
|
+
action: 'key',
|
|
527
|
+
interactionId: requireInteractionId(),
|
|
528
|
+
keys: Array.isArray(args.keys) ? args.keys.filter((value): value is string => typeof value === 'string') : [],
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
if (actionId === 'desktop_open_url') {
|
|
532
|
+
return { capability: COMPUTER_INPUT_CAPABILITY, action: 'open_url', url: String(args.url ?? '') };
|
|
533
|
+
}
|
|
534
|
+
if (actionId === 'desktop_screenshot') {
|
|
535
|
+
return {
|
|
536
|
+
capability: COMPUTER_CAPTURE_CAPABILITY,
|
|
537
|
+
action: 'screenshot',
|
|
538
|
+
...(args.scope === 'display' || args.scope === 'window' ? { scope: args.scope } : {}),
|
|
539
|
+
...(interactionId ? { interactionId } : {}),
|
|
540
|
+
...(typeof args.window_id === 'number' ? { windowId: args.window_id } : {}),
|
|
541
|
+
...(typeof args.label === 'string' ? { label: args.label } : {}),
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
if (actionId === DESKTOP_ELEMENT_OBSERVE_ACTION) {
|
|
545
|
+
return {
|
|
546
|
+
capability: COMPUTER_ELEMENT_OBSERVE_CAPABILITY,
|
|
547
|
+
action: 'observe_elements',
|
|
548
|
+
interactionId: requireInteractionId(),
|
|
549
|
+
...(typeof args.max_depth === 'number' ? { maxDepth: args.max_depth } : {}),
|
|
550
|
+
...(typeof args.max_nodes === 'number' ? { maxNodes: args.max_nodes } : {}),
|
|
551
|
+
...(typeof args.include_values === 'boolean' ? { includeValues: args.include_values } : {}),
|
|
552
|
+
...(args.root_selector && typeof args.root_selector === 'object' ? { rootSelector: args.root_selector as ComputerSemanticSelector } : {}),
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
if (actionId === DESKTOP_ELEMENT_ACTION_ACTION) {
|
|
556
|
+
const semanticAction = typeof args.action === 'string' && (COMPUTER_ELEMENT_SEMANTIC_ACTIONS as readonly string[]).includes(args.action)
|
|
557
|
+
? args.action as ComputerElementSemanticAction
|
|
558
|
+
: undefined;
|
|
559
|
+
if (!semanticAction || !args.target || typeof args.target !== 'object' || typeof args.ref !== 'string') {
|
|
560
|
+
throw new AssistantPluginError('PLUGIN_COMPUTER_ELEMENT_ACTION_INVALID', 'desktop_element_action requires target, ref, and one declared semantic action.', { retryable: false });
|
|
561
|
+
}
|
|
562
|
+
return {
|
|
563
|
+
capability: COMPUTER_ELEMENT_ACTION_CAPABILITY,
|
|
564
|
+
action: semanticAction,
|
|
565
|
+
target: args.target as ComputerElementTarget,
|
|
566
|
+
ref: args.ref,
|
|
567
|
+
...(args.value !== undefined ? { value: args.value } : {}),
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
throw new AssistantPluginError('PLUGIN_COMPUTER_DESKTOP_ACTION_UNSUPPORTED', `Unsupported retained Desktop Computer action ${actionId}.`, { retryable: false });
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
async function executeRetainedDesktopAction(
|
|
574
|
+
input: AssistantPluginActionExecutionInput,
|
|
575
|
+
args: Record<string, unknown>,
|
|
576
|
+
interactionId?: string,
|
|
577
|
+
): Promise<Record<string, unknown>> {
|
|
578
|
+
const descriptor = desktopProductActions().find((action) => action.actionId === input.actionId);
|
|
579
|
+
if (!descriptor) throw new AssistantPluginError('PLUGIN_COMPUTER_DESKTOP_ACTION_UNSUPPORTED', `Computer product action ${input.actionId} is not registered.`, { retryable: false });
|
|
580
|
+
return await executeRuntimeComputer(
|
|
581
|
+
desktopComputerRequest(input.actionId, args, interactionId),
|
|
582
|
+
input.timeoutMs ?? descriptor.defaultTimeoutMs ?? 30_000,
|
|
583
|
+
input.controllerHome,
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
function isMissingProviderSessionFailure(error: unknown): error is AssistantPluginError {
|
|
588
|
+
return error instanceof AssistantPluginError
|
|
589
|
+
&& error.code === 'SESSION_NOT_FOUND'
|
|
590
|
+
&& error.effectOutcome === 'failed';
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
async function rebindProviderSession(
|
|
594
|
+
input: AssistantPluginActionExecutionInput,
|
|
595
|
+
lease: ComputerApplicationTargetLease,
|
|
596
|
+
provider: AssistantPluginAdapter,
|
|
597
|
+
): Promise<string> {
|
|
598
|
+
const target = lease.current();
|
|
599
|
+
const rebound = await provider.executeAction(providerInput(input, 'desktop_session_open', {
|
|
600
|
+
...(target.stableIdentity.bundleId ? { bundle_id: target.stableIdentity.bundleId } : { app_name: target.stableIdentity.appName }),
|
|
601
|
+
launch: false,
|
|
602
|
+
activate: false,
|
|
603
|
+
}, 'binding-reopen'));
|
|
604
|
+
const interactionId = providerSessionId(rebound);
|
|
605
|
+
if (!targetMatchesProviderSession(target, rebound)) {
|
|
606
|
+
try {
|
|
607
|
+
await provider.executeAction(providerInput(input, 'desktop_session_close', { interaction_id: interactionId }, 'binding-reopen-identity-compensate'));
|
|
608
|
+
} catch (cleanupError) {
|
|
609
|
+
throw new AssistantPluginError(
|
|
610
|
+
'PLUGIN_COMPUTER_TARGET_REBIND_IDENTITY_CLEANUP_UNKNOWN',
|
|
611
|
+
'Computer target rebind returned an unverifiable application identity and provider-session cleanup could not be confirmed.',
|
|
612
|
+
{ retryable: false, details: { targetId: target.targetId, cleanupCause: cleanupError instanceof Error ? cleanupError.message : String(cleanupError) } },
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
throw new AssistantPluginError(
|
|
616
|
+
'PLUGIN_COMPUTER_TARGET_REBIND_IDENTITY_MISMATCH',
|
|
617
|
+
'Computer target rebind did not return the durable target application identity.',
|
|
618
|
+
{ retryable: false, details: { targetId: target.targetId, stableIdentity: target.stableIdentity } },
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
lease.bind({
|
|
622
|
+
providerId: DESKTOP_PROVIDER_ID,
|
|
623
|
+
providerSessionId: interactionId,
|
|
624
|
+
observedAt: new Date().toISOString(),
|
|
625
|
+
});
|
|
626
|
+
return interactionId;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
async function ensureProviderBinding(
|
|
630
|
+
input: AssistantPluginActionExecutionInput,
|
|
631
|
+
lease: ComputerApplicationTargetLease,
|
|
632
|
+
provider: AssistantPluginAdapter,
|
|
633
|
+
): Promise<string> {
|
|
634
|
+
const target = lease.current();
|
|
635
|
+
if (target.providerBinding?.providerId === DESKTOP_PROVIDER_ID) {
|
|
636
|
+
return target.providerBinding.providerSessionId;
|
|
637
|
+
}
|
|
638
|
+
return rebindProviderSession(input, lease, provider);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function stableIdentityFromProviderResult(
|
|
642
|
+
result: Record<string, unknown>,
|
|
643
|
+
requested: ComputerApplicationStableIdentity,
|
|
644
|
+
): ComputerApplicationStableIdentity {
|
|
645
|
+
const returnedBundleId = firstString(result, 'bundleIdentifier', 'bundle_id');
|
|
646
|
+
const returnedAppName = firstString(result, 'appName', 'app_name');
|
|
647
|
+
if (requested.bundleId && returnedBundleId !== requested.bundleId) {
|
|
648
|
+
throw new AssistantPluginError(
|
|
649
|
+
returnedBundleId ? 'PLUGIN_COMPUTER_TARGET_IDENTITY_MISMATCH' : 'PLUGIN_COMPUTER_TARGET_IDENTITY_UNVERIFIED',
|
|
650
|
+
returnedBundleId
|
|
651
|
+
? 'Native Computer provider opened a different application bundle than the authorized target.'
|
|
652
|
+
: 'Native Computer provider did not return the application bundle required to verify the authorized target.',
|
|
653
|
+
{ retryable: false, details: { requestedBundleId: requested.bundleId, returnedBundleId } },
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
if (!requested.bundleId && requested.appName && returnedAppName !== requested.appName) {
|
|
657
|
+
throw new AssistantPluginError(
|
|
658
|
+
returnedAppName ? 'PLUGIN_COMPUTER_TARGET_IDENTITY_MISMATCH' : 'PLUGIN_COMPUTER_TARGET_IDENTITY_UNVERIFIED',
|
|
659
|
+
returnedAppName
|
|
660
|
+
? 'Native Computer provider opened a different application name than the authorized target.'
|
|
661
|
+
: 'Native Computer provider did not return the application name required to verify the authorized target.',
|
|
662
|
+
{ retryable: false, details: { requestedAppName: requested.appName, returnedAppName } },
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
return {
|
|
666
|
+
...(returnedBundleId ? { bundleId: returnedBundleId } : requested.bundleId ? { bundleId: requested.bundleId } : {}),
|
|
667
|
+
...(returnedAppName ? { appName: returnedAppName } : requested.appName ? { appName: requested.appName } : {}),
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
async function openDesktopTarget(
|
|
672
|
+
input: AssistantPluginActionExecutionInput,
|
|
673
|
+
provider: AssistantPluginAdapter,
|
|
674
|
+
): Promise<Record<string, unknown>> {
|
|
675
|
+
const opened = await provider.executeAction(providerInput(input, 'desktop_session_open', input.args, 'target-open'));
|
|
676
|
+
const interactionId = providerSessionId(opened);
|
|
677
|
+
const requested = stableIdentityFromArgs(input.args);
|
|
678
|
+
let stableIdentity: ComputerApplicationStableIdentity;
|
|
679
|
+
try {
|
|
680
|
+
stableIdentity = stableIdentityFromProviderResult(opened, requested);
|
|
681
|
+
} catch (error) {
|
|
682
|
+
try {
|
|
683
|
+
await provider.executeAction(providerInput(input, 'desktop_session_close', { interaction_id: interactionId }, 'target-open-identity-compensate'));
|
|
684
|
+
} catch (cleanupError) {
|
|
685
|
+
throw new AssistantPluginError('PLUGIN_COMPUTER_TARGET_IDENTITY_MISMATCH_CLEANUP_UNKNOWN', 'Computer target identity drift was detected but provider-session cleanup could not be confirmed.', {
|
|
686
|
+
retryable: false,
|
|
687
|
+
details: { cause: error instanceof Error ? error.message : String(error), cleanupCause: cleanupError instanceof Error ? cleanupError.message : String(cleanupError) },
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
throw error;
|
|
691
|
+
}
|
|
692
|
+
try {
|
|
693
|
+
const target = computerTargetAuthority.create(input.controllerHome, {
|
|
694
|
+
stableIdentity,
|
|
695
|
+
providerBinding: { providerId: DESKTOP_PROVIDER_ID, providerSessionId: interactionId, observedAt: new Date().toISOString() },
|
|
696
|
+
});
|
|
697
|
+
return {
|
|
698
|
+
targetId: target.targetId,
|
|
699
|
+
kind: target.kind,
|
|
700
|
+
stableIdentity: target.stableIdentity,
|
|
701
|
+
providerBound: true,
|
|
702
|
+
};
|
|
703
|
+
} catch (error) {
|
|
704
|
+
try {
|
|
705
|
+
await provider.executeAction(providerInput(input, 'desktop_session_close', { interaction_id: interactionId }, 'target-open-compensate'));
|
|
706
|
+
} catch (cleanupError) {
|
|
707
|
+
throw new AssistantPluginError('PLUGIN_COMPUTER_TARGET_PERSIST_FAILED', 'Computer target persistence failed and provider-session cleanup could not be confirmed.', {
|
|
708
|
+
retryable: false,
|
|
709
|
+
details: { cause: error instanceof Error ? error.message : String(error), cleanupCause: cleanupError instanceof Error ? cleanupError.message : String(cleanupError) },
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
throw error;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
async function closeDesktopTarget(
|
|
717
|
+
input: AssistantPluginActionExecutionInput,
|
|
718
|
+
provider: AssistantPluginAdapter | undefined,
|
|
719
|
+
): Promise<Record<string, unknown>> {
|
|
720
|
+
const targetId = typeof input.args.target_id === 'string' ? input.args.target_id.trim() : '';
|
|
721
|
+
if (!targetId) throw new AssistantPluginError('PLUGIN_COMPUTER_TARGET_REQUIRED', 'desktop_target_close requires target_id.', { retryable: false });
|
|
722
|
+
return computerTargetAuthority.withLease(input.controllerHome, targetId, async (lease) => {
|
|
723
|
+
const target = lease.current();
|
|
724
|
+
if (target.providerBinding) {
|
|
725
|
+
if (target.providerBinding.providerId !== DESKTOP_PROVIDER_ID) {
|
|
726
|
+
throw new AssistantPluginError(
|
|
727
|
+
'PLUGIN_COMPUTER_TARGET_PROVIDER_MISMATCH',
|
|
728
|
+
'Computer target is bound to a different provider and cannot be retired through the current Desktop provider.',
|
|
729
|
+
{ retryable: false, details: { targetId, providerId: target.providerBinding.providerId, expectedProviderId: DESKTOP_PROVIDER_ID } },
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
if (provider) {
|
|
733
|
+
await provider.executeAction(providerInput(input, 'desktop_session_close', { interaction_id: target.providerBinding.providerSessionId }, 'target-close-provider'));
|
|
734
|
+
}
|
|
735
|
+
// A missing registration is authoritative absence only because provider uninstall
|
|
736
|
+
// must stop/remove its native lifecycle before the registration is deleted.
|
|
737
|
+
}
|
|
738
|
+
const retired = lease.tombstone();
|
|
739
|
+
return { targetId: retired.targetId, retired: true, stableIdentity: retired.stableIdentity };
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
async function executeDesktopSemanticAction(
|
|
744
|
+
input: AssistantPluginActionExecutionInput,
|
|
745
|
+
provider: AssistantPluginAdapter,
|
|
746
|
+
): Promise<Record<string, unknown>> {
|
|
747
|
+
if (input.actionId === 'desktop_open_url') {
|
|
748
|
+
return executeRetainedDesktopAction(input, input.args);
|
|
749
|
+
}
|
|
750
|
+
const targetId = typeof input.args.target_id === 'string' ? input.args.target_id.trim() : '';
|
|
751
|
+
if (input.actionId === DESKTOP_ELEMENT_ACTION_ACTION) {
|
|
752
|
+
if (!targetId) throw new AssistantPluginError('PLUGIN_COMPUTER_TARGET_REQUIRED', 'desktop_element_action requires target_id.', { retryable: false });
|
|
753
|
+
return computerTargetAuthority.withLease(input.controllerHome, targetId, async (lease) => {
|
|
754
|
+
const current = lease.current();
|
|
755
|
+
const observedTarget = input.args.target && typeof input.args.target === 'object' ? input.args.target as Record<string, unknown> : undefined;
|
|
756
|
+
const observedInteractionId = typeof observedTarget?.interactionId === 'string' ? observedTarget.interactionId : '';
|
|
757
|
+
const binding = current.providerBinding;
|
|
758
|
+
if (!binding || binding.providerId !== DESKTOP_PROVIDER_ID || !observedInteractionId || binding.providerSessionId !== observedInteractionId) {
|
|
759
|
+
throw new AssistantPluginError(
|
|
760
|
+
'COMPUTER_ELEMENT_OBSERVATION_STALE',
|
|
761
|
+
'Observed element target no longer matches the current provider binding. Re-observe the Forge Computer target instead of replaying an old element ref after rebind.',
|
|
762
|
+
{ retryable: true, details: { targetId, providerBound: Boolean(binding), observedInteractionId: observedInteractionId || undefined } },
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
const { target_id: _targetId, ...rest } = input.args;
|
|
766
|
+
return await executeRetainedDesktopAction(input, rest, binding.providerSessionId);
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
if (!targetId) {
|
|
770
|
+
if (input.actionId === 'desktop_screenshot') {
|
|
771
|
+
return executeRetainedDesktopAction(input, input.args);
|
|
772
|
+
}
|
|
773
|
+
throw new AssistantPluginError('PLUGIN_COMPUTER_TARGET_REQUIRED', `${input.actionId} requires target_id.`, { retryable: false });
|
|
774
|
+
}
|
|
775
|
+
return computerTargetAuthority.withLease(input.controllerHome, targetId, async (lease) => {
|
|
776
|
+
let interactionId = await ensureProviderBinding(input, lease, provider);
|
|
777
|
+
const { target_id: _targetId, ...rest } = input.args;
|
|
778
|
+
const dispatch = () => executeRetainedDesktopAction(input, rest, interactionId);
|
|
779
|
+
try {
|
|
780
|
+
return await dispatch();
|
|
781
|
+
} catch (error) {
|
|
782
|
+
// SESSION_NOT_FOUND is emitted by Desktop Operator before UI/input dispatch.
|
|
783
|
+
// It is the only provider failure that permits one binding rebuild + retry.
|
|
784
|
+
// Transport/timeout/outcome-unknown failures remain fenced and are never replayed.
|
|
785
|
+
if (!isMissingProviderSessionFailure(error)) throw error;
|
|
786
|
+
interactionId = await rebindProviderSession(input, lease, provider);
|
|
787
|
+
return await dispatch();
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
function targetAuthorization(identity: ComputerApplicationStableIdentity): AssistantPluginAuthorizationContext {
|
|
793
|
+
const id = identity.bundleId ?? `app-name:${identity.appName}`;
|
|
794
|
+
const identityFingerprint = createHash('sha256').update(JSON.stringify(identity)).digest('hex');
|
|
795
|
+
return { target: { kind: 'desktop-application', id, identityFingerprint } };
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
async function resolveDesktopAuthorizationContext(input: AssistantPluginActionExecutionInput): Promise<AssistantPluginAuthorizationContext | undefined> {
|
|
799
|
+
if (input.actionId === COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION || input.actionId === COMPUTER_CONSOLE_UNLOCK_ACTION) return undefined;
|
|
800
|
+
if (input.actionId === DESKTOP_TARGET_OPEN_ACTION) return targetAuthorization(stableIdentityFromArgs(input.args));
|
|
801
|
+
const targetId = typeof input.args.target_id === 'string' ? input.args.target_id.trim() : '';
|
|
802
|
+
if (targetId) return targetAuthorization(computerTargetAuthority.require(input.controllerHome, targetId).stableIdentity);
|
|
803
|
+
const provider = desktopProvider(input);
|
|
804
|
+
return provider.resolveAuthorizationContext?.(providerInput(input, input.actionId, input.args));
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
export const computerPluginAdapter: AssistantPluginAdapter = {
|
|
808
|
+
pluginId: 'computer',
|
|
809
|
+
scope: 'controller_with_repository_overlay',
|
|
810
|
+
buildManifest: buildComputerManifest,
|
|
811
|
+
async resolveAuthorizationContext(input) {
|
|
812
|
+
if (!isDesktopProductAction(input.actionId)) {
|
|
813
|
+
return resolveBrowserPluginAuthorizationContext({ ...input, pluginId: 'browser' });
|
|
814
|
+
}
|
|
815
|
+
return resolveDesktopAuthorizationContext(input);
|
|
816
|
+
},
|
|
817
|
+
async executeAction(input) {
|
|
818
|
+
if (!isDesktopProductAction(input.actionId)) {
|
|
819
|
+
return executeBrowserPluginAction({ ...input, pluginId: 'browser' });
|
|
820
|
+
}
|
|
821
|
+
if (input.actionId === COMPUTER_CONSOLE_UNLOCK_PREPARE_ACTION) {
|
|
822
|
+
return executeProtectedConsoleUnlockPreparation({ confirmAuthorization: true, timeoutMs: input.timeoutMs }, input.controllerHome);
|
|
823
|
+
}
|
|
824
|
+
if (input.actionId === COMPUTER_CONSOLE_UNLOCK_ACTION) {
|
|
825
|
+
return executeProtectedConsoleUnlockInvocation({
|
|
826
|
+
credentialHandle: typeof input.args.credential_handle === 'string' ? input.args.credential_handle : '',
|
|
827
|
+
confirmAuthorization: true,
|
|
828
|
+
timeoutMs: input.timeoutMs,
|
|
829
|
+
}, input.controllerHome);
|
|
830
|
+
}
|
|
831
|
+
if (input.actionId === DESKTOP_TARGET_CLOSE_ACTION) return closeDesktopTarget(input, optionalDesktopProvider(input));
|
|
832
|
+
const provider = desktopProvider(input);
|
|
833
|
+
if (input.actionId === DESKTOP_TARGET_OPEN_ACTION) return openDesktopTarget(input, provider);
|
|
834
|
+
return executeDesktopSemanticAction(input, provider);
|
|
835
|
+
},
|
|
836
|
+
shouldRefreshManifestAfterAction(actionId) {
|
|
837
|
+
return actionId === 'configure';
|
|
838
|
+
},
|
|
839
|
+
};
|