@moretea-labs/forge 1.8.0 → 1.8.1
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 +70 -7
- package/CHANGELOG.md +14 -0
- package/CLAUDE.md +17 -2
- package/CONTRIBUTING.md +3 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/adapters/chatgpt/browser-delivery-host.ts +7 -1
- package/adapters/chatgpt/browser-delivery-runtime.ts +529 -56
- package/adapters/chatgpt/controller-binding-store.ts +101 -22
- package/adapters/chatgpt/controller-round-host.ts +15 -25
- package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
- package/adapters/chatgpt/provider-delivery.ts +228 -1
- package/adapters/chatgpt/work-conversation-binding-store.ts +79 -53
- package/adapters/computer/chatgpt-extension-target.ts +463 -0
- package/adapters/computer/chatgpt-target-router.ts +103 -0
- package/adapters/computer/chrome-extension/background.js +385 -0
- package/adapters/computer/chrome-extension/content.js +378 -0
- package/adapters/computer/chrome-extension/core.js +24 -0
- package/adapters/computer/chrome-extension/manifest.json +30 -0
- package/adapters/computer/desktop-operator-discovery.ts +11 -31
- package/adapters/computer/interaction-target-authority.ts +142 -18
- package/adapters/mcp/auth.ts +0 -1
- package/adapters/mcp/instructions.ts +5 -4
- package/adapters/mcp/multi-repository.ts +3 -19
- package/adapters/mcp/oauth.ts +73 -0
- package/adapters/mcp/paths.ts +4 -1
- package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
- package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
- package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
- package/adapters/mcp/runtime-gateway/context-adapter.ts +411 -73
- package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
- package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
- package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
- package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
- package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
- package/adapters/mcp/runtime-gateway/execution-tools.ts +8 -42
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
- package/adapters/mcp/runtime-gateway/plugin-adapter.ts +117 -45
- package/adapters/mcp/runtime-gateway/process-tools.ts +190 -22
- package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
- package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
- package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
- package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
- package/adapters/mcp/runtime-gateway/router.ts +18 -504
- package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +14 -65
- package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +113 -173
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +15 -5
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +1 -0
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +358 -266
- package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +261 -3122
- package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
- package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
- package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
- package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
- package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
- package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
- package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
- package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
- package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
- package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
- package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
- package/adapters/mcp/server.ts +67 -23
- package/adapters/mcp/setup.ts +1 -3
- package/adapters/mcp/tool-mapping/legacy-tool-service.ts +44 -170
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +4 -9
- package/adapters/mcp/tool-mapping/repository-tools.ts +133 -142
- package/adapters/mcp/toolset-names.ts +5 -0
- package/adapters/mcp/toolset.ts +6 -5
- package/adapters/mcp/transports/http-observation.ts +365 -0
- package/adapters/mcp/transports/http.ts +154 -677
- package/adapters/mcp/transports/oauth-http.ts +322 -0
- package/adapters/mcp/transports/session-registry.ts +6 -0
- package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
- package/assets/plugin-registry.v1.json +6 -4
- package/assets/reference-configs/agentic-development-flow.md +25 -0
- package/assets/reference-configs/global-working-rules.md +19 -0
- package/assets/skill-version.json +2 -2
- package/docs/architecture/CURRENT.md +111 -41
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
- package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
- package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
- package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
- package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
- package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
- package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
- package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
- package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
- package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
- package/docs/architecture/domains/verification.md +1 -0
- package/docs/architecture/domains/workflow-engine.md +6 -0
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/forge-plugin-management.md +2 -2
- package/docs/operations/controller-performance-and-502.md +17 -0
- package/docs/operations/controller-reliability-runbook.md +2 -2
- package/docs/operations/features.md +1 -1
- package/docs/operations/features.zh-CN.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +2 -0
- package/docs/operations/releasing.md +2 -0
- package/docs/operations/standalone-disaster-recovery.md +14 -6
- package/docs/wiki/Implementation.md +1 -1
- package/package.json +25 -14
- package/packages/kernel/cognition/api/index.ts +6 -0
- package/packages/kernel/cognition/application/activation-service.ts +451 -0
- package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
- package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
- package/packages/kernel/cognition/application/memory-service.ts +64 -0
- package/packages/kernel/cognition/domain/learning.ts +106 -0
- package/packages/kernel/cognition/domain/memory.ts +254 -0
- package/packages/kernel/controller/api/index.ts +1 -0
- package/packages/kernel/controller/application/continuation-service.ts +281 -0
- package/packages/kernel/controller/application/controller-round-service.ts +12 -0
- package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
- package/packages/kernel/controller/domain/controller-round.ts +4 -1
- package/packages/kernel/controller/domain/execution-quality.ts +3 -1
- package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
- package/packages/kernel/controller/infrastructure/controller-session-store.ts +297 -71
- package/packages/kernel/controller/ports/controller-host.ts +2 -0
- package/packages/kernel/identity/api/index.ts +10 -0
- package/packages/kernel/identity/domain/activity-projection.ts +43 -0
- package/packages/kernel/identity/domain/capability-broker.ts +60 -0
- package/packages/kernel/identity/domain/grant.ts +72 -0
- package/packages/kernel/identity/domain/owned-resource.ts +116 -0
- package/packages/kernel/identity/domain/user-request.ts +93 -0
- package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
- package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
- package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
- package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
- package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
- package/packages/kernel/scheduler/api/index.ts +0 -2
- package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
- package/packages/kernel/scheduler/application/settlement.ts +0 -15
- package/packages/kernel/scheduler/domain/schedule.ts +87 -0
- package/packages/kernel/scheduler/infrastructure/schedule-store.ts +153 -133
- package/packages/kernel/work/api/index.ts +3 -2
- package/packages/kernel/work/application/work-service.ts +17 -42
- package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
- package/packages/kernel/work/domain/engineering-design.ts +10 -5
- package/packages/kernel/work/domain/engineering-profile.ts +8 -12
- package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
- package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
- package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
- package/packages/kernel/work/domain/implementation-review.ts +14 -331
- package/packages/kernel/work/domain/objective-graph.ts +119 -0
- package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
- package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
- package/packages/kernel/work/domain/state-machine.ts +25 -63
- package/packages/kernel/work/domain/types.ts +57 -51
- package/packages/kernel/work/infrastructure/work-contract-store.ts +819 -728
- package/packages/kernel/work/ports/work-contract-store.ts +5 -2
- package/packages/plugin-runtime/browser/session-authority.ts +2 -1
- package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
- package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
- package/packages/plugin-runtime/computer/index.ts +2 -0
- package/packages/plugin-runtime/computer/target-authority.ts +26 -1
- package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
- package/packages/protocols/computer/contract.ts +27 -1
- package/scripts/activate-source-baseline.ts +7 -9
- package/scripts/canary-controller-semantic-wait.ts +12 -24
- package/scripts/check-mcp-compatibility.ts +48 -136
- package/scripts/check-runtime-architecture.mjs +622 -217
- package/scripts/forge-local-recovery-helper.mjs +93 -15
- package/scripts/lib/project-init-lib.sh +3 -0
- package/scripts/open-source-audit-allowlist.txt +1 -2
- package/scripts/run-bounded-command.mjs +5 -0
- package/scripts/run-governed-gate.ts +0 -1
- package/scripts/run-mobile-monitor-bridge.ts +0 -1
- package/scripts/smoke-control-plane-failure-domain.ts +94 -0
- package/scripts/smoke-mcp-http-runtime.ts +5 -0
- package/scripts/smoke-runtime-recovery.ts +12 -43
- package/scripts/smoke-schedule-engine.ts +23 -15
- package/scripts/smoke-unattended-transport-recovery.ts +223 -0
- package/scripts/smoke-user-request-continuation-restart.ts +232 -0
- package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
- package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
- package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
- package/scripts/smoke-workflow-supervisor.ts +103 -0
- package/scripts/verify-forge-runtime.sh +2 -1
- package/src/cli/agent-jobs/executor-health.ts +11 -34
- package/src/cli/agent-jobs/integration.ts +18 -49
- package/src/cli/agent-jobs/job-manager.ts +7 -3
- package/src/cli/commands/brain-assistant.ts +27 -13
- package/src/cli/commands/brain.ts +13 -15
- package/src/cli/commands/chatgpt.ts +1 -163
- package/src/cli/commands/recovery.ts +135 -121
- package/src/cli/commands/runtime.ts +3 -3
- package/src/cli/commands/setup-profile.ts +8 -0
- package/src/cli/controller/check-runner.ts +13 -2
- package/src/cli/controller/completion-backlog.ts +3 -3
- package/src/cli/controller/completion-orchestrator.ts +4 -43
- package/src/cli/controller/completion-target.ts +3 -72
- package/src/cli/controller/context/source-materializer.ts +81 -100
- package/src/cli/controller/context-pack.ts +10 -8
- package/src/cli/controller/execution-completion.ts +4 -7
- package/src/cli/controller/execution-policy.ts +36 -153
- package/src/cli/controller/governance.ts +2 -3
- package/src/cli/controller/issue-store.ts +4 -99
- package/src/cli/controller/launch-agents.ts +59 -18
- package/src/cli/controller/operational-plan.ts +24 -51
- package/src/cli/controller/runtime-config.ts +5 -1
- package/src/cli/controller/stuck-state-migration.ts +2 -3
- package/src/cli/controller/systemd-user.ts +39 -1
- package/src/cli/editing/edit-session.ts +1 -7
- package/src/cli/local-bridge/console-automations.ts +18 -13
- package/src/cli/local-bridge/console-view-models.ts +3 -12
- package/src/cli/local-bridge/facade-api.ts +64 -191
- package/src/cli/local-bridge/server.ts +24 -147
- package/src/cli/local-bridge/types.ts +0 -1
- package/src/cli/mcp/oauth-client-retirement.ts +74 -0
- package/src/cli/repositories/command-executor.ts +29 -23
- package/src/cli/repositories/command-scope.ts +35 -16
- package/src/cli/repositories/controller-home.ts +48 -0
- package/src/cli/repositories/ephemeral-workspace.ts +20 -30
- package/src/cli/repositories/git-command-executor.ts +2 -2
- package/src/cli/repositories/registry.ts +77 -11
- package/src/cli/repositories/structured-git.ts +62 -2
- package/src/cli/repository/session-cache.ts +92 -6
- package/src/runtime/context/assistant-context.ts +20 -7
- package/src/runtime/context/assistant-work-context.ts +89 -27
- package/src/runtime/context/automatic-learning.ts +565 -0
- package/src/runtime/context/cognitive-attention.ts +173 -0
- package/src/runtime/context/cognitive-skill-canary.ts +158 -0
- package/src/runtime/context/context-closure.ts +46 -9
- package/src/runtime/context/context-pack-process.ts +103 -0
- package/src/runtime/context/context-plane.ts +1 -9
- package/src/runtime/context/direct-controller-learning.ts +298 -0
- package/src/runtime/context/semantic-navigation-contract.ts +9 -0
- package/src/runtime/context/semantic-navigation.ts +6 -34
- package/src/runtime/context/typescript-navigation-process.ts +145 -0
- package/src/runtime/context/typescript-navigation.ts +89 -3
- package/src/runtime/control-plane/cleanup-artifact-retention.ts +212 -9
- package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
- package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
- package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
- package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
- package/src/runtime/control-plane/execution/session-store.ts +31 -1
- package/src/runtime/control-plane/execution/validation.ts +6 -8
- package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
- package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
- package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
- package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
- package/src/runtime/control-plane/execution/work-handle-authority.ts +188 -109
- package/src/runtime/control-plane/execution/work-handle-store.ts +19 -43
- package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
- package/src/runtime/control-plane/execution/work-operation-service.ts +43 -27
- package/src/runtime/control-plane/execution/work-preparation-service.ts +126 -266
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
- package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +173 -186
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -84
- package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
- package/src/runtime/control-plane/facade/capability-registry.ts +362 -37
- package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
- package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
- package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
- package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
- package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
- package/src/runtime/control-plane/facade/index.ts +0 -1
- package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
- package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
- package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
- package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
- package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
- package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
- package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
- package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
- package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
- package/src/runtime/control-plane/facade/types.ts +49 -108
- package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
- package/src/runtime/control-plane/generated-cache-retention.ts +97 -1
- package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +239 -112
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +2 -1
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
- package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
- package/src/runtime/control-plane/governance/access-policy.ts +19 -2
- package/src/runtime/control-plane/governance/authorization.ts +20 -3
- package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +28 -300
- package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
- package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
- package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
- package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
- package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
- package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
- package/src/runtime/control-plane/release-retention.ts +135 -47
- package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
- package/src/runtime/control-plane/runtime-cleanup.ts +290 -21
- package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
- package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
- package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
- package/src/runtime/diagnostics/incident-repair.ts +313 -146
- package/src/runtime/diagnostics/mcp-timing.ts +114 -0
- package/src/runtime/evidence/artifact-store.ts +158 -40
- package/src/runtime/evidence/evidence-store.ts +112 -8
- package/src/runtime/evidence/output-handle-index.ts +225 -0
- package/src/runtime/evidence/result-store.ts +158 -44
- package/src/runtime/execution/jobs/store.ts +3 -4
- package/src/runtime/execution/managed-workspace.ts +57 -0
- package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
- package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
- package/src/runtime/execution/process-runtime/check-result.ts +105 -1
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
- package/src/runtime/execution/process-runtime/command-facade.ts +79 -27
- package/src/runtime/execution/process-runtime/gc.ts +15 -2
- package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
- package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
- package/src/runtime/execution/process-runtime/index.ts +3 -0
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
- package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
- package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
- package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
- package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
- package/src/runtime/execution/process-runtime/runtime.ts +35 -2
- package/src/runtime/execution/process-runtime/store.ts +30 -2
- package/src/runtime/execution/process-runtime/types.ts +6 -1
- package/src/runtime/execution/workers/executor.ts +2 -6
- package/src/runtime/platform/service-inventory.ts +130 -0
- package/src/runtime/platform/service-manager.ts +8 -0
- package/src/runtime/plugins/action-application.ts +85 -28
- package/src/runtime/plugins/app-store-connect-adapter.ts +38 -14
- package/src/runtime/plugins/browser-adapter.ts +757 -34
- package/src/runtime/plugins/browser-automation-service.ts +23 -3
- package/src/runtime/plugins/browser-macos-bridge.ts +321 -29
- package/src/runtime/plugins/browser-manifest-surface.ts +45 -11
- package/src/runtime/plugins/browser-native-session-service.ts +63 -13
- package/src/runtime/plugins/browser-registration.ts +16 -0
- package/src/runtime/plugins/browser-runtime.ts +14 -1
- package/src/runtime/plugins/browser-session-authority.ts +2 -2
- package/src/runtime/plugins/browser-session-store.ts +46 -76
- package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
- package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
- package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
- package/src/runtime/plugins/computer-registration.ts +222 -11
- package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
- package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
- package/src/runtime/plugins/external-adapter.ts +42 -6
- package/src/runtime/plugins/external-registration.ts +21 -1
- package/src/runtime/plugins/gmail-adapter.ts +23 -2
- package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
- package/src/runtime/plugins/google-shared.ts +14 -7
- package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
- package/src/runtime/plugins/ios-adapter.ts +1 -1
- package/src/runtime/plugins/lightweight-action.ts +208 -2
- package/src/runtime/plugins/local-system-adapter.ts +12 -2
- package/src/runtime/plugins/managed-process-adapter.ts +12 -5
- package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
- package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +602 -428
- package/src/runtime/plugins/types.ts +20 -0
- package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
- package/src/runtime/projections/invalidation.ts +7 -3
- package/src/runtime/projections/materialized-view.ts +80 -36
- package/src/runtime/recovery/actions.ts +3 -3
- package/src/runtime/recovery/capability-action-application.ts +46 -45
- package/src/runtime/recovery/lifecycle-inventory.ts +29 -29
- package/src/runtime/recovery/maintenance-executor.ts +374 -123
- package/src/runtime/recovery/store.ts +29 -11
- package/src/runtime/release/release-coordinator.ts +296 -0
- package/src/runtime/release/release-session.ts +716 -0
- package/src/runtime/release/release-state-migration.ts +25 -0
- package/src/runtime/resources/leases/store.ts +56 -25
- package/src/runtime/root/computer-composition.ts +191 -6
- package/src/runtime/root/controller-progression-composition.ts +192 -0
- package/src/runtime/root/controller-round-composition.ts +20 -1
- package/src/runtime/root/deployment-topology.ts +106 -0
- package/src/runtime/root/entry.ts +4 -3
- package/src/runtime/root/known-good-recovery.ts +184 -0
- package/src/runtime/root/local-bridge.ts +0 -1
- package/src/runtime/root/mcp-transport.ts +111 -18
- package/src/runtime/root/ownership.ts +261 -9
- package/src/runtime/root/package-connector-service.ts +105 -19
- package/src/runtime/root/package-runtime-release.ts +117 -18
- package/src/runtime/root/package-runtime-service.ts +17 -11
- package/src/runtime/root/release-execution-canary.ts +44 -12
- package/src/runtime/root/release-loader.ts +90 -8
- package/src/runtime/root/release-manifest.ts +80 -6
- package/src/runtime/root/release-materialize.ts +372 -28
- package/src/runtime/root/release-store.ts +395 -36
- package/src/runtime/root/runtime-lane.ts +191 -0
- package/src/runtime/root/runtime.ts +159 -27
- package/src/runtime/root/scheduled-controller-composition.ts +28 -3
- package/src/runtime/root/service-runner.ts +2 -2
- package/src/runtime/root/service.ts +36 -33
- package/src/runtime/root/status.ts +48 -0
- package/src/runtime/root/types.ts +32 -3
- package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
- package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
- package/src/runtime/root/write-fence.ts +50 -2
- package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
- package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
- package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
- package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
- package/src/runtime/shared/process-environment.ts +20 -9
- package/src/runtime/shared/response-budget.ts +1 -3
- package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
- package/src/runtime/standalone-recovery/core.ts +3702 -342
- package/src/runtime/standalone-recovery/entry.ts +469 -39
- package/src/runtime/standalone-recovery/installer.ts +262 -148
- package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
- package/src/runtime/standalone-recovery/operation-lock.ts +1 -1
- package/src/runtime/standalone-recovery/performance.ts +54 -16
- package/src/runtime/standalone-recovery/release.ts +53 -5
- package/src/runtime/standalone-recovery/service-labels.ts +5 -2
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
- package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +10 -3
- package/src/runtime/workflow/schedules/engine.ts +138 -172
- package/src/runtime/workflow/schedules/work-continuation.ts +44 -5
- package/src/runtime/workflows/runtime.ts +15 -19
- package/src/testing/test-governance.ts +5 -1
- package/supervisor/chatgpt-conversation.ts +23 -0
- package/supervisor/client.ts +201 -0
- package/supervisor/control-plane.ts +868 -0
- package/supervisor/entry.ts +15 -0
- package/supervisor/forge-validators.ts +80 -0
- package/supervisor/index.ts +5 -0
- package/supervisor/native-browser-adapter.ts +786 -0
- package/supervisor/native-messaging/host.ts +39 -0
- package/supervisor/native-messaging/manifest.ts +26 -0
- package/supervisor/native-messaging/protocol.ts +27 -0
- package/supervisor/paths.ts +18 -0
- package/supervisor/protocol.ts +202 -0
- package/supervisor/server.ts +404 -0
- package/supervisor/store.ts +1451 -0
- package/supervisor/tsconfig.json +8 -0
- package/supervisor/types.ts +255 -0
- package/adapters/chatgpt/controller-host.ts +0 -119
- package/adapters/mcp/controller-round-compatibility.ts +0 -184
- package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
- package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
- package/packages/kernel/progression/api/index.ts +0 -2
- package/packages/kernel/progression/application/projector.ts +0 -211
- package/packages/kernel/progression/domain/types.ts +0 -116
- package/packages/kernel/progression/index.ts +0 -1
- package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
- package/packages/kernel/scheduler/domain/continuation.ts +0 -38
- package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
- package/packages/kernel/work/domain/admission-policy.ts +0 -34
- package/scripts/benchmark-background-check-overlap.ts +0 -228
- package/scripts/benchmark-computer-hotpath.ts +0 -255
- package/scripts/benchmark-controller-hotpath.ts +0 -212
- package/scripts/benchmark-controller-round2.ts +0 -191
- package/scripts/benchmark-ios-agent-device.ts +0 -511
- package/scripts/benchmark-mcp-host.sh +0 -117
- package/scripts/benchmark-mcp-transport.ts +0 -169
- package/scripts/benchmark-operational-memory-activation.ts +0 -235
- package/scripts/benchmark-operational-shadow.ts +0 -28
- package/scripts/benchmark-quality-harness.ts +0 -146
- package/scripts/benchmark-route-session-concurrency.ts +0 -915
- package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
- package/scripts/benchmark-thin-harness.ts +0 -251
- package/scripts/benchmark-typescript-navigation.ts +0 -186
- package/scripts/benchmark-work-efficiency.ts +0 -334
- package/scripts/build-controller-ui.ts +0 -28
- package/scripts/check-npm-release.sh +0 -32
- package/scripts/check-public-release-surface.sh +0 -19
- package/scripts/check-release-published.sh +0 -57
- package/scripts/check-release-readiness.sh +0 -37
- package/scripts/check-release-version.mjs +0 -74
- package/scripts/check-tarball-install-smoke.sh +0 -150
- package/scripts/package-source-archive.sh +0 -147
- package/scripts/public-release-files.txt +0 -39
- package/scripts/public-release.ts +0 -174
- package/scripts/publish-release-tarball.sh +0 -27
- package/scripts/route-nl-vs-ts-eval.ts +0 -679
- package/scripts/stage-runtime-release.ts +0 -44
- package/src/cli/controller/progress.ts +0 -656
- package/src/cli/controller/work-mode.ts +0 -181
- package/src/cli/local-bridge/console-assets.ts +0 -17
- package/src/cli/local-bridge/dashboard.ts +0 -17
- package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
- package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
- package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
- package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
- package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/styles.css +0 -28
- package/src/cli/local-bridge/frontend/src/types.ts +0 -15
- package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
- package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
- package/src/cli/local-bridge/ui-dist/app.css +0 -1
- package/src/cli/local-bridge/ui-dist/app.js +0 -11228
- package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
- package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
- package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
- package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
- package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
- package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
- package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
- package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
- package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
- package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
- package/src/runtime/control-plane/routing/index.ts +0 -1
- package/src/runtime/control-plane/routing/route-policy.ts +0 -401
- package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { migrateReleaseSessionState, type ReleaseSessionStateMigration } from './release-session';
|
|
2
|
+
import { migrateRuntimeReleaseAuthorityState, readRuntimeReleaseAuthority, type RuntimeReleaseAuthority } from '../root/release-store';
|
|
3
|
+
|
|
4
|
+
export interface ReleaseDurableStateMigration {
|
|
5
|
+
authority?: RuntimeReleaseAuthority;
|
|
6
|
+
sessions: ReleaseSessionStateMigration;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* One migration boundary for all persisted Runtime release semantics.
|
|
11
|
+
* Runtime and Recovery cross this boundary before they declare themselves ready
|
|
12
|
+
* or consume ReleaseSession state. RuntimeReleaseAuthority upgrades its storage
|
|
13
|
+
* schema; ReleaseSession keeps downgrade-readable wire schema 1 while migrating
|
|
14
|
+
* once to semanticEpoch 2. Steady-state readers consume only the current model.
|
|
15
|
+
*/
|
|
16
|
+
export function migrateReleaseDurableState(controllerHome: string): ReleaseDurableStateMigration {
|
|
17
|
+
const authority = migrateRuntimeReleaseAuthorityState(controllerHome);
|
|
18
|
+
const sessions = migrateReleaseSessionState(controllerHome, {
|
|
19
|
+
readAuthority: () => authority ?? readRuntimeReleaseAuthority(controllerHome),
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
...(authority ? { authority } : {}),
|
|
23
|
+
sessions,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'crypto';
|
|
2
2
|
import { existsSync, readdirSync } from 'fs';
|
|
3
3
|
import { join } from 'path';
|
|
4
|
-
import {
|
|
4
|
+
import { controllerSystemRoot } from '../../../cli/repositories/controller-home';
|
|
5
5
|
import { ControllerLockContentionError, withControllerLock } from '../../../cli/repositories/locks';
|
|
6
6
|
import type { ResourceClaimSpec } from '../../execution/jobs/types';
|
|
7
7
|
import { readJsonFile, removeFile, writeJsonAtomic } from '../../shared/json-files';
|
|
@@ -9,7 +9,7 @@ import { markRepositoryProjectionDirty } from '../../projections/invalidation';
|
|
|
9
9
|
import { touchSchedulerWakeSignal } from '../../control-plane/global-scheduler/wake-signal';
|
|
10
10
|
import { claimsConflict } from '../claims/conflicts';
|
|
11
11
|
import { appendRuntimeEvent } from '../../evidence/event-ledger';
|
|
12
|
-
import { assertRuntimeMayWrite, assertRuntimeMayWriteOrThrow } from '../../root/write-fence';
|
|
12
|
+
import { assertRuntimeMayWrite, assertRuntimeMayWriteOrThrow, getRuntimeWriteClaim, isRuntimeWriteFenceError } from '../../root/write-fence';
|
|
13
13
|
import type {
|
|
14
14
|
ExecutionLease,
|
|
15
15
|
LeaseAcquisitionOptions,
|
|
@@ -18,8 +18,10 @@ import type {
|
|
|
18
18
|
ExecutionLeaseOwnerIdentity,
|
|
19
19
|
} from './types';
|
|
20
20
|
|
|
21
|
-
function leaseRoot(controllerHome: string,
|
|
22
|
-
|
|
21
|
+
function leaseRoot(controllerHome: string, _repoId: string): string {
|
|
22
|
+
// Concrete resource leases coordinate across the whole ForgeInstance. repoId
|
|
23
|
+
// is provenance/filter metadata, never the storage partition.
|
|
24
|
+
return join(controllerSystemRoot(controllerHome), 'execution-leases');
|
|
23
25
|
}
|
|
24
26
|
function activeRoot(controllerHome: string, repoId: string): string { return join(leaseRoot(controllerHome, repoId), 'active'); }
|
|
25
27
|
function leasePath(controllerHome: string, repoId: string, leaseId: string): string { return join(activeRoot(controllerHome, repoId), `${leaseId}.json`); }
|
|
@@ -29,6 +31,21 @@ function counterPath(controllerHome: string, repoId: string, resourceKey: string
|
|
|
29
31
|
}
|
|
30
32
|
function expired(lease: ExecutionLease): boolean { return Date.parse(lease.expiresAt) <= Date.now(); }
|
|
31
33
|
|
|
34
|
+
function currentManagedRuntimeClaim(controllerHome: string) {
|
|
35
|
+
const fence = assertRuntimeMayWrite(undefined, controllerHome);
|
|
36
|
+
if (!fence.allowed) return undefined;
|
|
37
|
+
const current = getRuntimeWriteClaim();
|
|
38
|
+
return current && !current.unmanaged ? current : undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function fencedEphemeralOwner(lease: ExecutionLease, current: ReturnType<typeof getRuntimeWriteClaim>): boolean {
|
|
42
|
+
if (lease.visibility !== 'ephemeral' || !lease.ownerIdentity || !current || current.unmanaged) return false;
|
|
43
|
+
const ownerInstanceId = lease.ownerIdentity.controllerInstanceId?.trim();
|
|
44
|
+
const ownerGeneration = lease.ownerIdentity.controllerGeneration?.trim();
|
|
45
|
+
if (!ownerInstanceId || !ownerGeneration || ownerGeneration === 'unbound') return false;
|
|
46
|
+
return ownerInstanceId !== current.runtimeInstanceId;
|
|
47
|
+
}
|
|
48
|
+
|
|
32
49
|
function validateClaimScopes(repoId: string, claims: ResourceClaimSpec[]): void {
|
|
33
50
|
const checkoutIds = new Set<string>();
|
|
34
51
|
const workIds = new Set<string>();
|
|
@@ -82,10 +99,12 @@ function normalizedOwnerIdentity(
|
|
|
82
99
|
branch: provided?.branch?.trim() || 'unknown',
|
|
83
100
|
principalId: provided?.principalId?.trim() || `owner:${ownerJobId}`,
|
|
84
101
|
controllerInstanceId: provided?.controllerInstanceId?.trim()
|
|
102
|
+
|| process.env.FORGE_RUNTIME_INSTANCE_ID?.trim()
|
|
85
103
|
|| process.env.FORGE_WRITER_INSTANCE_ID?.trim()
|
|
86
104
|
|| process.env.FORGE_DAEMON_INSTANCE_ID?.trim()
|
|
87
105
|
|| `process:${process.pid}`,
|
|
88
106
|
controllerGeneration: provided?.controllerGeneration?.trim()
|
|
107
|
+
|| process.env.FORGE_RUNTIME_INCARNATION_GENERATION?.trim()
|
|
89
108
|
|| process.env.FORGE_WRITER_GENERATION?.trim()
|
|
90
109
|
|| process.env.FORGE_ACTIVE_RUNTIME_REVISION?.trim()
|
|
91
110
|
|| 'unbound',
|
|
@@ -139,19 +158,29 @@ export function resetLeaseSideEffectMetrics(): void {
|
|
|
139
158
|
leaseSideEffectMetrics.ephemeralReleases = 0;
|
|
140
159
|
}
|
|
141
160
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
161
|
+
function listAllActiveLeases(controllerHome: string): ExecutionLease[] {
|
|
162
|
+
const root = activeRoot(controllerHome, '__instance__');
|
|
163
|
+
if (!existsSync(root)) return [];
|
|
164
|
+
const currentRuntime = currentManagedRuntimeClaim(controllerHome);
|
|
165
|
+
const leases: ExecutionLease[] = [];
|
|
166
|
+
for (const name of readdirSync(root).filter((entry) => entry.endsWith('.json'))) {
|
|
167
|
+
const path = join(root, name);
|
|
168
|
+
try {
|
|
169
|
+
const lease = readJsonFile<ExecutionLease>(path);
|
|
170
|
+
if (!lease?.leaseId || !lease.repoId || !lease.resourceKey || !lease.ownerJobId) {
|
|
171
|
+
throw new Error('required lease identity is missing');
|
|
172
|
+
}
|
|
173
|
+
if (expired(lease) || fencedEphemeralOwner(lease, currentRuntime)) removeFile(path);
|
|
174
|
+
else leases.push(lease);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
throw new Error(`LEASE_STORE_CORRUPT: ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
152
177
|
}
|
|
153
|
-
|
|
154
|
-
|
|
178
|
+
}
|
|
179
|
+
return leases;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function listActiveLeases(controllerHome: string, repoId: string): ExecutionLease[] {
|
|
183
|
+
return listAllActiveLeases(controllerHome).filter((lease) => lease.repoId === repoId);
|
|
155
184
|
}
|
|
156
185
|
|
|
157
186
|
export function acquireExecutionLeases(
|
|
@@ -186,8 +215,9 @@ export function acquireExecutionLeases(
|
|
|
186
215
|
const identityDigest = ownerIdentityDigest(ownerIdentity);
|
|
187
216
|
|
|
188
217
|
try {
|
|
189
|
-
return withControllerLock(controllerHome, { scope: '
|
|
190
|
-
const active =
|
|
218
|
+
return withControllerLock(controllerHome, { scope: 'global', resource: 'execution-leases' }, `lease-acquire:${ownerJobId}`, () => {
|
|
219
|
+
const active = listAllActiveLeases(controllerHome)
|
|
220
|
+
.filter((lease) => lease.ownerJobId !== ownerJobId || lease.repoId !== repoId);
|
|
191
221
|
const blockers = claims.flatMap((claim) => active
|
|
192
222
|
.filter((lease) => claimsConflict(claim, lease))
|
|
193
223
|
.map((lease) => ({ resourceKey: lease.resourceKey, ownerJobId: lease.ownerJobId, leaseId: lease.leaseId, mode: lease.mode, ownerIdentityDigest: lease.ownerIdentityDigest })));
|
|
@@ -297,10 +327,10 @@ export function renewExecutionLeases(
|
|
|
297
327
|
try {
|
|
298
328
|
assertRuntimeMayWriteOrThrow('renew_lease', controllerHome);
|
|
299
329
|
} catch (error) {
|
|
300
|
-
if (error
|
|
330
|
+
if (isRuntimeWriteFenceError(error)) throw error;
|
|
301
331
|
/* unbound legacy */
|
|
302
332
|
}
|
|
303
|
-
return withControllerLock(controllerHome, { scope: '
|
|
333
|
+
return withControllerLock(controllerHome, { scope: 'global', resource: 'execution-leases' }, `lease-renew:${ownerJobId}`, () => {
|
|
304
334
|
const expectedRefs = expectedLeaseMap(expected);
|
|
305
335
|
const timestamp = new Date().toISOString();
|
|
306
336
|
const owned = listActiveLeases(controllerHome, repoId)
|
|
@@ -329,10 +359,10 @@ export function releaseExecutionLeases(
|
|
|
329
359
|
try {
|
|
330
360
|
assertRuntimeMayWriteOrThrow('release_lease', controllerHome);
|
|
331
361
|
} catch (error) {
|
|
332
|
-
if (error
|
|
362
|
+
if (isRuntimeWriteFenceError(error)) throw error;
|
|
333
363
|
/* unbound legacy */
|
|
334
364
|
}
|
|
335
|
-
return withControllerLock(controllerHome, { scope: '
|
|
365
|
+
return withControllerLock(controllerHome, { scope: 'global', resource: 'execution-leases' }, `lease-release:${ownerJobId}`, () => {
|
|
336
366
|
const expectedRefs = expectedLeaseMap(expected);
|
|
337
367
|
let releasedCount = 0;
|
|
338
368
|
let visibility: LeaseVisibility = options?.visibility ?? 'durable';
|
|
@@ -384,10 +414,10 @@ export function releaseExactExecutionLeases(
|
|
|
384
414
|
try {
|
|
385
415
|
assertRuntimeMayWriteOrThrow('release_lease', controllerHome);
|
|
386
416
|
} catch (error) {
|
|
387
|
-
if (error
|
|
417
|
+
if (isRuntimeWriteFenceError(error)) throw error;
|
|
388
418
|
/* unbound legacy */
|
|
389
419
|
}
|
|
390
|
-
return withControllerLock(controllerHome, { scope: '
|
|
420
|
+
return withControllerLock(controllerHome, { scope: 'global', resource: 'execution-leases' }, `lease-release-exact:${ownerJobId}`, () => {
|
|
391
421
|
const expectedRefs = expectedLeaseMap(expected) ?? new Map<string, ExpectedLeaseRef>();
|
|
392
422
|
if (expectedRefs.size !== expected.length) {
|
|
393
423
|
throw new Error(`LEASE_SET_INVALID: ${ownerJobId} contains duplicate lease ids`);
|
|
@@ -460,7 +490,7 @@ export function releaseTerminalProcessLeases(
|
|
|
460
490
|
const normalizedProcessId = processId.trim();
|
|
461
491
|
if (!normalizedProcessId) throw new Error('TERMINAL_PROCESS_ID_REQUIRED');
|
|
462
492
|
const ownerJobId = `process:${normalizedProcessId}`;
|
|
463
|
-
return withControllerLock(controllerHome, { scope: '
|
|
493
|
+
return withControllerLock(controllerHome, { scope: 'global', resource: 'execution-leases' }, `terminal-lease-release:${ownerJobId}`, () => {
|
|
464
494
|
const expectedRefs = expectedLeaseMap(expected) ?? new Map<string, ExpectedLeaseRef>();
|
|
465
495
|
if (expectedRefs.size !== expected.length) {
|
|
466
496
|
throw new Error(`TERMINAL_PROCESS_LEASE_SET_INVALID: ${normalizedProcessId} contains duplicate lease ids`);
|
|
@@ -530,6 +560,7 @@ export function assertFencingToken(
|
|
|
530
560
|
const path = leasePath(controllerHome, repoId, leaseId);
|
|
531
561
|
if (!existsSync(path)) throw new Error(`LEASE_EXPIRED: ${leaseId}`);
|
|
532
562
|
const lease = readJsonFile<ExecutionLease>(path);
|
|
563
|
+
if (lease.repoId !== repoId) throw new Error(`LEASE_REPOSITORY_SCOPE_MISMATCH: expected ${repoId}, received ${lease.repoId}`);
|
|
533
564
|
if (expired(lease)) {
|
|
534
565
|
removeFile(path);
|
|
535
566
|
throw new Error(`LEASE_EXPIRED: ${leaseId}`);
|
|
@@ -3,9 +3,12 @@ import {
|
|
|
3
3
|
ComputerProviderRegistry,
|
|
4
4
|
computerProviderRegistrationSnapshot,
|
|
5
5
|
} from '../../../packages/plugin-runtime/computer/index';
|
|
6
|
+
import { randomUUID } from 'crypto';
|
|
6
7
|
import {
|
|
7
8
|
COMPUTER_BROWSER_AUTOMATION_CAPABILITY,
|
|
8
9
|
COMPUTER_CONSOLE_UNLOCK_CAPABILITY,
|
|
10
|
+
COMPUTER_ELEMENT_OBSERVE_CAPABILITY,
|
|
11
|
+
COMPUTER_INPUT_CAPABILITY,
|
|
9
12
|
type ComputerBrowserAutomationRequest,
|
|
10
13
|
type ComputerBrowserProduct,
|
|
11
14
|
type ComputerConsoleUnlockCommandRequest,
|
|
@@ -37,7 +40,7 @@ function computerCompositionKey(controllerHome: string): string {
|
|
|
37
40
|
const registration = currentDesktopOperatorRegistration(controllerHome);
|
|
38
41
|
const fingerprint = registration
|
|
39
42
|
? `${registration.revision}:${registration.registrationFingerprint}:${registration.enabled ? 'enabled' : 'disabled'}`
|
|
40
|
-
: 'desktop_operator:
|
|
43
|
+
: 'desktop_operator:unregistered';
|
|
41
44
|
return `${controllerHome}:${currentComputerPlatform()}:${fingerprint}`;
|
|
42
45
|
}
|
|
43
46
|
|
|
@@ -54,9 +57,6 @@ function ensureComputerComposition(controllerHome: string = resolveControllerHom
|
|
|
54
57
|
if (providerPluginId !== DESKTOP_OPERATOR_PROVIDER_PLUGIN_ID || !registration) return undefined;
|
|
55
58
|
return computerProviderRegistrationSnapshot(registration);
|
|
56
59
|
},
|
|
57
|
-
// Compatibility is an explicit Runtime composition decision, never an adapter fallback.
|
|
58
|
-
// Remove this switch once Desktop Operator 0.2.x support is retired.
|
|
59
|
-
legacyFallback: 'unregistered_v0_2',
|
|
60
60
|
});
|
|
61
61
|
next.register(desktopOperatorProvider);
|
|
62
62
|
}
|
|
@@ -111,8 +111,8 @@ export async function executeRuntimeComputerConsoleUnlock(
|
|
|
111
111
|
controllerHome: string = resolveControllerHome(),
|
|
112
112
|
): Promise<Record<string, unknown>> {
|
|
113
113
|
if (request.capability !== COMPUTER_CONSOLE_UNLOCK_CAPABILITY
|
|
114
|
-
|| !['prepare_unlock_console', 'unlock_console'].includes(request.action)) {
|
|
115
|
-
throw new AssistantPluginError('COMPUTER_CONSOLE_UNLOCK_REQUEST_INVALID', 'Protected console unlock accepts only computer.console.unlock.v1
|
|
114
|
+
|| !['prepare_unlock_console', 'unlock_console', 'console_unlock_enroll', 'console_unlock_status', 'console_unlock_recover', 'console_unlock_revoke'].includes(request.action)) {
|
|
115
|
+
throw new AssistantPluginError('COMPUTER_CONSOLE_UNLOCK_REQUEST_INVALID', 'Protected console unlock accepts only declared computer.console.unlock.v1 temporary or unattended-recovery commands.', { retryable: false });
|
|
116
116
|
}
|
|
117
117
|
if (authorization.kind !== 'explicit_single_use'
|
|
118
118
|
|| authorization.confirmed !== true
|
|
@@ -143,6 +143,191 @@ export async function executeRuntimeComputerBrowserAutomation(
|
|
|
143
143
|
return await desktopOperatorProvider.executeBrowserCompatibility(request, timeoutMs);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
type BrowserTrustedInputSemanticProof = {
|
|
147
|
+
domRole: string;
|
|
148
|
+
accessibleName: string;
|
|
149
|
+
editable: true;
|
|
150
|
+
focused: true;
|
|
151
|
+
multiline: boolean;
|
|
152
|
+
};
|
|
153
|
+
type BrowserTrustedInputRequest = Extract<ComputerBrowserAutomationRequest, { action: 'trusted_input' }> & {
|
|
154
|
+
semanticTarget?: BrowserTrustedInputSemanticProof;
|
|
155
|
+
};
|
|
156
|
+
function objectValue(value: unknown): Record<string, unknown> | undefined {
|
|
157
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : undefined;
|
|
158
|
+
}
|
|
159
|
+
function stringValue(record: Record<string, unknown> | undefined, ...keys: string[]): string {
|
|
160
|
+
for (const key of keys) {
|
|
161
|
+
const value = record?.[key];
|
|
162
|
+
if (typeof value === 'string' && value.trim()) return value.trim();
|
|
163
|
+
}
|
|
164
|
+
return '';
|
|
165
|
+
}
|
|
166
|
+
function browserTrustedInputAction(
|
|
167
|
+
controllerHome: string,
|
|
168
|
+
actionId: string,
|
|
169
|
+
args: Record<string, unknown>,
|
|
170
|
+
requestId: string,
|
|
171
|
+
timeoutMs: number,
|
|
172
|
+
): AssistantPluginActionExecutionInput {
|
|
173
|
+
return {
|
|
174
|
+
controllerHome,
|
|
175
|
+
repoId: '__controller__',
|
|
176
|
+
repoRoot: controllerHome,
|
|
177
|
+
pluginId: DESKTOP_OPERATOR_PROVIDER_PLUGIN_ID,
|
|
178
|
+
actionId,
|
|
179
|
+
requestId,
|
|
180
|
+
args,
|
|
181
|
+
origin: { surface: 'system', actor: 'native-browser-trusted-input' },
|
|
182
|
+
timeoutMs,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Trusted text/key input is a Unified Computer concern, not Browser compatibility.
|
|
188
|
+
* Browser owns the exact tab and DOM identity; the Desktop Operator interaction is
|
|
189
|
+
* a short-lived transport binding used only after that exact tab is already
|
|
190
|
+
* foreground. No provider session is promoted into a second semantic authority.
|
|
191
|
+
*/
|
|
192
|
+
export async function executeRuntimeComputerBrowserTrustedInput(
|
|
193
|
+
request: BrowserTrustedInputRequest,
|
|
194
|
+
timeoutMs: number,
|
|
195
|
+
controllerHome: string = resolveControllerHome(),
|
|
196
|
+
): Promise<Record<string, unknown>> {
|
|
197
|
+
if (request.input.kind !== 'text' && request.input.kind !== 'key') {
|
|
198
|
+
throw new AssistantPluginError(
|
|
199
|
+
'PLUGIN_BROWSER_NATIVE_UNIFIED_INPUT_KIND_UNSUPPORTED',
|
|
200
|
+
`Unified native Browser input handles text/key only, not ${request.input.kind}.`,
|
|
201
|
+
{ retryable: false, details: { browserProduct: request.product, inputKind: request.input.kind } },
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
if (currentComputerPlatform() !== 'darwin') {
|
|
205
|
+
throw new AssistantPluginError(
|
|
206
|
+
'PLUGIN_BROWSER_NATIVE_TRUSTED_INPUT_UNSUPPORTED_PLATFORM',
|
|
207
|
+
`Native Browser trusted input is unavailable on ${currentComputerPlatform()}.`,
|
|
208
|
+
{ retryable: false, details: { browserProduct: request.product } },
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
const expectedBundleId = NATIVE_BROWSER_BUNDLE_IDS[request.product];
|
|
212
|
+
const desktopOperator = getExternalPluginAdapter(controllerHome, DESKTOP_OPERATOR_PROVIDER_PLUGIN_ID);
|
|
213
|
+
if (!desktopOperator) {
|
|
214
|
+
throw new AssistantPluginError(
|
|
215
|
+
'PLUGIN_BROWSER_TRUSTED_INPUT_UNAVAILABLE',
|
|
216
|
+
'Native Browser trusted input requires the Unified Computer provider.',
|
|
217
|
+
{ retryable: true, details: { browserProduct: request.product, providerId: DESKTOP_OPERATOR_PROVIDER_PLUGIN_ID } },
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
const invocationId = randomUUID();
|
|
221
|
+
let interactionId = '';
|
|
222
|
+
let effectCompleted = false;
|
|
223
|
+
try {
|
|
224
|
+
const opened = await desktopOperator.executeAction(browserTrustedInputAction(
|
|
225
|
+
controllerHome,
|
|
226
|
+
'desktop_session_open',
|
|
227
|
+
{ bundle_id: expectedBundleId, launch: false, activate: false },
|
|
228
|
+
`native-browser-trusted-input:${invocationId}:open`,
|
|
229
|
+
timeoutMs,
|
|
230
|
+
));
|
|
231
|
+
interactionId = stringValue(opened, 'interactionId', 'interaction_id');
|
|
232
|
+
const observedBundleId = stringValue(opened, 'bundleIdentifier', 'bundle_id');
|
|
233
|
+
if (!interactionId || observedBundleId !== expectedBundleId) {
|
|
234
|
+
throw new AssistantPluginError(
|
|
235
|
+
observedBundleId ? 'PLUGIN_BROWSER_TRUSTED_INPUT_IDENTITY_MISMATCH' : 'PLUGIN_BROWSER_TRUSTED_INPUT_IDENTITY_UNVERIFIED',
|
|
236
|
+
'Unified Computer did not bind the exact requested native browser application.',
|
|
237
|
+
{ retryable: false, details: { browserProduct: request.product, expectedBundleId, observedBundleId: observedBundleId || undefined } },
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (request.input.kind === 'text') {
|
|
242
|
+
if (request.input.text.length > 10_000) {
|
|
243
|
+
throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'Trusted Browser text input must be at most 10000 characters.', { retryable: false });
|
|
244
|
+
}
|
|
245
|
+
const proof = request.semanticTarget;
|
|
246
|
+
if (!proof || proof.editable !== true || proof.focused !== true || !proof.accessibleName.trim() || !proof.domRole.trim()) {
|
|
247
|
+
throw new AssistantPluginError(
|
|
248
|
+
'PLUGIN_BROWSER_TRUSTED_INPUT_SEMANTIC_TARGET_REQUIRED',
|
|
249
|
+
'Unified Computer text input requires exact Browser-owned DOM semantic target proof.',
|
|
250
|
+
{ retryable: false, details: { browserProduct: request.product } },
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
const expectedAxRole = proof.domRole === 'textbox'
|
|
254
|
+
? (proof.multiline ? 'AXTextArea' : 'AXTextField')
|
|
255
|
+
: proof.domRole;
|
|
256
|
+
const observed = await executeRuntimeComputer({
|
|
257
|
+
capability: COMPUTER_ELEMENT_OBSERVE_CAPABILITY,
|
|
258
|
+
action: 'observe_elements',
|
|
259
|
+
interactionId,
|
|
260
|
+
maxDepth: 2,
|
|
261
|
+
maxNodes: 16,
|
|
262
|
+
includeValues: true,
|
|
263
|
+
rootSelector: { role: expectedAxRole },
|
|
264
|
+
}, timeoutMs, controllerHome);
|
|
265
|
+
const root = objectValue(observed.root);
|
|
266
|
+
const target = objectValue(root?.target);
|
|
267
|
+
const ref = stringValue(root, 'ref');
|
|
268
|
+
const targetInteractionId = stringValue(target, 'interactionId');
|
|
269
|
+
const targetBundleId = stringValue(target, 'bundleIdentifier');
|
|
270
|
+
const axAccessibleNames = [stringValue(root, 'description'), stringValue(root, 'name')].filter(Boolean);
|
|
271
|
+
const semanticIdentityMatches = axAccessibleNames.includes(proof.accessibleName.trim());
|
|
272
|
+
if (stringValue(root, 'role') !== expectedAxRole
|
|
273
|
+
|| !semanticIdentityMatches
|
|
274
|
+
|| !ref
|
|
275
|
+
|| targetInteractionId !== interactionId
|
|
276
|
+
|| targetBundleId !== expectedBundleId
|
|
277
|
+
|| typeof target?.pid !== 'number'
|
|
278
|
+
|| !Number.isInteger(target.pid)
|
|
279
|
+
|| typeof target?.appName !== 'string'
|
|
280
|
+
|| typeof target?.snapshotRevision !== 'number'
|
|
281
|
+
|| !Number.isInteger(target.snapshotRevision)) {
|
|
282
|
+
throw new AssistantPluginError(
|
|
283
|
+
'PLUGIN_BROWSER_TRUSTED_INPUT_SEMANTIC_TARGET_MISMATCH',
|
|
284
|
+
'Unified Computer element identity no longer matches the Browser-owned active DOM target.',
|
|
285
|
+
{ retryable: true, details: { browserProduct: request.product, interactionId, expectedAxRole, accessibleName: proof.accessibleName, observedRole: root?.role, observedNames: axAccessibleNames, ref: ref || undefined } },
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
// AX set_value can report success for Chromium contenteditable controls while
|
|
289
|
+
// React immediately restores the DOM value. Keep element.observe.v2 as the
|
|
290
|
+
// exact identity fence, then perform the actual text mutation through the
|
|
291
|
+
// Unified Computer input capability bound to that exact observed AX ref.
|
|
292
|
+
await executeRuntimeComputer({
|
|
293
|
+
capability: COMPUTER_INPUT_CAPABILITY,
|
|
294
|
+
action: 'type_text',
|
|
295
|
+
interactionId: targetInteractionId,
|
|
296
|
+
selector: { ref },
|
|
297
|
+
text: request.input.text,
|
|
298
|
+
replace: true,
|
|
299
|
+
}, timeoutMs, controllerHome);
|
|
300
|
+
} else {
|
|
301
|
+
await desktopOperator.executeAction(browserTrustedInputAction(
|
|
302
|
+
controllerHome,
|
|
303
|
+
'desktop_key',
|
|
304
|
+
{ interaction_id: interactionId, keys: [request.input.key] },
|
|
305
|
+
`native-browser-trusted-input:${invocationId}:key`,
|
|
306
|
+
timeoutMs,
|
|
307
|
+
));
|
|
308
|
+
}
|
|
309
|
+
effectCompleted = true;
|
|
310
|
+
return { performed: true, transport: 'computer', inputKind: request.input.kind };
|
|
311
|
+
} finally {
|
|
312
|
+
if (interactionId) {
|
|
313
|
+
try {
|
|
314
|
+
await desktopOperator.executeAction(browserTrustedInputAction(
|
|
315
|
+
controllerHome,
|
|
316
|
+
'desktop_session_close',
|
|
317
|
+
{ interaction_id: interactionId },
|
|
318
|
+
`native-browser-trusted-input:${invocationId}:close`,
|
|
319
|
+
timeoutMs,
|
|
320
|
+
));
|
|
321
|
+
} catch (error) {
|
|
322
|
+
// Provider-session cleanup is transport hygiene, never external-effect
|
|
323
|
+
// outcome authority. In particular, do not convert a confirmed text/key
|
|
324
|
+
// mutation into a replayable failure because session retirement failed.
|
|
325
|
+
process.stderr.write(`[computer-browser-trusted-input] cleanup_failed effect_completed=${effectCompleted} ${error instanceof Error ? error.message : String(error)}\n`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
146
331
|
export async function activateRuntimeComputerBrowserApplication(
|
|
147
332
|
input: AssistantPluginActionExecutionInput,
|
|
148
333
|
product: ComputerBrowserProduct,
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import {
|
|
2
|
+
beginControllerRoundRelayAfterRelease,
|
|
3
|
+
controllerRoundBlockerClass,
|
|
4
|
+
getControllerRoundRelay,
|
|
5
|
+
getControllerWorkBinding,
|
|
6
|
+
getRetainedControllerSession,
|
|
7
|
+
prepareControllerRoundOccurrence,
|
|
8
|
+
resumeControllerRoundOccurrence,
|
|
9
|
+
type ControllerBinding,
|
|
10
|
+
type ControllerHost,
|
|
11
|
+
} from '../../../packages/kernel/controller/api/index';
|
|
12
|
+
import { getWorkContract, semanticWorkState } from '../../../packages/kernel/work/api/index';
|
|
13
|
+
import {
|
|
14
|
+
controllerHostForScheduledBinding,
|
|
15
|
+
ensureScheduledControllerBindingForWork,
|
|
16
|
+
} from './scheduled-controller-composition';
|
|
17
|
+
import {
|
|
18
|
+
ensureWorkflowSupervisorEnrollmentForWork,
|
|
19
|
+
type WorkflowSupervisorEnrollmentStatus,
|
|
20
|
+
} from './workflow-supervisor-composition';
|
|
21
|
+
|
|
22
|
+
export interface ControllerProgressionInput {
|
|
23
|
+
workId: string;
|
|
24
|
+
occurrenceId: string;
|
|
25
|
+
relayScopeId?: string;
|
|
26
|
+
continuationHint?: string;
|
|
27
|
+
allowSemanticWaitRecovery?: boolean;
|
|
28
|
+
scheduleName?: string;
|
|
29
|
+
bindingArgs?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ControllerProgressionDependencies {
|
|
33
|
+
ensureBinding?: typeof ensureScheduledControllerBindingForWork;
|
|
34
|
+
hostForBinding?: typeof controllerHostForScheduledBinding;
|
|
35
|
+
prepareOccurrence?: typeof prepareControllerRoundOccurrence;
|
|
36
|
+
resumeOccurrence?: typeof resumeControllerRoundOccurrence;
|
|
37
|
+
ensureSupervisorEnrollment?: typeof ensureWorkflowSupervisorEnrollmentForWork;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type ControllerProgressionResult =
|
|
41
|
+
| { status: 'terminal_or_missing'; reason: string }
|
|
42
|
+
| { status: 'retained_session_missing'; reason: string }
|
|
43
|
+
| { status: 'human_controller'; reason: string }
|
|
44
|
+
| { status: 'semantic_wait'; reason?: string; binding: ControllerBinding }
|
|
45
|
+
| { status: 'wait_for_user'; reason?: string; binding: ControllerBinding }
|
|
46
|
+
| { status: 'rejected'; reason?: string; binding: ControllerBinding }
|
|
47
|
+
| {
|
|
48
|
+
status: 'chatgpt_enrolled';
|
|
49
|
+
binding: ControllerBinding;
|
|
50
|
+
relayScopeId: string;
|
|
51
|
+
reused: boolean;
|
|
52
|
+
supervisorEnrollment: {
|
|
53
|
+
status: WorkflowSupervisorEnrollmentStatus;
|
|
54
|
+
taskId?: string;
|
|
55
|
+
effectId?: string;
|
|
56
|
+
reason?: string;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
| {
|
|
60
|
+
status: 'chatgpt_not_enrolled';
|
|
61
|
+
binding: ControllerBinding;
|
|
62
|
+
relayScopeId: string;
|
|
63
|
+
reused: boolean;
|
|
64
|
+
supervisorEnrollment: {
|
|
65
|
+
status: WorkflowSupervisorEnrollmentStatus;
|
|
66
|
+
taskId?: string;
|
|
67
|
+
effectId?: string;
|
|
68
|
+
reason?: string;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
| {
|
|
72
|
+
status: 'provider_dispatched';
|
|
73
|
+
binding: ControllerBinding;
|
|
74
|
+
relayScopeId: string;
|
|
75
|
+
reused: boolean;
|
|
76
|
+
providerDispatchReceiptId?: string;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Stateless composition for one already-authorized Controller progression
|
|
81
|
+
* occurrence. It owns no persistence and introduces no lifecycle state.
|
|
82
|
+
*
|
|
83
|
+
* Work decides semantic terminality. ControllerSession/ControllerRound provide
|
|
84
|
+
* retained execution identity and one mechanical occurrence. Workflow Supervisor
|
|
85
|
+
* exclusively reserves and delivers Work-bound ChatGPT effects. Non-ChatGPT
|
|
86
|
+
* ControllerHost remains the direct provider boundary.
|
|
87
|
+
*/
|
|
88
|
+
export async function reconcileControllerProgression(
|
|
89
|
+
options: { controllerHome: string; repoId: string; repoRoot: string },
|
|
90
|
+
input: ControllerProgressionInput,
|
|
91
|
+
dependencies: ControllerProgressionDependencies = {},
|
|
92
|
+
): Promise<ControllerProgressionResult> {
|
|
93
|
+
const store = { controllerHome: options.controllerHome, repoId: options.repoId };
|
|
94
|
+
const work = getWorkContract(store, input.workId);
|
|
95
|
+
if (!work || semanticWorkState(work) !== 'open') {
|
|
96
|
+
return { status: 'terminal_or_missing', reason: work ? `WORK_TERMINAL:${semanticWorkState(work)}` : 'WORK_NOT_FOUND' };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const retainedSession = getRetainedControllerSession(store, input.workId);
|
|
100
|
+
if (!retainedSession) return { status: 'retained_session_missing', reason: 'CONTROLLER_SESSION_NOT_RETAINED' };
|
|
101
|
+
if (retainedSession.controllerType === 'human') return { status: 'human_controller', reason: 'HUMAN_CONTROLLER' };
|
|
102
|
+
|
|
103
|
+
const ensureBinding = dependencies.ensureBinding ?? ensureScheduledControllerBindingForWork;
|
|
104
|
+
const existingBinding = getControllerWorkBinding(store, input.workId)?.binding;
|
|
105
|
+
const binding = existingBinding ?? ensureBinding(store, {
|
|
106
|
+
workId: input.workId,
|
|
107
|
+
session: retainedSession,
|
|
108
|
+
scheduleName: input.scheduleName,
|
|
109
|
+
args: input.bindingArgs ?? {},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
if (retainedSession.controllerType === 'chatgpt') {
|
|
113
|
+
const ensureSupervisorEnrollment = dependencies.ensureSupervisorEnrollment ?? ensureWorkflowSupervisorEnrollmentForWork;
|
|
114
|
+
let existingRound = getControllerRoundRelay(store, input.workId);
|
|
115
|
+
let controllerRoundOccurrenceId = input.occurrenceId;
|
|
116
|
+
if (existingRound?.status === 'pending_release') {
|
|
117
|
+
// The semantic turn already chose continue_immediately. Once its exact
|
|
118
|
+
// ControllerSession lease has been released, reopen that same durable
|
|
119
|
+
// ControllerRound for dispatch before reserving another Supervisor effect.
|
|
120
|
+
// Schedule occurrence ids are trigger evidence, not a replacement
|
|
121
|
+
// ControllerRound identity for an already-open continuation chain.
|
|
122
|
+
existingRound = beginControllerRoundRelayAfterRelease(store, {
|
|
123
|
+
workId: input.workId,
|
|
124
|
+
releasedSession: retainedSession,
|
|
125
|
+
}) ?? getControllerRoundRelay(store, input.workId);
|
|
126
|
+
}
|
|
127
|
+
// An already-open recoverable ControllerRound keeps its durable occurrence
|
|
128
|
+
// identity across Scheduler wake attempts. A fresh ScheduleOccurrence is
|
|
129
|
+
// trigger/evidence identity only; replacing the round occurrence here would
|
|
130
|
+
// manufacture a second open round and permanently self-block continuation.
|
|
131
|
+
if (existingRound?.occurrenceId?.trim()
|
|
132
|
+
&& ['dispatching', 'dispatched', 'claimed'].includes(existingRound.status)) {
|
|
133
|
+
controllerRoundOccurrenceId = existingRound.occurrenceId.trim();
|
|
134
|
+
}
|
|
135
|
+
if (existingRound?.status === 'blocked'
|
|
136
|
+
&& controllerRoundBlockerClass(existingRound) === 'provider_dispatch_outcome_unknown') {
|
|
137
|
+
const supervisorEnrollment = await ensureSupervisorEnrollment(store, input.workId);
|
|
138
|
+
return {
|
|
139
|
+
status: supervisorEnrollment.status === 'enrolled' ? 'chatgpt_enrolled' : 'chatgpt_not_enrolled',
|
|
140
|
+
binding,
|
|
141
|
+
relayScopeId: existingRound.relayScopeId,
|
|
142
|
+
reused: true,
|
|
143
|
+
supervisorEnrollment,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const prepareOccurrence = dependencies.prepareOccurrence ?? prepareControllerRoundOccurrence;
|
|
148
|
+
const prepared = prepareOccurrence(store, {
|
|
149
|
+
occurrenceId: controllerRoundOccurrenceId,
|
|
150
|
+
workId: input.workId,
|
|
151
|
+
controllerBindingId: binding.bindingId,
|
|
152
|
+
relayScopeId: input.relayScopeId,
|
|
153
|
+
continuationHint: input.continuationHint,
|
|
154
|
+
allowSemanticWaitRecovery: input.allowSemanticWaitRecovery,
|
|
155
|
+
});
|
|
156
|
+
if (prepared.outcome === 'semantic_wait') return { status: 'semantic_wait', reason: prepared.reason, binding };
|
|
157
|
+
if (prepared.outcome === 'wait_for_user') return { status: 'wait_for_user', reason: prepared.reason, binding };
|
|
158
|
+
if (prepared.outcome === 'rejected') return { status: 'rejected', reason: prepared.reason, binding };
|
|
159
|
+
|
|
160
|
+
const supervisorEnrollment = await ensureSupervisorEnrollment(store, input.workId);
|
|
161
|
+
return {
|
|
162
|
+
status: supervisorEnrollment.status === 'enrolled' ? 'chatgpt_enrolled' : 'chatgpt_not_enrolled',
|
|
163
|
+
binding,
|
|
164
|
+
relayScopeId: prepared.relay.relayScopeId,
|
|
165
|
+
reused: prepared.reused,
|
|
166
|
+
supervisorEnrollment,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const hostForBinding = dependencies.hostForBinding ?? controllerHostForScheduledBinding;
|
|
171
|
+
const host: ControllerHost = hostForBinding(options, binding);
|
|
172
|
+
const resumeOccurrence = dependencies.resumeOccurrence ?? resumeControllerRoundOccurrence;
|
|
173
|
+
const resumed = await resumeOccurrence(store, {
|
|
174
|
+
occurrenceId: input.occurrenceId,
|
|
175
|
+
workId: input.workId,
|
|
176
|
+
controllerBindingId: binding.bindingId,
|
|
177
|
+
relayScopeId: input.relayScopeId,
|
|
178
|
+
continuationHint: input.continuationHint,
|
|
179
|
+
allowSemanticWaitRecovery: input.allowSemanticWaitRecovery,
|
|
180
|
+
}, host);
|
|
181
|
+
|
|
182
|
+
if (resumed.outcome === 'semantic_wait') return { status: 'semantic_wait', reason: resumed.reason, binding };
|
|
183
|
+
if (resumed.outcome === 'wait_for_user') return { status: 'wait_for_user', reason: resumed.reason, binding };
|
|
184
|
+
if (resumed.outcome === 'rejected') return { status: 'rejected', reason: resumed.reason, binding };
|
|
185
|
+
return {
|
|
186
|
+
status: 'provider_dispatched',
|
|
187
|
+
binding,
|
|
188
|
+
relayScopeId: resumed.relay.relayScopeId,
|
|
189
|
+
reused: resumed.reused,
|
|
190
|
+
providerDispatchReceiptId: resumed.providerDispatchReceiptId,
|
|
191
|
+
};
|
|
192
|
+
}
|