@moretea-labs/forge 1.8.0 → 1.8.2
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 +73 -7
- package/CHANGELOG.md +34 -0
- package/CLAUDE.md +17 -2
- package/CONTRIBUTING.md +3 -2
- package/README.en.md +24 -3
- package/README.md +10 -6
- package/README.zh-CN.md +5 -3
- package/THIRD_PARTY_NOTICES.md +1 -2
- package/adapters/chatgpt/browser-delivery-host.ts +7 -1
- package/adapters/chatgpt/browser-delivery-runtime.ts +531 -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 +229 -2
- package/adapters/chatgpt/work-conversation-binding-store.ts +99 -54
- package/adapters/computer/chatgpt-extension-target.ts +708 -0
- package/adapters/computer/chrome-extension/background.js +541 -0
- package/adapters/computer/chrome-extension/content.js +402 -0
- package/adapters/computer/chrome-extension/core.js +24 -0
- package/adapters/computer/chrome-extension/manifest.json +32 -0
- package/adapters/computer/desktop-operator-discovery.ts +11 -31
- package/adapters/computer/desktop-operator-provider.ts +18 -6
- package/adapters/computer/interaction-target-authority.ts +178 -24
- package/adapters/mcp/access-mode.ts +18 -39
- package/adapters/mcp/auth.ts +2 -7
- package/adapters/mcp/instructions.ts +6 -5
- package/adapters/mcp/multi-repository.ts +10 -47
- package/adapters/mcp/oauth.ts +73 -0
- package/adapters/mcp/paths.ts +4 -1
- 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 +490 -113
- package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +83 -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 +14 -54
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
- package/adapters/mcp/runtime-gateway/plugin-adapter.ts +132 -47
- package/adapters/mcp/runtime-gateway/process-tools.ts +173 -23
- 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 +19 -507
- package/adapters/mcp/runtime-gateway/routing-policy.ts +506 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +15 -66
- package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +123 -178
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +11 -5
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +37 -1
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +416 -270
- package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +140 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +262 -3123
- 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 +229 -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 +320 -0
- package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
- package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +180 -0
- package/adapters/mcp/server.ts +91 -26
- package/adapters/mcp/setup.ts +5 -13
- package/adapters/mcp/tool-mapping/access-tools.ts +0 -6
- package/adapters/mcp/tool-mapping/legacy-tool-service.ts +703 -3092
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +5 -10
- package/adapters/mcp/tool-mapping/repository-tools.ts +170 -213
- package/adapters/mcp/toolset-names.ts +11 -37
- package/adapters/mcp/toolset.ts +19 -92
- package/{src/cli → adapters}/mcp/transports/AGENTS.md +5 -5
- package/{src/cli → adapters}/mcp/transports/CLAUDE.md +5 -5
- package/adapters/mcp/transports/http-observation.ts +377 -0
- package/adapters/mcp/transports/http-post-lifecycle.ts +19 -0
- package/adapters/mcp/transports/http.ts +200 -683
- 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/adapters/mcp/types.ts +0 -6
- package/assets/hooks/lib/session-state.sh +0 -38
- package/assets/hooks/post-bash.sh +1 -1
- package/assets/hooks/post-tool-observer.sh +0 -5
- package/assets/hooks/prompt-guard.sh +0 -55
- package/assets/partials/04-project-structure.partial.md +1 -1
- package/assets/partials/07-footer.partial.md +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +1 -1
- package/assets/partials-agents/08-deep-docs.partial.md +1 -1
- package/assets/plugin-registry.v1.json +6 -4
- package/assets/reference-configs/agentic-development-flow.md +26 -1
- package/assets/reference-configs/external-tooling.md +0 -76
- package/assets/reference-configs/global-working-rules.md +19 -0
- package/assets/reference-configs/release-deploy.md +1 -1
- package/assets/templates/helpers/architecture-queue.sh +1 -1
- package/assets/templates/helpers/check-agent-tooling.sh +1 -327
- package/assets/templates/helpers/check-task-workflow.sh +1 -1
- package/assets/templates/helpers/ensure-task-workflow.sh +0 -14
- package/assets/templates/helpers/migrate-project-template.sh +2 -2
- package/assets/workflow-contract.v1.json +0 -2
- package/docs/README.md +5 -2
- package/docs/architecture/CURRENT.md +205 -51
- 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/20260904-ios-device-migration-baseline.md +42 -0
- 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 +234 -0
- package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
- package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +74 -0
- package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +342 -0
- package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
- package/docs/architecture/decisions/20261009-exact-code-context-discovery.md +19 -0
- package/docs/architecture/decisions/20261009-generated-xcode-cache-retention.md +37 -0
- package/docs/architecture/decisions/20261011-autonomous-continuation-convergence.md +597 -0
- package/docs/architecture/decisions/20261017-edit-session-finalization-reconciliation.md +17 -0
- package/docs/architecture/decisions/20261019-retire-host-skills.md +16 -0
- package/docs/architecture/diagrams/agentic-dev-plugin-architecture.html +1 -1
- package/docs/architecture/domains/public-surface.md +3 -5
- package/docs/architecture/domains/verification.md +6 -5
- package/docs/architecture/domains/workflow-engine.md +6 -0
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +3 -3
- package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +4 -4
- package/docs/architecture/reviews/20261015-code-search-runtime-acceptance.md +75 -0
- package/docs/forge-plugin-management.md +16 -4
- package/docs/operations/controller-browser-plugin.md +23 -0
- package/docs/operations/controller-performance-and-502.md +17 -0
- package/docs/operations/controller-reliability-runbook.md +2 -2
- package/docs/operations/features.md +6 -7
- package/docs/operations/features.zh-CN.md +1 -1
- package/docs/operations/github-repository.md +4 -4
- package/docs/operations/github-semantic-release-projection.md +20 -0
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +13 -52
- package/docs/operations/releasing.md +2 -0
- package/docs/operations/runtime-performance-diagnostics.md +8 -0
- package/docs/operations/standalone-disaster-recovery.md +15 -7
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/tutorials/03-first-repository-task.md +2 -0
- package/docs/wiki/Computer-and-Plugins.md +78 -0
- package/docs/wiki/Computer-and-Plugins.zh-CN.md +88 -0
- package/docs/wiki/Home.md +16 -2
- package/docs/wiki/Implementation.md +25 -13
- package/docs/wiki/Installation.md +28 -32
- package/docs/wiki/Integrations.md +4 -0
- package/docs/wiki/Quick-Start.md +35 -22
- package/docs/wiki/Releases-and-Upgrades.md +15 -25
- package/docs/wiki/_Sidebar.md +5 -1
- package/package.json +25 -25
- 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 +348 -97
- 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 +87 -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/eligibility.ts +4 -1
- 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 +166 -143
- package/packages/kernel/work/api/index.ts +3 -2
- package/packages/kernel/work/application/work-service.ts +18 -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 +34 -65
- package/packages/kernel/work/domain/types.ts +57 -51
- package/packages/kernel/work/infrastructure/work-contract-store.ts +847 -729
- package/packages/kernel/work/ports/work-contract-store.ts +5 -2
- package/packages/plugin-runtime/browser/provider-registry.ts +12 -36
- 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 +153 -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/assemble-template.ts +11 -72
- package/scripts/canary-controller-semantic-wait.ts +12 -24
- package/scripts/check-mcp-compatibility.ts +94 -201
- package/scripts/check-package-identity.mjs +0 -5
- package/scripts/check-runtime-architecture.mjs +921 -239
- package/scripts/forge-local-recovery-helper.mjs +93 -15
- package/scripts/init-project.sh +0 -46
- package/scripts/install-ios-hid-toolchain.sh +60 -0
- package/scripts/install-standalone-recovery.ts +1 -1
- package/scripts/lib/project-init-lib.sh +6 -3
- package/scripts/migrate-windows-wsl-controller-home.ts +2 -0
- package/scripts/open-source-audit-allowlist.txt +1 -3
- package/scripts/run-bounded-command.mjs +5 -0
- package/scripts/run-governed-gate.ts +2 -1
- package/scripts/run-mobile-monitor-bridge.ts +0 -1
- package/scripts/smoke-control-plane-failure-domain.ts +94 -0
- package/scripts/smoke-ios-physical-device.ts +38 -10
- package/scripts/smoke-mcp-http-runtime.ts +12 -8
- package/scripts/smoke-mcp-tool-surface.ts +27 -41
- 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 +95 -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/sync-generated-authority.mjs +0 -1
- package/scripts/verify-forge-runtime.sh +2 -1
- package/src/cli/agent-jobs/executor-health.ts +12 -35
- package/src/cli/agent-jobs/integration.ts +20 -51
- package/src/cli/agent-jobs/job-manager.ts +7 -3
- package/src/cli/chatgpt-browser/file-policy.ts +2 -2
- 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/doctor.ts +1 -143
- package/src/cli/commands/global-runtime.ts +3 -196
- package/src/cli/commands/init-hook.ts +6 -23
- package/src/cli/commands/init.ts +3 -252
- package/src/cli/commands/mcp.ts +0 -5
- package/src/cli/commands/prompt-guard-decision.ts +0 -2
- package/src/cli/commands/recovery.ts +137 -135
- package/src/cli/commands/repository.ts +17 -1
- package/src/cli/commands/runtime.ts +3 -3
- package/src/cli/commands/setup-execution.ts +41 -0
- 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 +5 -44
- package/src/cli/controller/completion-target.ts +3 -72
- package/src/cli/controller/composite-operations.ts +1 -1
- package/src/cli/controller/context/instruction-context.ts +1 -1
- package/src/cli/controller/context/known-paths.ts +2 -2
- package/src/cli/controller/context/query-planning.ts +11 -4
- package/src/cli/controller/context/rule-resolution.ts +2 -2
- package/src/cli/controller/context/source-materializer.ts +83 -102
- package/src/cli/controller/context/structural-provider.ts +84 -0
- package/src/cli/controller/context/structural.ts +6 -6
- package/src/cli/controller/context/types.ts +8 -9
- package/src/cli/controller/context-pack.ts +107 -84
- 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 +25 -52
- 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 +42 -10
- package/src/cli/editing/edit-session.ts +18 -12
- package/src/cli/github/github.ts +4 -4
- package/src/cli/github/semantic-projection.ts +174 -0
- package/src/cli/hook/prompt-intents.ts +0 -9
- package/src/cli/index.ts +1 -43
- package/src/cli/local-bridge/connector-freshness.ts +1 -12
- package/src/cli/local-bridge/console-automations.ts +19 -14
- package/src/cli/local-bridge/console-view-models.ts +4 -13
- package/src/cli/local-bridge/facade-api.ts +64 -193
- 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-classifier.ts +0 -9
- package/src/cli/repositories/command-executor.ts +29 -23
- package/src/cli/repositories/command-scope.ts +37 -18
- 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/locks.ts +20 -0
- package/src/cli/repositories/registry.ts +79 -12
- package/src/cli/repositories/safe-patch.ts +2 -12
- package/src/cli/repositories/structured-git.ts +101 -5
- package/src/cli/repository/inspector.ts +185 -343
- package/src/cli/repository/session-cache.ts +92 -6
- package/src/effects/process-runner.ts +17 -1
- 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/generic-lsp-provider.ts +1 -1
- package/src/runtime/context/semantic-navigation-contract.ts +16 -0
- package/src/runtime/context/semantic-navigation.ts +7 -35
- 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 +215 -12
- 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 +616 -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 +197 -110
- package/src/runtime/control-plane/execution/work-handle-store.ts +72 -44
- 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 +60 -34
- package/src/runtime/control-plane/execution/work-preparation-service.ts +231 -267
- package/src/runtime/control-plane/execution/work-process-evidence.ts +2 -2
- 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 +201 -199
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +33 -85
- package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +6 -2
- package/src/runtime/control-plane/facade/capability-registry.ts +364 -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 +9 -9
- package/src/runtime/control-plane/generated-cache-retention.ts +206 -59
- 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 +256 -117
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -12
- 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/governance/external-effects.ts +1 -1
- package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +29 -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 +295 -107
- 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/evidence/sensitive-output.ts +22 -2
- package/src/runtime/execution/jobs/child-reference.ts +11 -0
- package/src/runtime/execution/jobs/receipt-recovery.ts +1 -11
- 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 +82 -30
- 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 +55 -18
- package/src/runtime/execution/process-runtime/store.ts +30 -2
- package/src/runtime/execution/process-runtime/types.ts +6 -1
- package/src/runtime/execution/thin-harness/execution-router.ts +16 -16
- package/src/runtime/execution/thin-harness/fast-executor.ts +2 -2
- package/src/runtime/execution/thin-harness/search-worker.ts +2 -2
- package/src/runtime/execution/workers/executor.ts +3 -8
- package/src/runtime/maintenance/cleanup.ts +41 -5
- 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 +97 -29
- package/src/runtime/plugins/app-store-connect-adapter.ts +290 -18
- package/src/runtime/plugins/browser-adapter.ts +1124 -333
- package/src/runtime/plugins/browser-automation-service.ts +23 -3
- package/src/runtime/plugins/browser-macos-bridge.ts +431 -137
- package/src/runtime/plugins/browser-manifest-surface.ts +47 -12
- package/src/runtime/plugins/browser-native-session-service.ts +63 -13
- package/src/runtime/plugins/browser-registration.ts +18 -0
- package/src/runtime/plugins/browser-runtime.ts +40 -36
- 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 +228 -0
- package/src/runtime/plugins/computer-registration.ts +298 -20
- 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/github-adapter.ts +30 -3
- package/src/runtime/plugins/gmail-adapter.ts +189 -3
- package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
- package/src/runtime/plugins/google-shared.ts +24 -12
- package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
- package/src/runtime/plugins/ios/remote-xpc-hid.ts +70 -30
- package/src/runtime/plugins/ios-adapter.ts +46 -41
- package/src/runtime/plugins/ios-agent-device.ts +54 -4
- package/src/runtime/plugins/ios-device-ownership.ts +103 -0
- package/src/runtime/plugins/ios-physical-device.ts +497 -79
- package/src/runtime/plugins/lightweight-action.ts +208 -2
- package/src/runtime/plugins/local-system-adapter.ts +12 -100
- 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 +682 -435
- package/src/runtime/plugins/types.ts +24 -0
- package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
- package/src/runtime/projections/git-status-sampler.ts +2 -19
- package/src/runtime/projections/invalidation.ts +7 -3
- package/src/runtime/projections/materialized-view.ts +80 -36
- package/src/runtime/recovery/actions.ts +4 -4
- package/src/runtime/recovery/capability-action-application.ts +46 -45
- package/src/runtime/recovery/lifecycle-inventory.ts +30 -40
- package/src/runtime/recovery/maintenance-executor.ts +374 -123
- package/src/runtime/recovery/probe.ts +2 -2
- package/src/runtime/recovery/store.ts +29 -11
- package/src/runtime/release/release-coordinator.ts +312 -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 +254 -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 +227 -29
- package/src/runtime/root/package-runtime-release.ts +117 -30
- package/src/runtime/root/package-runtime-service.ts +24 -24
- package/src/runtime/root/release-execution-canary.ts +57 -12
- package/src/runtime/root/release-loader.ts +90 -8
- package/src/runtime/root/release-manifest.ts +80 -40
- package/src/runtime/root/release-materialize.ts +372 -106
- package/src/runtime/root/release-store.ts +395 -36
- package/src/runtime/root/runtime-lane.ts +191 -0
- package/src/runtime/root/runtime.ts +160 -29
- package/src/runtime/root/scheduled-controller-composition.ts +29 -3
- package/src/runtime/root/service-runner.ts +2 -2
- package/src/runtime/root/service.ts +126 -44
- package/src/runtime/root/status.ts +48 -0
- package/src/runtime/root/types.ts +32 -9
- package/src/runtime/root/workflow-supervisor-composition.ts +681 -0
- package/src/runtime/root/workflow-supervisor-runtime.ts +564 -0
- package/src/runtime/root/write-fence.ts +50 -2
- package/src/runtime/safe-tooling/google-credential-store.ts +67 -22
- package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
- package/src/runtime/safe-tooling/ios-development.ts +22 -8
- package/src/runtime/safe-tooling/job-summary.ts +1 -1
- package/src/runtime/safe-tooling/workspace-auth.ts +5 -2
- package/src/runtime/shared/atomic-text-file.ts +21 -0
- package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
- package/src/runtime/shared/json-files.ts +8 -3
- 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 +3792 -417
- package/src/runtime/standalone-recovery/entry.ts +507 -45
- 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 +12 -2
- 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 +11 -3
- package/src/runtime/workflow/schedules/engine.ts +166 -178
- package/src/runtime/workflow/schedules/pending-activation.ts +11 -4
- package/src/runtime/workflow/schedules/work-continuation.ts +95 -11
- 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 +218 -0
- package/supervisor/control-plane.ts +963 -0
- package/supervisor/entry.ts +15 -0
- package/supervisor/forge-validators.ts +147 -0
- package/supervisor/index.ts +5 -0
- package/supervisor/native-browser-adapter.ts +1151 -0
- package/supervisor/native-messaging/host.ts +58 -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 +250 -0
- package/supervisor/server.ts +412 -0
- package/supervisor/store.ts +1870 -0
- package/supervisor/tsconfig.json +8 -0
- package/supervisor/types.ts +261 -0
- package/SKILL.md +0 -427
- 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/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +0 -1
- package/adapters/mcp/toolset-selection.ts +0 -41
- package/agents/openai.yaml +0 -4
- package/assets/skill-hooks.json +0 -41
- package/assets/skill-version.json +0 -189
- package/assets/skills/claude-review/SKILL.md +0 -231
- package/assets/skills/codex-review/SKILL.md +0 -103
- package/assets/templates/helpers/check-skill-version.ts +0 -193
- 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-skill-version.ts +0 -5
- package/scripts/check-tarball-install-smoke.sh +0 -150
- package/scripts/ensure-codegraph.sh +0 -16
- 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/run-skill-hook.ts +0 -244
- package/scripts/stage-runtime-release.ts +0 -44
- package/scripts/sync-codex-installed-copies.sh +0 -182
- package/src/cli/commands/tools.ts +0 -167
- 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/cli/mcp/access-mode.ts +0 -2
- package/src/cli/mcp/access-tools.ts +0 -2
- package/src/cli/mcp/audit.ts +0 -2
- package/src/cli/mcp/auth.ts +0 -2
- package/src/cli/mcp/instructions.ts +0 -2
- package/src/cli/mcp/legacy-context.ts +0 -2
- package/src/cli/mcp/legacy-tool-service.ts +0 -2
- package/src/cli/mcp/multi-repository.ts +0 -2
- package/src/cli/mcp/oauth.ts +0 -2
- package/src/cli/mcp/openai-secure-tunnel.ts +0 -2
- package/src/cli/mcp/paths.ts +0 -2
- package/src/cli/mcp/policy.ts +0 -2
- package/src/cli/mcp/post-finalize-work-attribution.ts +0 -2
- package/src/cli/mcp/proxy-env.ts +0 -2
- package/src/cli/mcp/readiness-projection.ts +0 -2
- package/src/cli/mcp/redaction.ts +0 -2
- package/src/cli/mcp/repo.ts +0 -2
- package/src/cli/mcp/repository-tools.ts +0 -2
- package/src/cli/mcp/server.ts +0 -2
- package/src/cli/mcp/setup.ts +0 -2
- package/src/cli/mcp/tool-capability-cache.ts +0 -2
- package/src/cli/mcp/tool-contract.ts +0 -2
- package/src/cli/mcp/tools.ts +0 -2
- package/src/cli/mcp/toolset-names.ts +0 -2
- package/src/cli/mcp/toolset-selection.ts +0 -2
- package/src/cli/mcp/toolset.ts +0 -2
- package/src/cli/mcp/transports/http.ts +0 -2
- package/src/cli/mcp/transports/session-registry.ts +0 -2
- package/src/cli/mcp/transports/stdio.ts +0 -2
- package/src/cli/mcp/types.ts +0 -2
- package/src/cli/mcp/umbrella-tools.ts +0 -2
- package/src/cli/tools/codegraph.ts +0 -695
- package/src/core/adoption/helper-wrapper-plan.ts +0 -159
- package/src/runtime/context/codegraph-cache-boundary.ts +0 -255
- package/src/runtime/context/codegraph-read-provider.ts +0 -611
- package/src/runtime/context/codegraph-sidecar.cjs +0 -248
- package/src/runtime/control-plane/codegraph-cache-retention.ts +0 -164
- 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
- package/src/runtime/gateway/mcp/execution-tools.ts +0 -2
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +0 -2
- package/src/runtime/gateway/mcp/persisted-check-process.ts +0 -2
- package/src/runtime/gateway/mcp/process-tools.ts +0 -2
- package/src/runtime/gateway/mcp/router.ts +0 -2
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +0 -2
- package/src/runtime/gateway/mcp/runtime-tools.ts +0 -2
- package/src/runtime/gateway/mcp/work-validation-reconciler.ts +0 -2
- package/src/runtime/plugins/browser-provider-registry.ts +0 -2
|
@@ -2,16 +2,27 @@ import { randomUUID } from 'crypto';
|
|
|
2
2
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
3
3
|
import type { ExecutionJobOrigin } from '../../src/runtime/execution/jobs/types';
|
|
4
4
|
import { browserActions } from '../../src/runtime/plugins/browser-manifest-surface';
|
|
5
|
-
import {
|
|
5
|
+
import { executeControllerScopedPluginAction, getControllerPluginManifest, submitControllerPluginAction } from '../../src/runtime/plugins/store';
|
|
6
6
|
import {
|
|
7
|
+
CHATGPT_AUTOMATION_RATE_LIMITED,
|
|
8
|
+
CHATGPT_AUTOMATION_RATE_LIMITED_AFTER_SUBMIT,
|
|
7
9
|
CHATGPT_AUTOMATION_SUBMISSION_OUTCOME_UNKNOWN,
|
|
8
10
|
ChatgptProviderDeliveryError,
|
|
11
|
+
chatgptProviderPageFailure,
|
|
9
12
|
DEFAULT_CHATGPT_AUTOMATION_MODEL,
|
|
10
13
|
type ChatgptAutomationReasoning,
|
|
11
14
|
type ChatgptAutomationTabCleanupStatus,
|
|
15
|
+
type ChatgptProviderPageFailureCode,
|
|
12
16
|
} from './provider-delivery';
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
// The installed/connected primary Forge plugin is `forge`, not the separate
|
|
19
|
+
// Plugin Creator package `forge-current-1-8-1` or the Forge Recovery app.
|
|
20
|
+
// Live ChatGPT selection yields an exact app:// ProseMirror Forge chip.
|
|
21
|
+
const CHATGPT_FORGE_PLUGIN_SLUG = 'forge';
|
|
22
|
+
const CHATGPT_FORGE_PLUGIN_LABEL = 'forge';
|
|
23
|
+
const CHATGPT_FORGE_PLUGIN_PATH = 'app://asdk_app_6ac09022b26081918f20ff868c773824';
|
|
24
|
+
const CHATGPT_PLUGIN_PICKER_OPTIONS = '[data-mention-section-id="plugins"] [data-mention-section-items] > button';
|
|
25
|
+
|
|
15
26
|
|
|
16
27
|
type ChatgptBrowserActionOrigin = Pick<ExecutionJobOrigin, 'surface' | 'actor'>;
|
|
17
28
|
interface ChatgptBrowserActionContext {
|
|
@@ -28,16 +39,20 @@ export function withChatgptBrowserActionOrigin<T>(
|
|
|
28
39
|
return chatgptBrowserActionOrigin.run({ origin, authorizationGrantRefs }, operation);
|
|
29
40
|
}
|
|
30
41
|
|
|
31
|
-
|
|
32
|
-
|
|
42
|
+
/** Strip the legacy text trigger; only a real ChatGPT app chip selects Forge. */
|
|
43
|
+
export function chatgptSupervisorPromptBody(prompt: string): string {
|
|
44
|
+
const value = prompt.trim().replace(/^@forge(?:[ \t]*\r?\n|[ \t]+|$)/i, '').trim();
|
|
33
45
|
if (!value) throw new Error('CHATGPT_AUTOMATION_PROMPT_REQUIRED');
|
|
34
|
-
|
|
35
|
-
return `${DEFAULT_CHATGPT_AUTOMATION_PLUGIN_MENTION} ${value}`;
|
|
46
|
+
return value;
|
|
36
47
|
}
|
|
37
48
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
49
|
+
// ChatGPT's composer is a ProseMirror textbox; the historical #prompt-textarea id is no longer stable.
|
|
50
|
+
// Bind delivery to the semantic composer contract used by the live UI so readiness, fill, and Enter fallback share one selector authority.
|
|
51
|
+
const CHATGPT_PROMPT_SELECTOR = '[data-composer-markdown][role="textbox"][contenteditable="true"]';
|
|
52
|
+
const CHATGPT_SEND_SELECTOR = '[data-testid="send-button"], button[aria-label="Send"], button[aria-label="发送"], button[data-testid*="send"]';
|
|
53
|
+
const CHATGPT_USER_MESSAGE_SELECTOR = '[data-message-author-role="user"], [data-chatgpt-search-unit-key$=":user"], [data-content-search-unit-key$=":user"]';
|
|
54
|
+
const CHATGPT_ASSISTANT_MESSAGE_SELECTOR = '[data-message-author-role="assistant"], [data-chatgpt-search-unit-key$=":assistant"], [data-content-search-unit-key$=":assistant"]';
|
|
55
|
+
const CHATGPT_STOP_GENERATING_SELECTOR = '[data-testid="stop-button"], button[aria-label*="Stop"]';
|
|
41
56
|
const CHATGPT_INTELLIGENCE_CONTROL_SELECTORS = [
|
|
42
57
|
'main button, main [role="button"]',
|
|
43
58
|
'button, [role="button"]',
|
|
@@ -55,16 +70,15 @@ const CHATGPT_BROWSER_AUTHORIZATION_ACTIONS = new Set(
|
|
|
55
70
|
.map((action) => action.actionId),
|
|
56
71
|
);
|
|
57
72
|
|
|
58
|
-
const CHATGPT_BROWSER_TRANSPORT_OVERRIDES = {
|
|
59
|
-
browser_mode: 'attach_preferred',
|
|
60
|
-
cdp_attach_fallback: 'fail_closed',
|
|
61
|
-
native_attach_mode: 'auto',
|
|
62
|
-
native_browser_candidates: ['chrome'],
|
|
63
|
-
} as const;
|
|
64
|
-
|
|
65
73
|
export function chatgptBrowserActionArgs(actionId: string, args: Record<string, unknown>): Record<string, unknown> {
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
// Browser transport policy is controller-scoped configuration. Do not copy
|
|
75
|
+
// it into every action envelope: older Browser action schemas legitimately
|
|
76
|
+
// reject these optional fields even though the persisted configuration still
|
|
77
|
+
// supports the same policy. Keeping the envelope action-specific also lets a
|
|
78
|
+
// resumed ChatGPT round cross a connector/schema rotation without failing
|
|
79
|
+
// before the provider can observe the conversation.
|
|
80
|
+
void actionId;
|
|
81
|
+
return args;
|
|
68
82
|
}
|
|
69
83
|
|
|
70
84
|
export function chatgptBrowserActionResult(envelope: Record<string, unknown>, actionId: string): Record<string, unknown> {
|
|
@@ -97,11 +111,7 @@ async function controllerBrowserAction(
|
|
|
97
111
|
// reusable controller-scoped Browser grant. Scheduled delivery stays on the
|
|
98
112
|
// low-level executor and must present explicit refs already bound to this Work.
|
|
99
113
|
if (origin.surface === 'chatgpt-action' && CHATGPT_BROWSER_AUTHORIZATION_ACTIONS.has(actionId)) {
|
|
100
|
-
const submitted = await
|
|
101
|
-
controllerHome,
|
|
102
|
-
controllerPluginRepository(controllerHome),
|
|
103
|
-
actionRequest,
|
|
104
|
-
);
|
|
114
|
+
const submitted = await submitControllerPluginAction(controllerHome, actionRequest);
|
|
105
115
|
const grantId = submitted.authorization?.grantId?.trim();
|
|
106
116
|
if (grantId) context?.authorizationGrantRefs.add(grantId);
|
|
107
117
|
if (!submitted.result) throw new Error(`CHATGPT_BROWSER_ACTION_RESULT_INVALID:${actionId}`);
|
|
@@ -155,17 +165,31 @@ function normalizeChatgptOutboundText(value: string): string {
|
|
|
155
165
|
const CHATGPT_OUTBOUND_MESSAGE_UI_SUFFIXES = ['收起', 'Collapse', 'Show less'] as const;
|
|
156
166
|
const MAX_CHATGPT_OUTBOUND_VERIFICATION_CHARS = 100_000;
|
|
157
167
|
const MIN_TRUNCATED_CHATGPT_OUTBOUND_PREFIX_CHARS = 256;
|
|
168
|
+
const CHATGPT_PROVIDER_ERROR_SELECTOR = '[role="alert"], [aria-live="assertive"], [data-testid*="error"], [data-testid*="toast"], [data-sonner-toast]';
|
|
169
|
+
const CHATGPT_DELIVERY_FAILURE_PROBE_INTERVAL_MS = 1_000;
|
|
170
|
+
|
|
171
|
+
interface BrowserFailedRequest {
|
|
172
|
+
url?: string;
|
|
173
|
+
method?: string;
|
|
174
|
+
status?: number;
|
|
175
|
+
failure?: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
type ChatgptFailedRequestBaseline = Map<string, number>;
|
|
158
179
|
|
|
159
180
|
export function chatgptOutboundMessageMatchesPrompt(
|
|
160
181
|
messageText: string,
|
|
161
182
|
prompt: string,
|
|
162
|
-
options: { truncated?: boolean } = {},
|
|
183
|
+
options: { truncated?: boolean; boundForgePlugin?: boolean } = {},
|
|
163
184
|
): boolean {
|
|
164
185
|
const message = normalizeChatgptOutboundText(messageText);
|
|
165
186
|
const normalizedPrompt = normalizeChatgptOutboundText(prompt);
|
|
166
187
|
if (!message || !normalizedPrompt) return false;
|
|
167
|
-
|
|
168
|
-
|
|
188
|
+
const candidatePrompts = [normalizedPrompt,
|
|
189
|
+
...(options.boundForgePlugin ? [`${normalizedPrompt} ${CHATGPT_FORGE_PLUGIN_LABEL}`] : []),
|
|
190
|
+
];
|
|
191
|
+
if (candidatePrompts.some((candidate) => message === candidate)) return true;
|
|
192
|
+
if (candidatePrompts.some((candidate) => CHATGPT_OUTBOUND_MESSAGE_UI_SUFFIXES.some((suffix) => message === `${candidate} ${suffix}`))) return true;
|
|
169
193
|
// Browser text extraction is deliberately bounded. A large ControllerRound
|
|
170
194
|
// prompt can exceed that bound, so requiring exact equality makes successful
|
|
171
195
|
// submissions mechanically unverifiable. Accept only an explicitly reported
|
|
@@ -173,7 +197,140 @@ export function chatgptOutboundMessageMatchesPrompt(
|
|
|
173
197
|
// remains insufficient evidence.
|
|
174
198
|
return options.truncated === true
|
|
175
199
|
&& message.length >= MIN_TRUNCATED_CHATGPT_OUTBOUND_PREFIX_CHARS
|
|
176
|
-
&&
|
|
200
|
+
&& candidatePrompts.some((candidate) => candidate.startsWith(message));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function chatgptAutomationDeliveryFailure(
|
|
204
|
+
bodyText: string | undefined,
|
|
205
|
+
): ChatgptProviderPageFailureCode | undefined {
|
|
206
|
+
return chatgptProviderPageFailure(bodyText);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function chatgptSubmissionSettlementWaitBudget(timeoutMs?: number): number {
|
|
210
|
+
return Math.min(Math.max(timeoutMs ?? 30_000, 3_000), 30_000);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function chatgptSubmissionObservationDelayMs(observationIndex: number): number {
|
|
214
|
+
const schedule = [500, 1_000, 2_000, 3_000, 5_000] as const;
|
|
215
|
+
return schedule[Math.min(Math.max(0, Math.trunc(observationIndex)), schedule.length - 1)];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function chatgptSubmissionAcceptanceObserved(input: {
|
|
219
|
+
outboundConfirmed: boolean;
|
|
220
|
+
hasConversationIdentity: boolean;
|
|
221
|
+
assistantResponseObserved: boolean;
|
|
222
|
+
generationInProgress: boolean;
|
|
223
|
+
}): boolean {
|
|
224
|
+
return input.outboundConfirmed
|
|
225
|
+
&& input.hasConversationIdentity
|
|
226
|
+
&& (input.assistantResponseObserved || input.generationInProgress);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function chatgptComposerRetainsPrompt(
|
|
230
|
+
composerText: string | undefined,
|
|
231
|
+
prompt: string,
|
|
232
|
+
): boolean {
|
|
233
|
+
if (composerText === undefined) return false;
|
|
234
|
+
const composer = normalizeChatgptOutboundText(composerText);
|
|
235
|
+
const expected = normalizeChatgptOutboundText(prompt);
|
|
236
|
+
return Boolean(composer && expected && composer === expected);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function currentChatgptComposerText(
|
|
240
|
+
controllerHome: string,
|
|
241
|
+
workId: string,
|
|
242
|
+
browserSessionId: string,
|
|
243
|
+
timeoutMs?: number,
|
|
244
|
+
): Promise<string | undefined> {
|
|
245
|
+
const result = await controllerBrowserAction(controllerHome, workId, 'get_text', {
|
|
246
|
+
session_id: browserSessionId,
|
|
247
|
+
selector: CHATGPT_PROMPT_SELECTOR,
|
|
248
|
+
max_chars: MAX_CHATGPT_OUTBOUND_VERIFICATION_CHARS,
|
|
249
|
+
timeout_ms: Math.min(timeoutMs ?? 3_000, 3_000),
|
|
250
|
+
}, timeoutMs).catch(() => undefined);
|
|
251
|
+
return typeof result?.text === 'string' ? result.text : undefined;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function currentChatgptComposerHtml(
|
|
255
|
+
controllerHome: string,
|
|
256
|
+
workId: string,
|
|
257
|
+
browserSessionId: string,
|
|
258
|
+
timeoutMs?: number,
|
|
259
|
+
): Promise<string | undefined> {
|
|
260
|
+
const result = await controllerBrowserAction(controllerHome, workId, 'get_html', {
|
|
261
|
+
session_id: browserSessionId,
|
|
262
|
+
selector: CHATGPT_PROMPT_SELECTOR,
|
|
263
|
+
max_chars: MAX_CHATGPT_OUTBOUND_VERIFICATION_CHARS,
|
|
264
|
+
timeout_ms: Math.min(timeoutMs ?? 3_000, 3_000),
|
|
265
|
+
}, timeoutMs).catch(() => undefined);
|
|
266
|
+
return typeof result?.text === 'string' && result.truncated !== true ? result.text : undefined;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** A real ChatGPT plugin mention is a non-editable ProseMirror app chip, not @ text. */
|
|
270
|
+
export function chatgptForgePluginMentionBound(
|
|
271
|
+
composerHtml: string | undefined,
|
|
272
|
+
composerText: string | undefined,
|
|
273
|
+
prompt: string,
|
|
274
|
+
): boolean {
|
|
275
|
+
if (!composerHtml || !composerText) return false;
|
|
276
|
+
// Name and path must belong to ONE real app chip, never to different
|
|
277
|
+
// elements in the same composer HTML. A plain @forge is not an invocation.
|
|
278
|
+
const chips = [...composerHtml.matchAll(/<[^>]*\b(?:plugin|app)-mention-name="[^"]+"[^>]*>/g)].map((match) => match[0]);
|
|
279
|
+
if (chips.length !== 1 || !chips[0]!.includes(`app-mention-name="${CHATGPT_FORGE_PLUGIN_SLUG}"`)
|
|
280
|
+
|| !chips[0]!.includes(`app-mention-path="${CHATGPT_FORGE_PLUGIN_PATH}"`)) return false;
|
|
281
|
+
const normalized = normalizeChatgptOutboundText(composerText);
|
|
282
|
+
const payload = normalizeChatgptOutboundText(prompt);
|
|
283
|
+
return normalized === `${payload} ${CHATGPT_FORGE_PLUGIN_LABEL}`;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Return the single exact main-Forge suggestion after normalizing UI line breaks. */
|
|
287
|
+
export function chatgptForgePluginPickerIndex(labels: string[]): number | undefined {
|
|
288
|
+
const matches = labels.flatMap((label, index) => {
|
|
289
|
+
const value = normalizeChatgptOutboundText(label);
|
|
290
|
+
return value === CHATGPT_FORGE_PLUGIN_LABEL || value.startsWith(`${CHATGPT_FORGE_PLUGIN_LABEL} `)
|
|
291
|
+
? [index] : [];
|
|
292
|
+
});
|
|
293
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** Browser owns DOM actions; Supervisor remains the only effect and delivery owner. */
|
|
297
|
+
async function bindChatgptForgePluginMention(
|
|
298
|
+
controllerHome: string,
|
|
299
|
+
workId: string,
|
|
300
|
+
browserSessionId: string,
|
|
301
|
+
prompt: string,
|
|
302
|
+
targetUrl: string,
|
|
303
|
+
timeoutMs?: number,
|
|
304
|
+
): Promise<void> {
|
|
305
|
+
const baseArgs = { session_id: browserSessionId, timeout_ms: timeoutMs ?? 60_000 };
|
|
306
|
+
// The payload and final standalone @ paragraph were inserted together.
|
|
307
|
+
// ProseMirror drops the leading whitespace of a later ` @` insertion.
|
|
308
|
+
await controllerBrowserAction(controllerHome, workId, 'type', {
|
|
309
|
+
...baseArgs, selector: CHATGPT_PROMPT_SELECTOR, text: CHATGPT_FORGE_PLUGIN_LABEL,
|
|
310
|
+
post_action_wait_ms: 120,
|
|
311
|
+
}, timeoutMs);
|
|
312
|
+
const entries = await controllerBrowserAction(controllerHome, workId, 'query_all', {
|
|
313
|
+
...baseArgs, selector: CHATGPT_PLUGIN_PICKER_OPTIONS, limit: 80,
|
|
314
|
+
}, timeoutMs);
|
|
315
|
+
const index = chatgptForgePluginPickerIndex(queryMatches(entries).map(matchText));
|
|
316
|
+
if (index === undefined) {
|
|
317
|
+
throw new ChatgptProviderDeliveryError('CHATGPT_AUTOMATION_PLUGIN_NOT_IN_PICKER',
|
|
318
|
+
`CHATGPT_AUTOMATION_PLUGIN_NOT_IN_PICKER:${CHATGPT_FORGE_PLUGIN_SLUG}:${targetUrl}`,
|
|
319
|
+
{ conversationUrl: targetUrl });
|
|
320
|
+
}
|
|
321
|
+
// The option order was observed from this exact open picker. Never select
|
|
322
|
+
// another Forge-prefixed app as a fallback; verify the resulting app chip.
|
|
323
|
+
await controllerBrowserAction(controllerHome, workId, 'click', {
|
|
324
|
+
...baseArgs, selector: `${CHATGPT_PLUGIN_PICKER_OPTIONS}:nth-of-type(${index + 1})`,
|
|
325
|
+
}, timeoutMs);
|
|
326
|
+
const [composerHtml, composerText] = await Promise.all([
|
|
327
|
+
currentChatgptComposerHtml(controllerHome, workId, browserSessionId, timeoutMs),
|
|
328
|
+
currentChatgptComposerText(controllerHome, workId, browserSessionId, timeoutMs),
|
|
329
|
+
]);
|
|
330
|
+
if (!chatgptForgePluginMentionBound(composerHtml, composerText, prompt)) {
|
|
331
|
+
throw new ChatgptProviderDeliveryError('CHATGPT_AUTOMATION_PLUGIN_MENTION_UNVERIFIED',
|
|
332
|
+
`CHATGPT_AUTOMATION_PLUGIN_MENTION_UNVERIFIED:${targetUrl}`, { conversationUrl: targetUrl });
|
|
333
|
+
}
|
|
177
334
|
}
|
|
178
335
|
|
|
179
336
|
async function latestChatgptUserMessage(
|
|
@@ -213,8 +370,138 @@ async function fullChatgptMessageText(
|
|
|
213
370
|
};
|
|
214
371
|
}
|
|
215
372
|
|
|
373
|
+
async function latestChatgptAssistantMessage(
|
|
374
|
+
controllerHome: string,
|
|
375
|
+
workId: string,
|
|
376
|
+
browserSessionId: string,
|
|
377
|
+
timeoutMs?: number,
|
|
378
|
+
): Promise<{ selector?: string; preview: string }> {
|
|
379
|
+
const result = await controllerBrowserAction(controllerHome, workId, 'query_all', {
|
|
380
|
+
session_id: browserSessionId,
|
|
381
|
+
selector: CHATGPT_ASSISTANT_MESSAGE_SELECTOR,
|
|
382
|
+
limit: 1,
|
|
383
|
+
from_end: true,
|
|
384
|
+
timeout_ms: Math.min(timeoutMs ?? 3_000, 3_000),
|
|
385
|
+
}, timeoutMs);
|
|
386
|
+
const latest = queryMatches(result).at(-1);
|
|
387
|
+
return { selector: matchSelector(latest), preview: latest ? matchText(latest) : '' };
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function chatgptMessageObservationChanged(
|
|
391
|
+
before: { selector?: string; preview: string },
|
|
392
|
+
latest: { selector?: string; preview: string },
|
|
393
|
+
): boolean {
|
|
394
|
+
return Boolean(
|
|
395
|
+
(latest.selector && latest.selector !== before.selector)
|
|
396
|
+
|| (!before.preview && latest.preview)
|
|
397
|
+
|| latest.preview !== before.preview,
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
async function chatgptGenerationInProgress(
|
|
402
|
+
controllerHome: string,
|
|
403
|
+
workId: string,
|
|
404
|
+
browserSessionId: string,
|
|
405
|
+
timeoutMs?: number,
|
|
406
|
+
): Promise<boolean> {
|
|
407
|
+
const result = await controllerBrowserAction(controllerHome, workId, 'query_all', {
|
|
408
|
+
session_id: browserSessionId,
|
|
409
|
+
selector: CHATGPT_STOP_GENERATING_SELECTOR,
|
|
410
|
+
limit: 1,
|
|
411
|
+
timeout_ms: Math.min(timeoutMs ?? 1_000, 1_000),
|
|
412
|
+
}, timeoutMs).catch(() => undefined);
|
|
413
|
+
return queryMatches(result).length > 0;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function failedRequestKey(request: BrowserFailedRequest): string {
|
|
417
|
+
return `${request.method?.toUpperCase() ?? ''}|${request.status ?? ''}|${request.url ?? ''}|${request.failure ?? ''}`;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/** Only provider requests causally inside the current send pipeline may classify that send as rate-limited. */
|
|
421
|
+
export function chatgptFailedRequestIsCausalRateLimit(request: Pick<BrowserFailedRequest, 'url' | 'method' | 'status'>): boolean {
|
|
422
|
+
if (request.status !== 429 || request.method?.trim().toUpperCase() !== 'POST') return false;
|
|
423
|
+
try {
|
|
424
|
+
const url = new URL(request.url ?? '');
|
|
425
|
+
if (url.protocol !== 'https:' || url.hostname !== 'chatgpt.com') return false;
|
|
426
|
+
const path = url.pathname.toLowerCase();
|
|
427
|
+
return /^\/backend-api\/(?:f\/)?conversation(?:\/|$)/.test(path)
|
|
428
|
+
|| path === '/backend-api/sentinel/chat-requirements';
|
|
429
|
+
} catch {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
async function chatgptFailedRequestBaseline(
|
|
435
|
+
controllerHome: string,
|
|
436
|
+
workId: string,
|
|
437
|
+
browserSessionId: string,
|
|
438
|
+
timeoutMs?: number,
|
|
439
|
+
): Promise<ChatgptFailedRequestBaseline | undefined> {
|
|
440
|
+
const result = await controllerBrowserAction(controllerHome, workId, 'get_failed_requests', {
|
|
441
|
+
session_id: browserSessionId,
|
|
442
|
+
timeout_ms: Math.min(timeoutMs ?? 2_000, 2_000),
|
|
443
|
+
}, timeoutMs).catch(() => undefined);
|
|
444
|
+
if (!result || !Array.isArray(result.failedRequests)) return undefined;
|
|
445
|
+
const baseline = new Map<string, number>();
|
|
446
|
+
for (const request of result.failedRequests) {
|
|
447
|
+
if (!request || typeof request !== 'object') continue;
|
|
448
|
+
const key = failedRequestKey(request as BrowserFailedRequest);
|
|
449
|
+
baseline.set(key, (baseline.get(key) ?? 0) + 1);
|
|
450
|
+
}
|
|
451
|
+
return baseline;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
async function chatgptProviderFailureOnErrorUi(
|
|
455
|
+
controllerHome: string,
|
|
456
|
+
workId: string,
|
|
457
|
+
browserSessionId: string,
|
|
458
|
+
timeoutMs?: number,
|
|
459
|
+
): Promise<ChatgptProviderPageFailureCode | undefined> {
|
|
460
|
+
const result = await controllerBrowserAction(controllerHome, workId, 'query_all', {
|
|
461
|
+
session_id: browserSessionId,
|
|
462
|
+
selector: CHATGPT_PROVIDER_ERROR_SELECTOR,
|
|
463
|
+
limit: 20,
|
|
464
|
+
timeout_ms: Math.min(timeoutMs ?? 2_000, 2_000),
|
|
465
|
+
}, timeoutMs).catch(() => undefined);
|
|
466
|
+
for (const match of queryMatches(result)) {
|
|
467
|
+
const failure = chatgptAutomationDeliveryFailure(matchText(match));
|
|
468
|
+
if (failure) return failure;
|
|
469
|
+
}
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
async function chatgptDeliveryFailureOnPage(
|
|
474
|
+
controllerHome: string,
|
|
475
|
+
workId: string,
|
|
476
|
+
browserSessionId: string,
|
|
477
|
+
failedRequestBaseline: ChatgptFailedRequestBaseline | undefined,
|
|
478
|
+
timeoutMs?: number,
|
|
479
|
+
): Promise<ChatgptProviderPageFailureCode | undefined> {
|
|
480
|
+
const uiFailure = await chatgptProviderFailureOnErrorUi(controllerHome, workId, browserSessionId, timeoutMs);
|
|
481
|
+
if (uiFailure) return uiFailure;
|
|
482
|
+
if (!failedRequestBaseline) return undefined;
|
|
483
|
+
|
|
484
|
+
const current = await controllerBrowserAction(controllerHome, workId, 'get_failed_requests', {
|
|
485
|
+
session_id: browserSessionId,
|
|
486
|
+
timeout_ms: Math.min(timeoutMs ?? 2_000, 2_000),
|
|
487
|
+
}, timeoutMs).catch(() => undefined);
|
|
488
|
+
if (!current || !Array.isArray(current.failedRequests)) return undefined;
|
|
489
|
+
const seen = new Map<string, number>();
|
|
490
|
+
for (const value of current.failedRequests) {
|
|
491
|
+
if (!value || typeof value !== 'object') continue;
|
|
492
|
+
const request = value as BrowserFailedRequest;
|
|
493
|
+
const key = failedRequestKey(request);
|
|
494
|
+
const occurrence = (seen.get(key) ?? 0) + 1;
|
|
495
|
+
seen.set(key, occurrence);
|
|
496
|
+
const baselineCount = failedRequestBaseline.get(key) ?? 0;
|
|
497
|
+
if (occurrence <= baselineCount) continue;
|
|
498
|
+
if (chatgptFailedRequestIsCausalRateLimit(request)) return CHATGPT_AUTOMATION_RATE_LIMITED;
|
|
499
|
+
}
|
|
500
|
+
return undefined;
|
|
501
|
+
}
|
|
502
|
+
|
|
216
503
|
function chatgptSendControlUnavailable(error: unknown): boolean {
|
|
217
|
-
return error instanceof Error &&
|
|
504
|
+
return error instanceof Error && error.message.includes('PLUGIN_BROWSER_SELECTOR_UNAVAILABLE');
|
|
218
505
|
}
|
|
219
506
|
|
|
220
507
|
function normalizeExecutionControlLabel(label: string | undefined): string {
|
|
@@ -438,7 +725,7 @@ export async function ensureChatgptExecutionPreference(
|
|
|
438
725
|
for (let index = 0; index < Math.abs(targetValue - currentValue); index += 1) {
|
|
439
726
|
await controllerBrowserAction(controllerHome, workId, 'press', {
|
|
440
727
|
session_id: browserSessionId,
|
|
441
|
-
selector:
|
|
728
|
+
selector: CHATGPT_CAPABILITY_SLIDER_SELECTOR,
|
|
442
729
|
key: direction,
|
|
443
730
|
timeout_ms: timeoutMs ?? 60_000,
|
|
444
731
|
post_action_wait_ms: 120,
|
|
@@ -502,6 +789,42 @@ function chatgptUrlMatchesContinuationTarget(observedUrl: string, targetUrl: str
|
|
|
502
789
|
}
|
|
503
790
|
}
|
|
504
791
|
|
|
792
|
+
/** The saved Browser session id is not proof of the live native tab identity. */
|
|
793
|
+
export function chatgptBrowserObservationMatchesTarget(
|
|
794
|
+
observation: Record<string, unknown>,
|
|
795
|
+
browserSessionId: string,
|
|
796
|
+
targetUrl: string,
|
|
797
|
+
): boolean {
|
|
798
|
+
const observedSessionId = stringField(observation.sessionId) ?? resultSessionId(observation);
|
|
799
|
+
if (observedSessionId && observedSessionId !== browserSessionId) return false;
|
|
800
|
+
const connection = observation.browserConnection;
|
|
801
|
+
const liveTab = connection && typeof connection === 'object'
|
|
802
|
+
? (connection as Record<string, unknown>).tab : undefined;
|
|
803
|
+
const liveTabUrl = liveTab && typeof liveTab === 'object'
|
|
804
|
+
? stringField((liveTab as Record<string, unknown>).url) : undefined;
|
|
805
|
+
const urls = [resultUrl(observation), liveTabUrl].filter((url): url is string => Boolean(url));
|
|
806
|
+
return urls.length > 0 && urls.every((url) => chatgptUrlMatchesContinuationTarget(url, targetUrl));
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
async function verifyChatgptExactSubmissionTab(
|
|
810
|
+
controllerHome: string,
|
|
811
|
+
workId: string,
|
|
812
|
+
browserSessionId: string,
|
|
813
|
+
targetUrl: string,
|
|
814
|
+
timeoutMs?: number,
|
|
815
|
+
): Promise<void> {
|
|
816
|
+
const observed = await controllerBrowserAction(controllerHome, workId, 'get_text', {
|
|
817
|
+
session_id: browserSessionId,
|
|
818
|
+
selector: CHATGPT_PROMPT_SELECTOR,
|
|
819
|
+
max_chars: 1,
|
|
820
|
+
timeout_ms: Math.min(timeoutMs ?? 3_000, 3_000),
|
|
821
|
+
}, timeoutMs);
|
|
822
|
+
if (!chatgptBrowserObservationMatchesTarget(observed, browserSessionId, targetUrl)) {
|
|
823
|
+
throw new ChatgptProviderDeliveryError('CHATGPT_AUTOMATION_TARGET_IDENTITY_CHANGED',
|
|
824
|
+
`CHATGPT_AUTOMATION_TARGET_IDENTITY_CHANGED:${targetUrl}`, { conversationUrl: targetUrl });
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
505
828
|
function completeChatgptBrowserInventorySessions(
|
|
506
829
|
inventory: Record<string, unknown>,
|
|
507
830
|
): ChatgptBrowserSessionInventoryItem[] | undefined {
|
|
@@ -557,11 +880,19 @@ export async function closeChatgptAutomationTabAfterDispatch(
|
|
|
557
880
|
workId: string,
|
|
558
881
|
browserSessionId: string,
|
|
559
882
|
timeoutMs?: number,
|
|
883
|
+
authorizationGrantRefs: readonly string[] = [],
|
|
560
884
|
): Promise<{ status: ChatgptAutomationTabCleanupStatus; error?: { code: string; message: string } }> {
|
|
561
885
|
try {
|
|
562
|
-
const
|
|
886
|
+
const closePage = () => controllerBrowserAction(controllerHome, workId, 'close_page', {
|
|
563
887
|
session_id: browserSessionId,
|
|
564
888
|
}, Math.min(timeoutMs ?? 15_000, 15_000));
|
|
889
|
+
const closed = authorizationGrantRefs.length > 0
|
|
890
|
+
? await withChatgptBrowserActionOrigin(
|
|
891
|
+
{ surface: 'schedule', actor: 'chatgpt-work-continuation' },
|
|
892
|
+
closePage,
|
|
893
|
+
new Set(authorizationGrantRefs),
|
|
894
|
+
)
|
|
895
|
+
: await closePage();
|
|
565
896
|
if (closed.preservedUserOwnedTab === true) return { status: 'preserved_user_owned' };
|
|
566
897
|
if (closed.resourceClosed === true) return { status: 'closed' };
|
|
567
898
|
return { status: 'session_closed' };
|
|
@@ -588,6 +919,7 @@ export async function settleWorkChatgptAutomationTab(input: {
|
|
|
588
919
|
workId: string;
|
|
589
920
|
browserSessionId: string;
|
|
590
921
|
timeoutMs?: number;
|
|
922
|
+
authorizationGrantRefs?: readonly string[];
|
|
591
923
|
}): Promise<{ status: ChatgptAutomationTabCleanupStatus; error?: { code: string; message: string } }> {
|
|
592
924
|
if (input.browserSessionId.startsWith('forge-chatgpt-bridge-')) return { status: 'session_closed' };
|
|
593
925
|
return closeChatgptAutomationTabAfterDispatch(
|
|
@@ -595,6 +927,7 @@ export async function settleWorkChatgptAutomationTab(input: {
|
|
|
595
927
|
input.workId,
|
|
596
928
|
input.browserSessionId,
|
|
597
929
|
input.timeoutMs,
|
|
930
|
+
input.authorizationGrantRefs,
|
|
598
931
|
);
|
|
599
932
|
}
|
|
600
933
|
|
|
@@ -632,6 +965,14 @@ export async function navigateWorkConversation(
|
|
|
632
965
|
const opened = await controllerBrowserAction(controllerHome, workId, 'create_session', {
|
|
633
966
|
session_id: sessionId,
|
|
634
967
|
url,
|
|
968
|
+
// Direct Browser delivery must never silently escalate to the macOS
|
|
969
|
+
// Apple Events compatibility provider. Work-bound unattended delivery is
|
|
970
|
+
// owned by Workflow Supervisor's extension transport; this legacy direct
|
|
971
|
+
// lane uses a Forge-managed browser resource unless the caller explicitly
|
|
972
|
+
// configured a different transport elsewhere.
|
|
973
|
+
browser_mode: 'managed_persistent',
|
|
974
|
+
native_attach_mode: 'disabled',
|
|
975
|
+
cdp_attach_fallback: 'fail_closed',
|
|
635
976
|
wait_until: 'domcontentloaded',
|
|
636
977
|
timeout_ms: timeoutMs ?? 60_000,
|
|
637
978
|
retries: 1,
|
|
@@ -665,6 +1006,13 @@ export async function navigateWorkConversation(
|
|
|
665
1006
|
} catch (preflightError) {
|
|
666
1007
|
if (!chatgptAutomationNavigationRequiresReplacement(preflightError)) throw preflightError;
|
|
667
1008
|
const replacementSessionId = await openReplacement(browserSessionId, targetUrl);
|
|
1009
|
+
// create_session establishes only the session capability. Activating the
|
|
1010
|
+
// exact replacement page is an interaction-capability action, so an
|
|
1011
|
+
// interactive prepare also establishes the grant required by later
|
|
1012
|
+
// schedule-origin fill/click actions on this same origin.
|
|
1013
|
+
await controllerBrowserAction(controllerHome, workId, 'activate_page', {
|
|
1014
|
+
session_id: replacementSessionId,
|
|
1015
|
+
}, timeoutMs);
|
|
668
1016
|
return { submissionTargetUrl: targetUrl, recoveredFromStaleBinding: true, browserSessionId: replacementSessionId };
|
|
669
1017
|
}
|
|
670
1018
|
await navigate(browserSessionId, targetUrl);
|
|
@@ -689,15 +1037,11 @@ export async function navigateWorkConversation(
|
|
|
689
1037
|
const replacementSessionId = await openReplacement(browserSessionId, targetUrl);
|
|
690
1038
|
return { submissionTargetUrl: targetUrl, recoveredFromStaleBinding: false, browserSessionId: replacementSessionId };
|
|
691
1039
|
}
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
if (!chatgptAutomationNavigationRequiresReplacement(fallbackError)) throw fallbackError;
|
|
698
|
-
const replacementSessionId = await openReplacement(browserSessionId, 'https://chatgpt.com/');
|
|
699
|
-
return { submissionTargetUrl: 'https://chatgpt.com/', recoveredFromStaleBinding: true, browserSessionId: replacementSessionId };
|
|
700
|
-
}
|
|
1040
|
+
// A bound /c/<id> is transport identity, not a hint. Falling back to the
|
|
1041
|
+
// ChatGPT root silently creates a replacement conversation and can turn one
|
|
1042
|
+
// transient navigation failure into duplicate provider recovery. Preserve the
|
|
1043
|
+
// exact conversation and let the owning continuation reconcile or retry it.
|
|
1044
|
+
throw error;
|
|
701
1045
|
}
|
|
702
1046
|
}
|
|
703
1047
|
|
|
@@ -709,17 +1053,62 @@ export async function submitChatgptPrompt(
|
|
|
709
1053
|
targetUrl: string,
|
|
710
1054
|
timeoutMs?: number,
|
|
711
1055
|
): Promise<string> {
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
1056
|
+
// Verify the live native tab before reading/sending. The saved session may
|
|
1057
|
+
// have retargeted while its Browser handle remained stable.
|
|
1058
|
+
await verifyChatgptExactSubmissionTab(
|
|
1059
|
+
controllerHome, workId, browserSessionId, targetUrl, timeoutMs,
|
|
1060
|
+
);
|
|
1061
|
+
const renderedPrompt = chatgptSupervisorPromptBody(prompt);
|
|
1062
|
+
const [before, beforeAssistant, failedRequestBaseline, preexistingPageFailure] = await Promise.all([
|
|
1063
|
+
latestChatgptUserMessage(controllerHome, workId, browserSessionId, timeoutMs)
|
|
1064
|
+
.catch((): { selector?: string; preview: string; url?: string } => ({ selector: undefined, preview: '', url: targetUrl })),
|
|
1065
|
+
latestChatgptAssistantMessage(controllerHome, workId, browserSessionId, timeoutMs)
|
|
1066
|
+
.catch((): { selector?: string; preview: string } => ({ selector: undefined, preview: '' })),
|
|
1067
|
+
chatgptFailedRequestBaseline(controllerHome, workId, browserSessionId, timeoutMs),
|
|
1068
|
+
chatgptProviderFailureOnErrorUi(controllerHome, workId, browserSessionId, timeoutMs),
|
|
1069
|
+
]);
|
|
1070
|
+
if (preexistingPageFailure === CHATGPT_AUTOMATION_RATE_LIMITED) {
|
|
1071
|
+
throw new ChatgptProviderDeliveryError(
|
|
1072
|
+
CHATGPT_AUTOMATION_RATE_LIMITED,
|
|
1073
|
+
`${CHATGPT_AUTOMATION_RATE_LIMITED}:${targetUrl}`,
|
|
1074
|
+
{ conversationUrl: targetUrl },
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1077
|
+
const mentionTriggerDraft = `${renderedPrompt}\n@`;
|
|
715
1078
|
await controllerBrowserAction(controllerHome, workId, 'fill', {
|
|
716
1079
|
session_id: browserSessionId,
|
|
717
1080
|
selector: CHATGPT_PROMPT_SELECTOR,
|
|
718
|
-
text:
|
|
1081
|
+
text: mentionTriggerDraft,
|
|
719
1082
|
timeout_ms: timeoutMs ?? 60_000,
|
|
720
1083
|
post_action_wait_ms: 100,
|
|
721
1084
|
}, timeoutMs);
|
|
722
1085
|
|
|
1086
|
+
// Browser fill can report success even when the live ProseMirror composer did
|
|
1087
|
+
// not retain the intended payload. Never send or trigger Enter fallback on
|
|
1088
|
+
// an unverified draft; the owning effect must remain unreplayed.
|
|
1089
|
+
const verifiedComposerText = await currentChatgptComposerText(
|
|
1090
|
+
controllerHome, workId, browserSessionId, timeoutMs,
|
|
1091
|
+
);
|
|
1092
|
+
if (!chatgptComposerRetainsPrompt(verifiedComposerText, mentionTriggerDraft)) {
|
|
1093
|
+
throw new ChatgptProviderDeliveryError(
|
|
1094
|
+
'CHATGPT_AUTOMATION_COMPOSER_UNVERIFIED',
|
|
1095
|
+
`CHATGPT_AUTOMATION_COMPOSER_UNVERIFIED:${targetUrl}`,
|
|
1096
|
+
{ conversationUrl: targetUrl },
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// The immutable effect marker alone is not enough: choose the exact main
|
|
1101
|
+
// Forge app and verify its structured mention before sending the payload.
|
|
1102
|
+
await bindChatgptForgePluginMention(
|
|
1103
|
+
controllerHome, workId, browserSessionId, renderedPrompt, targetUrl, timeoutMs,
|
|
1104
|
+
);
|
|
1105
|
+
|
|
1106
|
+
// A popup or plugin-selection action can change the native tab. Re-attest
|
|
1107
|
+
// immediately before Send, never infer identity from a successful click.
|
|
1108
|
+
await verifyChatgptExactSubmissionTab(
|
|
1109
|
+
controllerHome, workId, browserSessionId, targetUrl, timeoutMs,
|
|
1110
|
+
);
|
|
1111
|
+
|
|
723
1112
|
let observedUrl = targetUrl;
|
|
724
1113
|
let submitOutcomeUnknown = false;
|
|
725
1114
|
let observedNewOutbound = false;
|
|
@@ -733,9 +1122,46 @@ export async function submitChatgptPrompt(
|
|
|
733
1122
|
observedUrl = resultUrl(sent) ?? observedUrl;
|
|
734
1123
|
} catch (error) {
|
|
735
1124
|
if (browserMutationOutcomeUnknown(error, 'click')) {
|
|
736
|
-
// Never replay an outcome-unknown submit
|
|
737
|
-
//
|
|
1125
|
+
// Never blind-replay an outcome-unknown submit. First reconcile the exact
|
|
1126
|
+
// provider state. If the same payload is still wholly present in the
|
|
1127
|
+
// composer, no new user message exists, and no conversation identity was
|
|
1128
|
+
// created, the original click is mechanically proven not to have committed.
|
|
1129
|
+
// Only then may the same provider dispatch resume Send once without
|
|
1130
|
+
// refilling the composer or creating a new semantic effect generation.
|
|
738
1131
|
submitOutcomeUnknown = true;
|
|
1132
|
+
const latestAfterUnknown = await latestChatgptUserMessage(
|
|
1133
|
+
controllerHome,
|
|
1134
|
+
workId,
|
|
1135
|
+
browserSessionId,
|
|
1136
|
+
timeoutMs,
|
|
1137
|
+
).catch(() => undefined);
|
|
1138
|
+
if (latestAfterUnknown) {
|
|
1139
|
+
observedUrl = latestAfterUnknown.url ?? observedUrl;
|
|
1140
|
+
observedNewOutbound = chatgptMessageObservationChanged(before, latestAfterUnknown);
|
|
1141
|
+
}
|
|
1142
|
+
const hasConversationIdentity = /\/c\/[^/?#]+/.test(observedUrl);
|
|
1143
|
+
const [composerHtml, composerText] = await Promise.all([
|
|
1144
|
+
currentChatgptComposerHtml(controllerHome, workId, browserSessionId, timeoutMs),
|
|
1145
|
+
currentChatgptComposerText(controllerHome, workId, browserSessionId, timeoutMs),
|
|
1146
|
+
]);
|
|
1147
|
+
if (
|
|
1148
|
+
!observedNewOutbound
|
|
1149
|
+
&& !hasConversationIdentity
|
|
1150
|
+
&& chatgptForgePluginMentionBound(composerHtml, composerText, renderedPrompt)
|
|
1151
|
+
) {
|
|
1152
|
+
try {
|
|
1153
|
+
const resumed = await controllerBrowserAction(controllerHome, workId, 'click', {
|
|
1154
|
+
session_id: browserSessionId,
|
|
1155
|
+
selector: CHATGPT_SEND_SELECTOR,
|
|
1156
|
+
timeout_ms: timeoutMs ?? 60_000,
|
|
1157
|
+
post_action_wait_ms: 250,
|
|
1158
|
+
}, timeoutMs);
|
|
1159
|
+
observedUrl = resultUrl(resumed) ?? observedUrl;
|
|
1160
|
+
submitOutcomeUnknown = false;
|
|
1161
|
+
} catch (resumeError) {
|
|
1162
|
+
if (!browserMutationOutcomeUnknown(resumeError, 'click')) throw resumeError;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
739
1165
|
} else if (chatgptSendControlUnavailable(error)) {
|
|
740
1166
|
const pressed = await controllerBrowserAction(controllerHome, workId, 'press', {
|
|
741
1167
|
session_id: browserSessionId,
|
|
@@ -750,28 +1176,78 @@ export async function submitChatgptPrompt(
|
|
|
750
1176
|
}
|
|
751
1177
|
}
|
|
752
1178
|
|
|
753
|
-
const deadline = Date.now() +
|
|
1179
|
+
const deadline = Date.now() + chatgptSubmissionSettlementWaitBudget(timeoutMs);
|
|
1180
|
+
let nextFailureProbeAt = 0;
|
|
1181
|
+
let observationIndex = 0;
|
|
754
1182
|
do {
|
|
755
1183
|
const latest = await latestChatgptUserMessage(controllerHome, workId, browserSessionId, timeoutMs).catch(() => undefined);
|
|
756
1184
|
if (latest) {
|
|
757
1185
|
observedUrl = latest.url ?? observedUrl;
|
|
758
|
-
const isNewOutbound =
|
|
759
|
-
(latest.selector && latest.selector !== before.selector)
|
|
760
|
-
|| (!before.preview && latest.preview)
|
|
761
|
-
|| latest.preview !== before.preview,
|
|
762
|
-
);
|
|
1186
|
+
const isNewOutbound = chatgptMessageObservationChanged(before, latest);
|
|
763
1187
|
if (isNewOutbound) {
|
|
764
1188
|
observedNewOutbound = true;
|
|
765
1189
|
const fullText = await fullChatgptMessageText(controllerHome, workId, browserSessionId, latest, timeoutMs);
|
|
766
|
-
|
|
767
|
-
|
|
1190
|
+
const outboundConfirmed = chatgptOutboundMessageMatchesPrompt(fullText.text, renderedPrompt, { truncated: fullText.truncated, boundForgePlugin: true });
|
|
1191
|
+
const hasConversationIdentity = /\/c\/[^/?#]+/.test(observedUrl);
|
|
1192
|
+
if (outboundConfirmed && hasConversationIdentity) {
|
|
1193
|
+
const [latestAssistant, generationInProgress] = await Promise.all([
|
|
1194
|
+
latestChatgptAssistantMessage(controllerHome, workId, browserSessionId, timeoutMs).catch(() => undefined),
|
|
1195
|
+
chatgptGenerationInProgress(controllerHome, workId, browserSessionId, timeoutMs),
|
|
1196
|
+
]);
|
|
1197
|
+
const assistantResponseObserved = Boolean(
|
|
1198
|
+
latestAssistant?.preview
|
|
1199
|
+
&& chatgptMessageObservationChanged(beforeAssistant, latestAssistant),
|
|
1200
|
+
);
|
|
1201
|
+
if (chatgptSubmissionAcceptanceObserved({
|
|
1202
|
+
outboundConfirmed,
|
|
1203
|
+
hasConversationIdentity,
|
|
1204
|
+
assistantResponseObserved,
|
|
1205
|
+
generationInProgress,
|
|
1206
|
+
})) {
|
|
1207
|
+
return observedUrl;
|
|
1208
|
+
}
|
|
1209
|
+
if (Date.now() >= nextFailureProbeAt) {
|
|
1210
|
+
const deliveryFailure = await chatgptDeliveryFailureOnPage(
|
|
1211
|
+
controllerHome,
|
|
1212
|
+
workId,
|
|
1213
|
+
browserSessionId,
|
|
1214
|
+
failedRequestBaseline,
|
|
1215
|
+
timeoutMs,
|
|
1216
|
+
);
|
|
1217
|
+
if (deliveryFailure) {
|
|
1218
|
+
const failureCode = deliveryFailure === CHATGPT_AUTOMATION_RATE_LIMITED
|
|
1219
|
+
? CHATGPT_AUTOMATION_RATE_LIMITED_AFTER_SUBMIT
|
|
1220
|
+
: deliveryFailure;
|
|
1221
|
+
throw new ChatgptProviderDeliveryError(
|
|
1222
|
+
failureCode,
|
|
1223
|
+
`${failureCode}:${observedUrl}`,
|
|
1224
|
+
{ conversationUrl: observedUrl },
|
|
1225
|
+
);
|
|
1226
|
+
}
|
|
1227
|
+
nextFailureProbeAt = Date.now() + CHATGPT_DELIVERY_FAILURE_PROBE_INTERVAL_MS;
|
|
1228
|
+
}
|
|
768
1229
|
}
|
|
769
1230
|
}
|
|
770
1231
|
}
|
|
771
|
-
|
|
1232
|
+
const remainingMs = deadline - Date.now();
|
|
1233
|
+
if (remainingMs <= 0) break;
|
|
1234
|
+
const observationDelayMs = chatgptSubmissionObservationDelayMs(observationIndex);
|
|
1235
|
+
observationIndex += 1;
|
|
1236
|
+
await new Promise((resolveWait) => setTimeout(resolveWait, Math.min(observationDelayMs, remainingMs)));
|
|
772
1237
|
} while (Date.now() < deadline);
|
|
773
1238
|
const hasConversationIdentity = /\/c\/[^/?#]+/.test(observedUrl);
|
|
774
|
-
const
|
|
1239
|
+
const finalComposerText = submitOutcomeUnknown && !observedNewOutbound && !hasConversationIdentity
|
|
1240
|
+
? await currentChatgptComposerText(controllerHome, workId, browserSessionId, timeoutMs)
|
|
1241
|
+
: undefined;
|
|
1242
|
+
const submitProvablyNotApplied = submitOutcomeUnknown
|
|
1243
|
+
&& !observedNewOutbound
|
|
1244
|
+
&& !hasConversationIdentity
|
|
1245
|
+
&& chatgptComposerRetainsPrompt(finalComposerText, renderedPrompt);
|
|
1246
|
+
// A fresh /c/<id> or any changed outbound user message is provider-side
|
|
1247
|
+
// evidence that the send may have committed even when DOM observation lagged.
|
|
1248
|
+
// Keep that ambiguity fenced. Conversely, an exact unchanged composer proves
|
|
1249
|
+
// the send did not commit and must not be mislabeled outcome_unknown.
|
|
1250
|
+
const failureCode = (submitOutcomeUnknown && !submitProvablyNotApplied) || hasConversationIdentity || observedNewOutbound
|
|
775
1251
|
? CHATGPT_AUTOMATION_SUBMISSION_OUTCOME_UNKNOWN
|
|
776
1252
|
: 'CHATGPT_AUTOMATION_SUBMISSION_NOT_CONFIRMED';
|
|
777
1253
|
throw new ChatgptProviderDeliveryError(
|
|
@@ -780,4 +1256,3 @@ export async function submitChatgptPrompt(
|
|
|
780
1256
|
{ conversationUrl: observedUrl },
|
|
781
1257
|
);
|
|
782
1258
|
}
|
|
783
|
-
|