@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
|
@@ -6,15 +6,16 @@ import { createInterface } from 'readline';
|
|
|
6
6
|
import { performance } from 'perf_hooks';
|
|
7
7
|
import { AssistantPluginError } from '../errors';
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
export const IOS_HID_TOOLCHAIN_VERSION = '11.24.0';
|
|
10
10
|
const WORKER_IDLE_MS = 15 * 60_000;
|
|
11
11
|
const WORKER_STARTUP_MS = 12_000;
|
|
12
|
-
const MUTATION_READY_BUDGET_MS = 2_500;
|
|
13
12
|
const REQUEST_TIMEOUT_MS = 12_000;
|
|
14
13
|
const RSD_ENDPOINT_CACHE_TTL_MS = 30_000;
|
|
15
14
|
const RSD_ENDPOINT_PERSISTED_TTL_MS = 10 * 60_000;
|
|
16
15
|
const MAX_TEXT_LENGTH = 2048;
|
|
17
16
|
const MAX_STDERR = 8 * 1024;
|
|
17
|
+
const TOOLCHAIN_PROBE_TTL_MS = 60_000;
|
|
18
|
+
const TOOLCHAIN_PROBE_TIMEOUT_MS = 5_000;
|
|
18
19
|
|
|
19
20
|
export interface RemoteXpcHidInput {
|
|
20
21
|
controllerHome: string;
|
|
@@ -99,6 +100,7 @@ const warmups = new Map<string, Promise<void>>();
|
|
|
99
100
|
const workerGenerations = new Map<string, number>();
|
|
100
101
|
const warmupFailures = new Map<string, WarmupFailure>();
|
|
101
102
|
const endpointCache = new Map<string, EndpointCacheEntry>();
|
|
103
|
+
const toolchainProbeCache = new Map<string, { checkedAt: number; installedVersion?: string; available: boolean; reason?: string }>();
|
|
102
104
|
|
|
103
105
|
export function setRemoteXpcHidExecutorForTest(executor: TestExecutor | undefined): void {
|
|
104
106
|
testExecutor = executor;
|
|
@@ -112,26 +114,71 @@ export function resetRemoteXpcHidForTest(): void {
|
|
|
112
114
|
workerGenerations.clear();
|
|
113
115
|
warmupFailures.clear();
|
|
114
116
|
endpointCache.clear();
|
|
117
|
+
toolchainProbeCache.clear();
|
|
115
118
|
}
|
|
116
119
|
|
|
117
|
-
|
|
120
|
+
const TOOLCHAIN_PROBE_SCRIPT = [
|
|
121
|
+
'from importlib.metadata import version',
|
|
122
|
+
'from pymobiledevice3.remote.remote_service_discovery import RemoteServiceDiscoveryService',
|
|
123
|
+
'from pymobiledevice3.remote.core_device.pasteboard_service import PasteboardService',
|
|
124
|
+
'from pymobiledevice3.remote.core_device.hid_service import UniversalHIDServiceService, touch_session',
|
|
125
|
+
"print(version('pymobiledevice3'))",
|
|
126
|
+
].join('; ');
|
|
127
|
+
|
|
128
|
+
function probeHidToolchain(python: string): { installedVersion?: string; available: boolean; reason?: string } {
|
|
129
|
+
const cached = toolchainProbeCache.get(python);
|
|
130
|
+
if (cached && Date.now() - cached.checkedAt <= TOOLCHAIN_PROBE_TTL_MS) return cached;
|
|
131
|
+
const result = spawnSync(python, ['-c', TOOLCHAIN_PROBE_SCRIPT], {
|
|
132
|
+
encoding: 'utf8', timeout: TOOLCHAIN_PROBE_TIMEOUT_MS, maxBuffer: 8 * 1024,
|
|
133
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
134
|
+
});
|
|
135
|
+
const installedVersion = typeof result.stdout === 'string' ? result.stdout.trim() : undefined;
|
|
136
|
+
const available = result.status === 0 && installedVersion === IOS_HID_TOOLCHAIN_VERSION && !result.error;
|
|
137
|
+
const reason = available ? undefined : result.error?.message ?? (result.status === 0
|
|
138
|
+
? `Expected pymobiledevice3 ${IOS_HID_TOOLCHAIN_VERSION}, found ${installedVersion || 'unknown'}.`
|
|
139
|
+
: `pymobiledevice3 import/version probe failed (exit ${result.status ?? 'unknown'}).`);
|
|
140
|
+
const probe = { checkedAt: Date.now(), installedVersion, available, reason };
|
|
141
|
+
// A failed probe is not durable: an explicitly authorized installer may
|
|
142
|
+
// finish immediately afterward without requiring a Runtime restart.
|
|
143
|
+
if (available) toolchainProbeCache.set(python, probe);
|
|
144
|
+
else toolchainProbeCache.delete(python);
|
|
145
|
+
return probe;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function hidToolchainStatus(controllerHome: string, env: NodeJS.ProcessEnv, allowProbe: boolean): Record<string, unknown> {
|
|
118
149
|
const python = resolvePython(controllerHome, env);
|
|
150
|
+
const cached = python ? toolchainProbeCache.get(python) : undefined;
|
|
151
|
+
const validCached = cached?.available === true && Date.now() - cached.checkedAt <= TOOLCHAIN_PROBE_TTL_MS
|
|
152
|
+
? cached : undefined;
|
|
153
|
+
const probe = python ? (allowProbe ? probeHidToolchain(python) : validCached) : undefined;
|
|
119
154
|
return {
|
|
120
155
|
backend: 'remote-xpc-hid',
|
|
121
|
-
available:
|
|
156
|
+
available: probe?.available === true,
|
|
122
157
|
python,
|
|
123
|
-
toolchainVersion:
|
|
158
|
+
toolchainVersion: IOS_HID_TOOLCHAIN_VERSION,
|
|
159
|
+
...(probe?.installedVersion ? { installedVersion: probe.installedVersion } : {}),
|
|
160
|
+
...(probe?.reason ? { reason: probe.reason } : {}),
|
|
124
161
|
transport: 'macos-trusted-coredevice-rsd',
|
|
125
162
|
runnerOwned: false,
|
|
126
163
|
};
|
|
127
164
|
}
|
|
128
165
|
|
|
166
|
+
// Manifest reads are passive: only an explicit HID action may start Python.
|
|
167
|
+
// This is a view of the same short-lived successful probe cache, not a second
|
|
168
|
+
// readiness authority or a durable grant.
|
|
169
|
+
export function remoteXpcHidCachedStatus(controllerHome: string, env: NodeJS.ProcessEnv = process.env): Record<string, unknown> {
|
|
170
|
+
return hidToolchainStatus(controllerHome, env, false);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function remoteXpcHidStatus(controllerHome: string, env: NodeJS.ProcessEnv = process.env): Record<string, unknown> {
|
|
174
|
+
return hidToolchainStatus(controllerHome, env, true);
|
|
175
|
+
}
|
|
176
|
+
|
|
129
177
|
function resolvePython(controllerHome: string, env: NodeJS.ProcessEnv): string | undefined {
|
|
130
178
|
const explicit = env.FORGE_IOS_HID_PYTHON?.trim();
|
|
131
179
|
const candidates = [
|
|
132
180
|
explicit,
|
|
133
|
-
join(controllerHome, 'toolchains', `pymobiledevice3-${
|
|
134
|
-
join(controllerHome, 'toolchains', `pymobiledevice3-${TOOLCHAIN_VERSION}`, 'bin', 'python'),
|
|
181
|
+
join(controllerHome, 'toolchains', `pymobiledevice3-${IOS_HID_TOOLCHAIN_VERSION}`, 'bin', 'python'),
|
|
135
182
|
].filter((value): value is string => Boolean(value));
|
|
136
183
|
return candidates.find((candidate) => existsSync(candidate));
|
|
137
184
|
}
|
|
@@ -143,6 +190,7 @@ import asyncio
|
|
|
143
190
|
import json
|
|
144
191
|
import sys
|
|
145
192
|
import time
|
|
193
|
+
from importlib.metadata import version as package_version
|
|
146
194
|
|
|
147
195
|
from pymobiledevice3.remote.remote_service_discovery import RemoteServiceDiscoveryService
|
|
148
196
|
from pymobiledevice3.remote.core_device.pasteboard_service import PasteboardService
|
|
@@ -222,7 +270,11 @@ async def main():
|
|
|
222
270
|
parser = argparse.ArgumentParser()
|
|
223
271
|
parser.add_argument('--host', required=True)
|
|
224
272
|
parser.add_argument('--port', required=True, type=int)
|
|
273
|
+
parser.add_argument('--expected-version', required=True)
|
|
225
274
|
args = parser.parse_args()
|
|
275
|
+
actual_version = package_version('pymobiledevice3')
|
|
276
|
+
if actual_version != args.expected_version:
|
|
277
|
+
raise RuntimeError(f'RemoteXPC HID pymobiledevice3 version mismatch: {actual_version} != {args.expected_version}')
|
|
226
278
|
async with RemoteServiceDiscoveryService((args.host, args.port)) as rsd:
|
|
227
279
|
async with touch_session(rsd) as hid:
|
|
228
280
|
connected = await hid.list_connected_services()
|
|
@@ -743,11 +795,12 @@ export function stopRemoteXpcHidForDevice(deviceIdentifier: string): Record<stri
|
|
|
743
795
|
}
|
|
744
796
|
|
|
745
797
|
function startWorker(input: Pick<RemoteXpcHidInput, 'controllerHome' | 'deviceIdentifier'>, endpoint: RsdEndpoint): WorkerRecord {
|
|
746
|
-
const
|
|
798
|
+
const status = remoteXpcHidStatus(input.controllerHome);
|
|
799
|
+
const python = status.available === true && typeof status.python === 'string' ? status.python : undefined;
|
|
747
800
|
if (!python) {
|
|
748
|
-
throw new AssistantPluginError('IOS_HID_TOOLCHAIN_MISSING', `The Controller-owned pymobiledevice3 ${
|
|
801
|
+
throw new AssistantPluginError('IOS_HID_TOOLCHAIN_MISSING', `The Controller-owned pymobiledevice3 ${IOS_HID_TOOLCHAIN_VERSION} toolchain is unavailable or incompatible.`, {
|
|
749
802
|
retryable: false,
|
|
750
|
-
details: { expected: join(input.controllerHome, 'toolchains', `pymobiledevice3-${
|
|
803
|
+
details: { expected: join(input.controllerHome, 'toolchains', `pymobiledevice3-${IOS_HID_TOOLCHAIN_VERSION}`, 'bin', 'python'), reason: status.reason },
|
|
751
804
|
});
|
|
752
805
|
}
|
|
753
806
|
const script = materializeWorker(input.controllerHome);
|
|
@@ -756,6 +809,7 @@ function startWorker(input: Pick<RemoteXpcHidInput, 'controllerHome' | 'deviceId
|
|
|
756
809
|
'-u', script,
|
|
757
810
|
'--host', endpoint.host,
|
|
758
811
|
'--port', String(endpoint.port),
|
|
812
|
+
'--expected-version', IOS_HID_TOOLCHAIN_VERSION,
|
|
759
813
|
], {
|
|
760
814
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
761
815
|
env: {
|
|
@@ -1089,23 +1143,11 @@ async function waitForMutationWorker(
|
|
|
1089
1143
|
}
|
|
1090
1144
|
const current = workers.get(input.deviceIdentifier);
|
|
1091
1145
|
const warmup = warmups.get(input.deviceIdentifier);
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
try {
|
|
1098
|
-
await Promise.race([
|
|
1099
|
-
readiness,
|
|
1100
|
-
new Promise<void>((resolve) => {
|
|
1101
|
-
timer = setTimeout(resolve, MUTATION_READY_BUDGET_MS);
|
|
1102
|
-
timer.unref?.();
|
|
1103
|
-
}),
|
|
1104
|
-
]);
|
|
1105
|
-
} finally {
|
|
1106
|
-
if (timer) clearTimeout(timer);
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1146
|
+
// Plugin actions use separate managed processes. A detached prewarm cannot
|
|
1147
|
+
// survive its owning action, so the first real mutation must finish its own
|
|
1148
|
+
// endpoint discovery and worker startup rather than time out and retry cold.
|
|
1149
|
+
const readiness = warmup ?? current?.ready.then(() => undefined).catch(() => undefined);
|
|
1150
|
+
if (readiness) await readiness;
|
|
1109
1151
|
const waitMs = Math.round((performance.now() - startedAt) * 100) / 100;
|
|
1110
1152
|
const worker = workers.get(input.deviceIdentifier);
|
|
1111
1153
|
if (!worker || worker.readyState !== 'ready') {
|
|
@@ -1115,15 +1157,13 @@ async function waitForMutationWorker(
|
|
|
1115
1157
|
}
|
|
1116
1158
|
throw new AssistantPluginError(
|
|
1117
1159
|
'IOS_HID_INPUT_NOT_READY',
|
|
1118
|
-
|
|
1160
|
+
'RemoteXPC HID worker did not reach ready state in this action. No input was sent.',
|
|
1119
1161
|
{
|
|
1120
1162
|
retryable: true,
|
|
1121
1163
|
details: {
|
|
1122
1164
|
deviceIdentifier: input.deviceIdentifier,
|
|
1123
1165
|
mutationDispatched: false,
|
|
1124
1166
|
workerReadyWaitMs: waitMs,
|
|
1125
|
-
readinessBudgetMs: MUTATION_READY_BUDGET_MS,
|
|
1126
|
-
prewarmContinues: warmups.has(input.deviceIdentifier) || worker?.readyState === 'starting',
|
|
1127
1167
|
},
|
|
1128
1168
|
},
|
|
1129
1169
|
);
|
|
@@ -33,14 +33,7 @@ import {
|
|
|
33
33
|
iosAgentDeviceStatus,
|
|
34
34
|
isIosAgentDeviceAction,
|
|
35
35
|
} from './ios-agent-device';
|
|
36
|
-
import {
|
|
37
|
-
executeIosPhysicalDeviceAction,
|
|
38
|
-
iosPhysicalDeviceActions,
|
|
39
|
-
iosPhysicalDeviceCapabilities,
|
|
40
|
-
iosPhysicalDeviceStatus,
|
|
41
|
-
isIosPhysicalDeviceAction,
|
|
42
|
-
resolveIosPhysicalDeviceAuthorizationContext,
|
|
43
|
-
} from './ios-physical-device';
|
|
36
|
+
import { iosPhysicalDeviceStatus, isIosPhysicalDeviceAction } from './ios-physical-device';
|
|
44
37
|
|
|
45
38
|
const IOS_PLUGIN_ID = 'ios';
|
|
46
39
|
|
|
@@ -99,26 +92,36 @@ function health(repoRoot: string): AssistantPluginHealth {
|
|
|
99
92
|
} as RepositoryRecord);
|
|
100
93
|
const currentPlatform = iosDevelopmentPlatform();
|
|
101
94
|
const platformOk = currentPlatform === 'darwin';
|
|
102
|
-
const
|
|
95
|
+
const developmentReady = platformOk && Boolean(xcode && 'ready' in xcode && xcode.ready);
|
|
96
|
+
const physicalDevice = iosPhysicalDeviceStatus();
|
|
97
|
+
const physicalReady = platformOk && physicalDevice.coreDeviceReady;
|
|
98
|
+
const agentDevice = iosAgentDeviceStatus({ repoRoot });
|
|
99
|
+
const semanticReady = agentDevice.available === true;
|
|
100
|
+
const pluginReady = platformOk && (developmentReady || physicalReady || semanticReady);
|
|
103
101
|
const warnings: string[] = [];
|
|
104
|
-
if (!platformOk) warnings.push('iOS
|
|
105
|
-
if (platformOk && !
|
|
106
|
-
|
|
102
|
+
if (!platformOk) warnings.push('iOS capabilities require a macOS host.');
|
|
103
|
+
if (platformOk && !developmentReady) warnings.push('Xcode/Simulator development capability is not fully ready on this host.');
|
|
104
|
+
if (platformOk && !physicalReady) warnings.push('CoreDevice physical-iPhone capability is not ready on this host.');
|
|
107
105
|
if (!discovery.ready) warnings.push('No .xcworkspace/.xcodeproj/Package.swift discovered in this repository yet.');
|
|
108
|
-
const status = userFacingStatusFrom(
|
|
106
|
+
const status = userFacingStatusFrom(developmentReady, discovery.ready, Boolean(xcode && 'simctlAvailable' in xcode && xcode.simctlAvailable), physicalReady);
|
|
109
107
|
return {
|
|
110
|
-
state: !platformOk ? 'disabled' :
|
|
108
|
+
state: !platformOk ? 'disabled' : pluginReady ? 'ready' : 'degraded',
|
|
111
109
|
checkedAt: now(),
|
|
112
|
-
ready:
|
|
113
|
-
probed: xcodeSnapshot.probed,
|
|
110
|
+
ready: pluginReady,
|
|
111
|
+
probed: xcodeSnapshot.probed || physicalDevice.probed || Boolean(agentDevice.available),
|
|
114
112
|
errors: [],
|
|
115
113
|
warnings,
|
|
116
114
|
details: {
|
|
117
|
-
provider: 'local-
|
|
115
|
+
provider: 'local-ios',
|
|
118
116
|
platform: currentPlatform,
|
|
119
117
|
userFacingStatus: status,
|
|
120
118
|
discoverable: discovery.ready,
|
|
121
119
|
defaultContainer: discovery.defaultContainer,
|
|
120
|
+
capabilities: {
|
|
121
|
+
development: developmentReady,
|
|
122
|
+
physicalDevice: physicalReady,
|
|
123
|
+
semanticAgentDevice: semanticReady,
|
|
124
|
+
},
|
|
122
125
|
xcode: xcode && 'ready' in xcode ? {
|
|
123
126
|
ready: xcode.ready,
|
|
124
127
|
xcodeSelectPath: 'xcodeSelectPath' in xcode ? xcode.xcodeSelectPath : undefined,
|
|
@@ -127,8 +130,8 @@ function health(repoRoot: string): AssistantPluginHealth {
|
|
|
127
130
|
probed: xcodeSnapshot.probed,
|
|
128
131
|
cached: xcodeSnapshot.cached,
|
|
129
132
|
} : xcode,
|
|
130
|
-
agentDevice
|
|
131
|
-
physicalDevice
|
|
133
|
+
agentDevice,
|
|
134
|
+
physicalDevice,
|
|
132
135
|
artifactRoots: {
|
|
133
136
|
repoLocal: '.forge/ios/',
|
|
134
137
|
controller: 'controller-home/repositories/<repoId>/artifacts/ios/',
|
|
@@ -137,21 +140,22 @@ function health(repoRoot: string): AssistantPluginHealth {
|
|
|
137
140
|
};
|
|
138
141
|
}
|
|
139
142
|
|
|
140
|
-
function userFacingStatusFrom(toolingReady: boolean, discoverable: boolean, simReady: boolean): string {
|
|
141
|
-
if (!toolingReady && !discoverable) return 'not_configured';
|
|
142
|
-
if (
|
|
143
|
+
function userFacingStatusFrom(toolingReady: boolean, discoverable: boolean, simReady: boolean, physicalReady: boolean): string {
|
|
144
|
+
if (!toolingReady && !physicalReady && !discoverable) return 'not_configured';
|
|
145
|
+
if (toolingReady && discoverable && simReady) return 'buildable';
|
|
146
|
+
if (physicalReady && !toolingReady) return 'physical_device_ready';
|
|
143
147
|
if (toolingReady && simReady) return 'simulator_ready';
|
|
144
148
|
if (discoverable) return 'discoverable';
|
|
145
|
-
if (
|
|
149
|
+
if (physicalReady) return 'physical_device_ready';
|
|
146
150
|
return 'not_configured';
|
|
147
151
|
}
|
|
148
152
|
|
|
149
|
-
function permissions(
|
|
153
|
+
function permissions(input: { developmentReady: boolean; physicalReady: boolean }): AssistantPluginPermissionScope[] {
|
|
150
154
|
return [
|
|
151
|
-
{ scope: 'ios.discover', mode: 'read', description: 'Discover
|
|
152
|
-
{ scope: 'ios.build', mode: 'write', description: 'Build iOS app targets into bounded DerivedData.', granted:
|
|
153
|
-
{ scope: 'ios.simulator', mode: 'write', description: 'Boot simulators, install, launch, screenshot, and collect logs.', granted:
|
|
154
|
-
{ scope: 'ios.device', mode: 'write', description: '
|
|
155
|
+
{ scope: 'ios.discover', mode: 'read', description: 'Discover iOS projects and paired physical devices.', granted: input.developmentReady || input.physicalReady, required: true },
|
|
156
|
+
{ scope: 'ios.build', mode: 'write', description: 'Build iOS app targets into bounded DerivedData.', granted: input.developmentReady, required: true },
|
|
157
|
+
{ scope: 'ios.simulator', mode: 'write', description: 'Boot simulators, install, launch, screenshot, and collect logs.', granted: input.developmentReady, required: true },
|
|
158
|
+
{ scope: 'ios.device', mode: 'write', description: 'Explicit paired-iPhone development/XCTest actions; everyday CoreDevice app interaction belongs to Computer.', granted: input.physicalReady, required: false },
|
|
155
159
|
];
|
|
156
160
|
}
|
|
157
161
|
|
|
@@ -172,7 +176,6 @@ function capabilities(): AssistantPluginCapability[] {
|
|
|
172
176
|
actions: ['smoke_review', 'build', 'xcode_test', 'launch_simulator', 'capture_screenshot'],
|
|
173
177
|
},
|
|
174
178
|
...iosAgentDeviceCapabilities(),
|
|
175
|
-
...iosPhysicalDeviceCapabilities(),
|
|
176
179
|
];
|
|
177
180
|
}
|
|
178
181
|
|
|
@@ -345,7 +348,7 @@ function actions(): AssistantPluginActionDescriptor[] {
|
|
|
345
348
|
description: 'Capture a simulator screenshot into controller artifact storage.',
|
|
346
349
|
readOnly: false,
|
|
347
350
|
risk: 'workspace_write',
|
|
348
|
-
confirmation: '
|
|
351
|
+
confirmation: 'authorization',
|
|
349
352
|
defaultTimeoutMs: 60_000,
|
|
350
353
|
cancellable: true,
|
|
351
354
|
idempotent: false,
|
|
@@ -395,7 +398,6 @@ function actions(): AssistantPluginActionDescriptor[] {
|
|
|
395
398
|
},
|
|
396
399
|
},
|
|
397
400
|
...iosAgentDeviceActions(),
|
|
398
|
-
...iosPhysicalDeviceActions(),
|
|
399
401
|
];
|
|
400
402
|
}
|
|
401
403
|
|
|
@@ -408,7 +410,7 @@ export function buildIosPluginManifest(previousRevision = 0, previousUpdatedAt?:
|
|
|
408
410
|
revision: Math.max(1, previousRevision || 1),
|
|
409
411
|
pluginId: IOS_PLUGIN_ID,
|
|
410
412
|
provider: 'apple-local',
|
|
411
|
-
displayName: 'iOS Development
|
|
413
|
+
displayName: 'iOS Development / Simulator / XCTest',
|
|
412
414
|
pluginVersion: '1.0.0',
|
|
413
415
|
authority: {
|
|
414
416
|
strategy: 'derived',
|
|
@@ -419,13 +421,16 @@ export function buildIosPluginManifest(previousRevision = 0, previousUpdatedAt?:
|
|
|
419
421
|
lifecycle: {
|
|
420
422
|
state: !enabled ? 'disabled' : state.ready ? 'enabled' : 'degraded',
|
|
421
423
|
reason: !enabled
|
|
422
|
-
? 'iOS
|
|
424
|
+
? 'iOS capabilities are only available on macOS hosts.'
|
|
423
425
|
: state.ready
|
|
424
|
-
? '
|
|
425
|
-
: state.warnings[0] ?? 'iOS
|
|
426
|
+
? 'At least one iOS development or physical-device capability is ready.'
|
|
427
|
+
: state.warnings[0] ?? 'iOS capabilities are partially available.',
|
|
426
428
|
},
|
|
427
429
|
health: state,
|
|
428
|
-
permissions: permissions(
|
|
430
|
+
permissions: permissions({
|
|
431
|
+
developmentReady: Boolean(state.details?.capabilities && typeof state.details.capabilities === 'object' && (state.details.capabilities as Record<string, unknown>).development === true),
|
|
432
|
+
physicalReady: Boolean(state.details?.capabilities && typeof state.details.capabilities === 'object' && (state.details.capabilities as Record<string, unknown>).physicalDevice === true),
|
|
433
|
+
}),
|
|
429
434
|
capabilities: capabilities(),
|
|
430
435
|
actions: actions(),
|
|
431
436
|
updatedAt: previousUpdatedAt ?? now(),
|
|
@@ -434,7 +439,9 @@ export function buildIosPluginManifest(previousRevision = 0, previousUpdatedAt?:
|
|
|
434
439
|
|
|
435
440
|
export async function executeIosPluginAction(input: AssistantPluginActionExecutionInput): Promise<Record<string, unknown>> {
|
|
436
441
|
if (isIosAgentDeviceAction(input.actionId)) return executeIosAgentDeviceAction(input);
|
|
437
|
-
if (isIosPhysicalDeviceAction(input.actionId))
|
|
442
|
+
if (isIosPhysicalDeviceAction(input.actionId)) {
|
|
443
|
+
throw new AssistantPluginError('PLUGIN_ACTION_NOT_SUPPORTED', `Physical iPhone app actions are available only through computer/${input.actionId}.`, { retryable: false });
|
|
444
|
+
}
|
|
438
445
|
const currentPlatform = iosDevelopmentPlatform();
|
|
439
446
|
if (currentPlatform !== 'darwin' && input.actionId !== 'discover_project' && input.actionId !== 'xcode_status') {
|
|
440
447
|
throw new AssistantPluginError('PLUGIN_DEPENDENCY_MISSING', 'iOS plugin actions require macOS with Xcode/Simulator.', {
|
|
@@ -590,9 +597,7 @@ export async function executeIosPluginAction(input: AssistantPluginActionExecuti
|
|
|
590
597
|
export const iosPluginAdapter = {
|
|
591
598
|
pluginId: IOS_PLUGIN_ID,
|
|
592
599
|
buildManifest: buildIosPluginManifest,
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
return resolveIosPhysicalDeviceAuthorizationContext(input);
|
|
596
|
-
},
|
|
600
|
+
// CoreDevice actions are public only through the Computer manifest; Xcode and XCTest stay here.
|
|
601
|
+
resolveAuthorizationContext: async () => undefined,
|
|
597
602
|
executeAction: executeIosPluginAction,
|
|
598
603
|
};
|
|
@@ -8,6 +8,7 @@ import { runBoundedProcess } from '../execution/thin-harness/async-process';
|
|
|
8
8
|
import { readJsonFile, writeJsonAtomic } from '../shared/json-files';
|
|
9
9
|
import { resolveTrustedNodeExecutable } from '../shared/trusted-node-executable';
|
|
10
10
|
import { AssistantPluginError, toAssistantPluginError } from './errors';
|
|
11
|
+
import { ensureIosDeviceOwnership, releaseIosDeviceOwnership, withIosDeviceTransientOwnership } from './ios-device-ownership';
|
|
11
12
|
import {
|
|
12
13
|
interactionAutomationEngine,
|
|
13
14
|
interactionMayOwnTarget,
|
|
@@ -734,6 +735,15 @@ function providerForDevice(device: AgentDeviceEntry): InteractionProvider {
|
|
|
734
735
|
return device.kind === 'simulator' ? SIMULATOR_PROVIDER : DEVICE_PROVIDER;
|
|
735
736
|
}
|
|
736
737
|
|
|
738
|
+
async function runPhysicalDeviceCommand<T>(
|
|
739
|
+
input: AssistantPluginActionExecutionInput,
|
|
740
|
+
device: AgentDeviceEntry,
|
|
741
|
+
operation: () => Promise<T>,
|
|
742
|
+
): Promise<T> {
|
|
743
|
+
if (device.kind !== 'device') return operation();
|
|
744
|
+
return withIosDeviceTransientOwnership(input.controllerHome, input.repoId, input.requestId, device.id, operation);
|
|
745
|
+
}
|
|
746
|
+
|
|
737
747
|
function selectTarget(input: AssistantPluginActionExecutionInput, selector?: string): AgentDeviceEntry {
|
|
738
748
|
const inventory = devices(input);
|
|
739
749
|
const normalizedSelector = selector?.trim().toLocaleLowerCase('en-US');
|
|
@@ -835,12 +845,26 @@ function requireRecord(input: AssistantPluginActionExecutionInput, allowTerminal
|
|
|
835
845
|
status: 'closing',
|
|
836
846
|
error: { code: 'AGENT_DEVICE_CLEANUP_FAILED', message: 'The expired agent-device session could not be closed; ownership remains fenced.' },
|
|
837
847
|
});
|
|
848
|
+
if (record.provider === DEVICE_PROVIDER && closed) releaseIosDeviceOwnership(input.controllerHome, record.owner.repoId, interactionId, record.targetId);
|
|
838
849
|
throw new AssistantPluginError(
|
|
839
850
|
closed ? 'AGENT_DEVICE_SESSION_EXPIRED' : 'AGENT_DEVICE_CLEANUP_FAILED',
|
|
840
851
|
closed ? 'The agent-device session expired and was closed.' : 'The expired agent-device session could not be closed; retry agent_device_close.',
|
|
841
852
|
{ retryable: !closed },
|
|
842
853
|
);
|
|
843
854
|
}
|
|
855
|
+
if (record.provider === DEVICE_PROVIDER) {
|
|
856
|
+
const ownership = ensureIosDeviceOwnership(input.controllerHome, input.repoId, interactionId, record.targetId);
|
|
857
|
+
if (!ownership.acquired) {
|
|
858
|
+
throw new AssistantPluginError('PLUGIN_RESOURCE_BUSY', 'The selected iPhone is already owned by another active Forge interaction.', {
|
|
859
|
+
retryable: true,
|
|
860
|
+
details: { interactionId, targetId: record.targetId, blocker: ownership.blocker },
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
const active = patchInteractionSession(input.repoRoot, record.provider, interactionId, {
|
|
864
|
+
expiresAt: new Date(hooks.now().getTime() + SESSION_EXPIRY_MS).toISOString(),
|
|
865
|
+
});
|
|
866
|
+
if (active) return active;
|
|
867
|
+
}
|
|
844
868
|
return record;
|
|
845
869
|
}
|
|
846
870
|
|
|
@@ -915,6 +939,7 @@ function reconcileExpiredSessions(input: AssistantPluginActionExecutionInput): v
|
|
|
915
939
|
status: 'closing',
|
|
916
940
|
error: { code: 'AGENT_DEVICE_CLEANUP_FAILED', message: 'The expired agent-device session could not be closed; ownership remains fenced.' },
|
|
917
941
|
});
|
|
942
|
+
if (record.provider === DEVICE_PROVIDER && closed) releaseIosDeviceOwnership(input.controllerHome, record.owner.repoId, record.interactionId, record.targetId);
|
|
918
943
|
}
|
|
919
944
|
}
|
|
920
945
|
|
|
@@ -934,6 +959,7 @@ function failSession(input: AssistantPluginActionExecutionInput, record: Interac
|
|
|
934
959
|
status: 'closing',
|
|
935
960
|
error: { code: 'AGENT_DEVICE_CLEANUP_FAILED', message: `${normalized.message}; cleanup failed and ownership remains fenced.` },
|
|
936
961
|
});
|
|
962
|
+
if (closed && record.provider === DEVICE_PROVIDER) releaseIosDeviceOwnership(input.controllerHome, record.owner.repoId, record.interactionId, record.targetId);
|
|
937
963
|
if (!closed) {
|
|
938
964
|
throw new AssistantPluginError('AGENT_DEVICE_CLEANUP_FAILED', 'The agent-device action failed and its session could not be closed; retry agent_device_close.', {
|
|
939
965
|
retryable: true,
|
|
@@ -2258,12 +2284,12 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
|
|
|
2258
2284
|
contractFingerprint: dependency.capabilityProfile.contractFingerprint,
|
|
2259
2285
|
device: selected,
|
|
2260
2286
|
physicalDeviceSupported: selected.kind === 'device',
|
|
2261
|
-
result: bounded(await runJsonAsync(input, args, {
|
|
2287
|
+
result: bounded(await runPhysicalDeviceCommand(input, selected, () => runJsonAsync(input, args, {
|
|
2262
2288
|
signing: signingFromArgs(input.args),
|
|
2263
2289
|
stateDir: targetRuntimeStateDir(input, selected),
|
|
2264
2290
|
failureCode: 'AGENT_DEVICE_DOCTOR_FAILED',
|
|
2265
2291
|
timeoutMs: 4 * 60_000,
|
|
2266
|
-
})),
|
|
2292
|
+
}))),
|
|
2267
2293
|
};
|
|
2268
2294
|
}
|
|
2269
2295
|
|
|
@@ -2276,14 +2302,14 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
|
|
|
2276
2302
|
contractFingerprint: dependency.capabilityProfile.contractFingerprint,
|
|
2277
2303
|
device: selected,
|
|
2278
2304
|
physicalDeviceSupported: selected.kind === 'device',
|
|
2279
|
-
result: bounded(await runJsonAsync(input, [
|
|
2305
|
+
result: bounded(await runPhysicalDeviceCommand(input, selected, () => runJsonAsync(input, [
|
|
2280
2306
|
'prepare', 'ios-runner', '--platform', 'ios', '--device', selected.name, '--timeout', '600000', '--json',
|
|
2281
2307
|
], {
|
|
2282
2308
|
signing,
|
|
2283
2309
|
stateDir: targetRuntimeStateDir(input, selected),
|
|
2284
2310
|
failureCode: 'AGENT_DEVICE_PREPARE_FAILED',
|
|
2285
2311
|
timeoutMs: 10 * 60_000,
|
|
2286
|
-
})),
|
|
2312
|
+
}))),
|
|
2287
2313
|
};
|
|
2288
2314
|
}
|
|
2289
2315
|
|
|
@@ -2298,6 +2324,19 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
|
|
|
2298
2324
|
const conflict = listInteractionSessions(input.repoRoot, provider).find((entry) =>
|
|
2299
2325
|
isInteractionSessionActive(entry.status) && interactionMayOwnTarget(entry, selected.aliases));
|
|
2300
2326
|
if (conflict) {
|
|
2327
|
+
if (selected.kind === 'device' && provider === DEVICE_PROVIDER && conflict.instructions === app && input.args.relaunch !== true) {
|
|
2328
|
+
const ownership = ensureIosDeviceOwnership(input.controllerHome, input.repoId, conflict.interactionId, selected.id);
|
|
2329
|
+
if (!ownership.acquired) {
|
|
2330
|
+
throw new AssistantPluginError('PLUGIN_RESOURCE_BUSY', 'The selected iPhone is already owned by another active Forge interaction.', {
|
|
2331
|
+
retryable: true,
|
|
2332
|
+
details: { interactionId: conflict.interactionId, targetId: conflict.targetId, blocker: ownership.blocker },
|
|
2333
|
+
});
|
|
2334
|
+
}
|
|
2335
|
+
const active = patchInteractionSession(input.repoRoot, provider, conflict.interactionId, {
|
|
2336
|
+
expiresAt: new Date(hooks.now().getTime() + SESSION_EXPIRY_MS).toISOString(),
|
|
2337
|
+
}) ?? conflict;
|
|
2338
|
+
return { provider: 'agent-device', version: dependency.detectedVersion ?? IOS_AGENT_DEVICE_VERSION, contractFingerprint: dependency.capabilityProfile.contractFingerprint, interaction: active, device: selected, physicalDeviceSupported: true, reusedSession: true };
|
|
2339
|
+
}
|
|
2301
2340
|
throw new AssistantPluginError('PLUGIN_RESOURCE_BUSY', 'The selected iOS target already has an active interaction.', {
|
|
2302
2341
|
retryable: true,
|
|
2303
2342
|
details: {
|
|
@@ -2310,6 +2349,15 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
|
|
|
2310
2349
|
}
|
|
2311
2350
|
pruneInteractionSessions(input.repoRoot, provider, 100);
|
|
2312
2351
|
const interactionId = `ios_agent_device_${randomUUID()}`;
|
|
2352
|
+
if (selected.kind === 'device') {
|
|
2353
|
+
const ownership = ensureIosDeviceOwnership(input.controllerHome, input.repoId, interactionId, selected.id);
|
|
2354
|
+
if (!ownership.acquired) {
|
|
2355
|
+
throw new AssistantPluginError('PLUGIN_RESOURCE_BUSY', 'The selected iPhone is already owned by another active Forge interaction.', {
|
|
2356
|
+
retryable: true,
|
|
2357
|
+
details: { interactionId, targetId: selected.id, blocker: ownership.blocker },
|
|
2358
|
+
});
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2313
2361
|
const createdAt = timestamp();
|
|
2314
2362
|
const record: InteractionSessionRecord = {
|
|
2315
2363
|
schemaVersion: 1,
|
|
@@ -2348,6 +2396,7 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
|
|
|
2348
2396
|
result: bounded(result),
|
|
2349
2397
|
};
|
|
2350
2398
|
} catch (error) {
|
|
2399
|
+
if (selected.kind === 'device') releaseIosDeviceOwnership(input.controllerHome, input.repoId, interactionId, selected.id);
|
|
2351
2400
|
return failSession(input, record, error);
|
|
2352
2401
|
}
|
|
2353
2402
|
}
|
|
@@ -2464,6 +2513,7 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
|
|
|
2464
2513
|
try {
|
|
2465
2514
|
const closedProvider = await closeProviderSession(input, current, args);
|
|
2466
2515
|
const closed = patchInteractionSession(input.repoRoot, current.provider, current.interactionId, { status: 'closed' }) ?? current;
|
|
2516
|
+
if (current.provider === DEVICE_PROVIDER) releaseIosDeviceOwnership(input.controllerHome, current.owner.repoId, current.interactionId, current.targetId);
|
|
2467
2517
|
return {
|
|
2468
2518
|
provider: 'agent-device',
|
|
2469
2519
|
interaction: closed,
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import {
|
|
2
|
+
acquireControllerLock,
|
|
3
|
+
ControllerLockContentionError,
|
|
4
|
+
readControllerLock,
|
|
5
|
+
releaseControllerLock,
|
|
6
|
+
renewControllerLock,
|
|
7
|
+
type ControllerLockRecord,
|
|
8
|
+
} from '../../cli/repositories/locks';
|
|
9
|
+
|
|
10
|
+
const IOS_DEVICE_LOCK_PREFIX = 'ios-device:';
|
|
11
|
+
const IOS_DEVICE_LOCK_TTL_MS = 2 * 60 * 60_000;
|
|
12
|
+
|
|
13
|
+
export interface IosDeviceOwnershipResult {
|
|
14
|
+
acquired: boolean;
|
|
15
|
+
lock?: ControllerLockRecord;
|
|
16
|
+
blocker?: Pick<ControllerLockRecord, 'lockId' | 'owner' | 'pid' | 'acquiredAt' | 'heartbeatAt' | 'expiresAt'>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function deviceResourceKey(deviceIdentifier: string): string {
|
|
20
|
+
const normalized = deviceIdentifier.trim().toUpperCase();
|
|
21
|
+
if (!normalized) throw new Error('IOS_DEVICE_IDENTIFIER_REQUIRED');
|
|
22
|
+
return `${IOS_DEVICE_LOCK_PREFIX}${normalized}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function sessionOwner(repoId: string, interactionId: string): string {
|
|
26
|
+
const repo = repoId.trim();
|
|
27
|
+
const interaction = interactionId.trim();
|
|
28
|
+
if (!repo || !interaction) throw new Error('IOS_DEVICE_OWNERSHIP_ID_REQUIRED');
|
|
29
|
+
return `ios-device-session:${repo}:${interaction}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function blocker(lock: ControllerLockRecord) {
|
|
33
|
+
return {
|
|
34
|
+
lockId: lock.lockId,
|
|
35
|
+
owner: lock.owner,
|
|
36
|
+
pid: lock.pid,
|
|
37
|
+
acquiredAt: lock.acquiredAt,
|
|
38
|
+
heartbeatAt: lock.heartbeatAt,
|
|
39
|
+
...(lock.expiresAt ? { expiresAt: lock.expiresAt } : {}),
|
|
40
|
+
} satisfies IosDeviceOwnershipResult['blocker'];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Use the hardware UDID as the single physical iPhone identity shared with XCTest.
|
|
44
|
+
// CoreDevice identifier is a transport-local locator, not the agent-device device id.
|
|
45
|
+
export function iosCoreDeviceOwnershipId(device: { identifier: string; udid?: string }): string {
|
|
46
|
+
const udid = device.udid?.trim();
|
|
47
|
+
if (!udid) throw new Error('IOS_DEVICE_UDID_REQUIRED');
|
|
48
|
+
return udid;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function ensureIosDeviceOwnership(
|
|
52
|
+
controllerHome: string,
|
|
53
|
+
repoId: string,
|
|
54
|
+
interactionId: string,
|
|
55
|
+
deviceIdentifier: string,
|
|
56
|
+
): IosDeviceOwnershipResult {
|
|
57
|
+
const key = { scope: 'global' as const, resource: deviceResourceKey(deviceIdentifier) };
|
|
58
|
+
const owner = sessionOwner(repoId, interactionId);
|
|
59
|
+
const current = readControllerLock(controllerHome, key);
|
|
60
|
+
if (current) {
|
|
61
|
+
if (current.owner !== owner) return { acquired: false, blocker: blocker(current) };
|
|
62
|
+
return { acquired: true, lock: renewControllerLock(controllerHome, key, current.lockId, IOS_DEVICE_LOCK_TTL_MS) };
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
return { acquired: true, lock: acquireControllerLock(controllerHome, key, owner, IOS_DEVICE_LOCK_TTL_MS) };
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if (!(error instanceof ControllerLockContentionError)) throw error;
|
|
68
|
+
const raced = readControllerLock(controllerHome, key);
|
|
69
|
+
if (!raced) return { acquired: false };
|
|
70
|
+
if (raced.owner !== owner) return { acquired: false, blocker: blocker(raced) };
|
|
71
|
+
return { acquired: true, lock: renewControllerLock(controllerHome, key, raced.lockId, IOS_DEVICE_LOCK_TTL_MS) };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function releaseIosDeviceOwnership(
|
|
76
|
+
controllerHome: string,
|
|
77
|
+
repoId: string,
|
|
78
|
+
interactionId: string,
|
|
79
|
+
deviceIdentifier: string,
|
|
80
|
+
): boolean {
|
|
81
|
+
const key = { scope: 'global' as const, resource: deviceResourceKey(deviceIdentifier) };
|
|
82
|
+
const current = readControllerLock(controllerHome, key);
|
|
83
|
+
if (!current || current.owner !== sessionOwner(repoId, interactionId)) return false;
|
|
84
|
+
releaseControllerLock(controllerHome, key, current.lockId);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function withIosDeviceTransientOwnership<T>(
|
|
89
|
+
controllerHome: string,
|
|
90
|
+
repoId: string,
|
|
91
|
+
requestId: string,
|
|
92
|
+
deviceIdentifier: string,
|
|
93
|
+
operation: () => T | Promise<T>,
|
|
94
|
+
): Promise<T> {
|
|
95
|
+
const key = { scope: 'global' as const, resource: deviceResourceKey(deviceIdentifier) };
|
|
96
|
+
const owner = `ios-device-transient:${repoId}:${requestId}`;
|
|
97
|
+
const lock = acquireControllerLock(controllerHome, key, owner, undefined);
|
|
98
|
+
try {
|
|
99
|
+
return await operation();
|
|
100
|
+
} finally {
|
|
101
|
+
releaseControllerLock(controllerHome, key, lock.lockId);
|
|
102
|
+
}
|
|
103
|
+
}
|