@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
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createPrivateKey, sign } from 'crypto';
|
|
1
|
+
import { createHash, createPrivateKey, sign } from 'crypto';
|
|
2
2
|
import { accessSync, constants as fsConstants, existsSync, mkdirSync, promises as fsPromises, readFileSync, statSync, writeFileSync } from 'fs';
|
|
3
|
-
import { dirname, join } from 'path';
|
|
3
|
+
import { basename, dirname, extname, isAbsolute, join, relative, resolve } from 'path';
|
|
4
4
|
import { CONTROLLER_SCOPE_REPO_ID, controllerSystemRoot } from '../../cli/repositories/controller-home';
|
|
5
5
|
import type {
|
|
6
6
|
AssistantPluginActionDescriptor,
|
|
@@ -16,6 +16,7 @@ import { readRepositoryPluginConfig, writeRepositoryPluginConfig } from './confi
|
|
|
16
16
|
import { buildQueryString, encodeBase64Url, stableMockId } from './google-shared';
|
|
17
17
|
|
|
18
18
|
const APP_STORE_CONNECT_PLUGIN_ID = 'app_store_connect';
|
|
19
|
+
const CONTROLLER_PLUGIN_CONFIG_SCOPE = 'controller:global';
|
|
19
20
|
const API_BASE_URL = 'https://api.appstoreconnect.apple.com';
|
|
20
21
|
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
21
22
|
const PRIVATE_KEY_READ_MAX_ATTEMPTS = 4;
|
|
@@ -107,7 +108,7 @@ function repositoryConfig(repoRoot: string, controllerHome?: string, repoId?: st
|
|
|
107
108
|
|
|
108
109
|
function loadConfig(repoRoot: string, controllerHome?: string, repoId?: string): AppStoreConnectPluginConfig {
|
|
109
110
|
const global = controllerHome ? readConfigFile(globalConfigPath(controllerHome)) : undefined;
|
|
110
|
-
if (repoId === CONTROLLER_SCOPE_REPO_ID) return normalizeConfig(global ?? {});
|
|
111
|
+
if (repoId === CONTROLLER_SCOPE_REPO_ID || repoId === CONTROLLER_PLUGIN_CONFIG_SCOPE) return normalizeConfig(global ?? {});
|
|
111
112
|
const local = repositoryConfig(repoRoot, controllerHome, repoId);
|
|
112
113
|
return normalizeConfig({ ...(global ?? {}), ...(local ?? {}) });
|
|
113
114
|
}
|
|
@@ -123,7 +124,7 @@ function saveConfig(
|
|
|
123
124
|
repoId?: string,
|
|
124
125
|
): AppStoreConnectPluginConfig {
|
|
125
126
|
const cleanPatch = definedPatch(patch);
|
|
126
|
-
if (controllerHome && repoId ===
|
|
127
|
+
if (controllerHome && repoId === CONTROLLER_PLUGIN_CONFIG_SCOPE) {
|
|
127
128
|
const path = globalConfigPath(controllerHome);
|
|
128
129
|
const next = normalizeConfig({ ...(readConfigFile(path) ?? {}), ...cleanPatch });
|
|
129
130
|
mkdirSync(dirname(path), { recursive: true });
|
|
@@ -131,6 +132,7 @@ function saveConfig(
|
|
|
131
132
|
return next;
|
|
132
133
|
}
|
|
133
134
|
|
|
135
|
+
if (repoId === CONTROLLER_SCOPE_REPO_ID) throw new Error('APP_STORE_CONNECT_LEGACY_CONTROLLER_SCOPE_WRITE_RETIRED');
|
|
134
136
|
if (!controllerHome || !repoId) throw new Error('APP_STORE_CONNECT_CONTROLLER_CONTEXT_REQUIRED');
|
|
135
137
|
// Repository state is an overlay only. Do not materialize inherited global
|
|
136
138
|
// credential references into every repository just because configure ran.
|
|
@@ -199,9 +201,9 @@ async function readPrivateKeyFile(path: string, source: string): Promise<{ key?:
|
|
|
199
201
|
}
|
|
200
202
|
if (code === 'EDEADLK') {
|
|
201
203
|
throw new AssistantPluginError(
|
|
202
|
-
'
|
|
203
|
-
'App Store Connect private key is
|
|
204
|
-
{ retryable:
|
|
204
|
+
'PLUGIN_AUTH_REQUIRED',
|
|
205
|
+
'Configured App Store Connect private key is not locally available. Keep File Provider/iCloud credentials downloaded or configure a stable local private_key_path.',
|
|
206
|
+
{ retryable: false, details: { credentialSource: source, code, localCredentialUnavailable: true } },
|
|
205
207
|
);
|
|
206
208
|
}
|
|
207
209
|
throw new AssistantPluginError(
|
|
@@ -211,7 +213,11 @@ async function readPrivateKeyFile(path: string, source: string): Promise<{ key?:
|
|
|
211
213
|
);
|
|
212
214
|
}
|
|
213
215
|
}
|
|
214
|
-
throw new AssistantPluginError(
|
|
216
|
+
throw new AssistantPluginError(
|
|
217
|
+
'PLUGIN_AUTH_REQUIRED',
|
|
218
|
+
'Configured App Store Connect private key is not locally available.',
|
|
219
|
+
{ retryable: false, details: { credentialSource: source, localCredentialUnavailable: true } },
|
|
220
|
+
);
|
|
215
221
|
}
|
|
216
222
|
|
|
217
223
|
async function privateKeyMaterial(config: AppStoreConnectPluginConfig): Promise<{ key?: string; source?: string; warning?: string }> {
|
|
@@ -223,6 +229,23 @@ async function privateKeyMaterial(config: AppStoreConnectPluginConfig): Promise<
|
|
|
223
229
|
return {};
|
|
224
230
|
}
|
|
225
231
|
|
|
232
|
+
async function resolveLiveAuthStatus(config: AppStoreConnectPluginConfig): Promise<AppStoreConnectAuthState> {
|
|
233
|
+
const auth = resolveAuth(config);
|
|
234
|
+
if (config.provider !== 'app-store-connect-api' || !config.enabled || !auth.ready) return auth;
|
|
235
|
+
try {
|
|
236
|
+
const material = await privateKeyMaterial(config);
|
|
237
|
+
if (material.key) return auth;
|
|
238
|
+
const detail = material.warning ?? 'Configured App Store Connect private key is not locally readable.';
|
|
239
|
+
return { ...auth, ready: false, authenticated: false, errors: [...auth.errors, detail] };
|
|
240
|
+
} catch (error) {
|
|
241
|
+
if (error instanceof AssistantPluginError && error.code === 'PLUGIN_AUTH_REQUIRED') {
|
|
242
|
+
const detail = error.message.replace(/^PLUGIN_AUTH_REQUIRED:\s*/, '');
|
|
243
|
+
return { ...auth, ready: false, authenticated: false, errors: [...auth.errors, detail] };
|
|
244
|
+
}
|
|
245
|
+
throw error;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
226
249
|
function resolveAuth(config: AppStoreConnectPluginConfig): AppStoreConnectAuthState {
|
|
227
250
|
if (config.provider === 'mock') {
|
|
228
251
|
return {
|
|
@@ -436,6 +459,7 @@ function permissions(ready: boolean): AssistantPluginPermissionScope[] {
|
|
|
436
459
|
permission('appstoreconnect.apps.read', 'read', 'Read App Store Connect apps, versions, localizations, builds, and TestFlight groups.', ready),
|
|
437
460
|
permission('appstoreconnect.developer_resources.read', 'read', 'Read Apple Developer bundle IDs, capabilities, certificates, devices, and provisioning profiles.', ready),
|
|
438
461
|
permission('appstoreconnect.metadata.write', 'write', 'Patch App Store Connect metadata after dry-run review and authorization.', ready),
|
|
462
|
+
permission('appstoreconnect.screenshots.write', 'write', 'Upload and order App Store screenshots in verified app/version/locale/device sets.', ready),
|
|
439
463
|
permission('appstoreconnect.testflight.write', 'write', 'Assign builds to TestFlight groups and prepare beta review submissions.', ready),
|
|
440
464
|
permission('appstoreconnect.release.write', 'write', 'Create App Store versions and gated review submissions.', ready),
|
|
441
465
|
permission('appstoreconnect.xcodecloud.read', 'read', 'Read Xcode Cloud products and workflow configuration.', ready),
|
|
@@ -463,6 +487,12 @@ function capabilities(): AssistantPluginCapability[] {
|
|
|
463
487
|
scopes: ['appstoreconnect.developer_resources.read'],
|
|
464
488
|
actions: ['list_bundle_ids', 'list_bundle_id_capabilities', 'list_certificates', 'list_devices', 'list_profiles'],
|
|
465
489
|
},
|
|
490
|
+
{
|
|
491
|
+
capabilityId: 'app-store-screenshots', title: 'App Store Screenshots',
|
|
492
|
+
description: 'Read screenshot sets and safely upload or order localized screenshots through official Apple reservations and upload operations.',
|
|
493
|
+
scopes: ['appstoreconnect.apps.read', 'appstoreconnect.screenshots.write'],
|
|
494
|
+
actions: ['list_app_screenshot_sets', 'list_app_screenshots', 'upload_app_screenshot', 'reorder_app_screenshots'],
|
|
495
|
+
},
|
|
466
496
|
{
|
|
467
497
|
capabilityId: 'app-store-metadata',
|
|
468
498
|
title: 'App Metadata Update',
|
|
@@ -503,7 +533,7 @@ function actions(): AssistantPluginActionDescriptor[] {
|
|
|
503
533
|
return [
|
|
504
534
|
{
|
|
505
535
|
actionId: 'configure', title: 'Configure App Store Connect plugin', description: 'Enable official App Store Connect API access and save non-secret defaults.', readOnly: false, risk: 'workspace_write', confirmation: 'authorization', defaultTimeoutMs: 30_000, cancellable: true, idempotent: true,
|
|
506
|
-
scopes: ['appstoreconnect.apps.read', 'appstoreconnect.developer_resources.read', 'appstoreconnect.metadata.write', 'appstoreconnect.testflight.write', 'appstoreconnect.release.write', 'appstoreconnect.xcodecloud.read', 'appstoreconnect.xcodecloud.write'], resourceClaims: [{ resource: 'repo-state', mode: 'write' }],
|
|
536
|
+
scopes: ['appstoreconnect.apps.read', 'appstoreconnect.developer_resources.read', 'appstoreconnect.metadata.write', 'appstoreconnect.screenshots.write', 'appstoreconnect.testflight.write', 'appstoreconnect.release.write', 'appstoreconnect.xcodecloud.read', 'appstoreconnect.xcodecloud.write'], resourceClaims: [{ resource: 'repo-state', mode: 'write' }],
|
|
507
537
|
argumentsSchema: { type: 'object', properties: { enabled: { type: 'boolean' }, provider: { type: 'string', enum: ['mock', 'app-store-connect-api'] }, issuer_id: { type: 'string' }, key_id: { type: 'string' }, private_key_path: { type: 'string' }, clear_private_key_path: { type: 'boolean' }, clear_api_identity: { type: 'boolean' }, team_id: { type: 'string' }, clear_team_id: { type: 'boolean' }, default_app_id: { type: 'string' }, clear_default_app_id: { type: 'boolean' }, default_locale: { type: 'string' }, default_timeout_ms: { type: 'number' } }, additionalProperties: false },
|
|
508
538
|
},
|
|
509
539
|
{ actionId: 'auth_status', title: 'Check App Store Connect auth', description: 'Report API readiness without returning secrets.', readOnly: true, risk: 'readonly', confirmation: 'none', defaultTimeoutMs: 10_000, cancellable: true, idempotent: true, scopes: ['appstoreconnect.apps.read'], resourceClaims: [], argumentsSchema: { type: 'object', properties: {}, additionalProperties: false } },
|
|
@@ -515,6 +545,10 @@ function actions(): AssistantPluginActionDescriptor[] {
|
|
|
515
545
|
{ actionId: 'list_profiles', title: 'List provisioning profiles', description: 'Read Apple Developer provisioning profiles, optionally filtered by profile name or type.', readOnly: true, risk: 'readonly', confirmation: 'none', defaultTimeoutMs: 45_000, cancellable: true, idempotent: true, scopes: ['appstoreconnect.developer_resources.read'], resourceClaims: readRemote, argumentsSchema: { type: 'object', properties: { name: { type: 'string' }, profile_type: { type: 'string' }, limit: { type: 'number' } }, additionalProperties: false } },
|
|
516
546
|
{ actionId: 'list_app_store_versions', title: 'List App Store versions', description: 'List App Store versions for one app.', readOnly: true, risk: 'readonly', confirmation: 'none', defaultTimeoutMs: 45_000, cancellable: true, idempotent: true, scopes: ['appstoreconnect.apps.read'], resourceClaims: readRemote, argumentsSchema: { type: 'object', properties: { app_id: { type: 'string' }, limit: { type: 'number' } }, additionalProperties: false } },
|
|
517
547
|
{ actionId: 'list_app_store_version_localizations', title: 'List App Store version localizations', description: 'List localizations for one App Store version.', readOnly: true, risk: 'readonly', confirmation: 'none', defaultTimeoutMs: 45_000, cancellable: true, idempotent: true, scopes: ['appstoreconnect.apps.read'], resourceClaims: readRemote, argumentsSchema: { type: 'object', properties: { version_id: { type: 'string' }, limit: { type: 'number' } }, required: ['version_id'], additionalProperties: false } },
|
|
548
|
+
{ actionId: 'list_app_screenshot_sets', title: 'List localized screenshot sets', description: 'Read device screenshot sets for a verified exact App/version/locale.', readOnly: true, risk: 'readonly', confirmation: 'none', defaultTimeoutMs: 60_000, cancellable: true, idempotent: true, scopes: ['appstoreconnect.apps.read'], resourceClaims: readRemote, argumentsSchema: { type: 'object', properties: { app_id: { type: 'string' }, version_id: { type: 'string' }, localization_id: { type: 'string' }, locale: { type: 'string' } }, required: ['app_id', 'version_id', 'localization_id', 'locale'], additionalProperties: false } },
|
|
549
|
+
{ actionId: 'list_app_screenshots', title: 'List localized screenshots', description: 'Read screenshot upload state and checksum for an exact device screenshot set.', readOnly: true, risk: 'readonly', confirmation: 'none', defaultTimeoutMs: 60_000, cancellable: true, idempotent: true, scopes: ['appstoreconnect.apps.read'], resourceClaims: readRemote, argumentsSchema: { type: 'object', properties: { app_id: { type: 'string' }, version_id: { type: 'string' }, localization_id: { type: 'string' }, locale: { type: 'string' }, display_type: { type: 'string' } }, required: ['app_id', 'version_id', 'localization_id', 'locale', 'display_type'], additionalProperties: false } },
|
|
550
|
+
{ actionId: 'upload_app_screenshot', title: 'Upload localized App screenshot', description: 'Verify exact App/version/locale/device, reserve Apple upload, PUT signed byte ranges, commit MD5, return processing state. Reconcile by checksum before retry.', readOnly: false, risk: 'remote_write', confirmation: 'authorization', defaultTimeoutMs: 180_000, cancellable: true, idempotent: false, scopes: ['appstoreconnect.screenshots.write'], resourceClaims: writeRemote, argumentsSchema: { type: 'object', properties: { app_id: { type: 'string' }, version_id: { type: 'string' }, localization_id: { type: 'string' }, locale: { type: 'string' }, display_type: { type: 'string' }, file_path: { type: 'string' }, expected_sha256: { type: 'string' }, dry_run: { type: 'boolean' } }, required: ['app_id', 'version_id', 'localization_id', 'locale', 'display_type', 'file_path'], additionalProperties: false } },
|
|
551
|
+
{ actionId: 'reorder_app_screenshots', title: 'Reorder localized screenshots', description: 'Replace exact screenshot ID order after reconciling same-set membership and processing state.', readOnly: false, risk: 'remote_write', confirmation: 'authorization', defaultTimeoutMs: 90_000, cancellable: true, idempotent: false, scopes: ['appstoreconnect.screenshots.write'], resourceClaims: writeRemote, argumentsSchema: { type: 'object', properties: { app_id: { type: 'string' }, version_id: { type: 'string' }, localization_id: { type: 'string' }, locale: { type: 'string' }, display_type: { type: 'string' }, screenshot_ids: { type: 'array', items: { type: 'string' }, minItems: 1, maxItems: 10 }, dry_run: { type: 'boolean' } }, required: ['app_id', 'version_id', 'localization_id', 'locale', 'display_type', 'screenshot_ids'], additionalProperties: false } },
|
|
518
552
|
{ actionId: 'get_app_info', title: 'Get app info', description: 'Get App Info records and localizations for one app.', readOnly: true, risk: 'readonly', confirmation: 'none', defaultTimeoutMs: 45_000, cancellable: true, idempotent: true, scopes: ['appstoreconnect.apps.read'], resourceClaims: readRemote, argumentsSchema: { type: 'object', properties: { app_id: { type: 'string' } }, additionalProperties: false } },
|
|
519
553
|
{ actionId: 'list_app_infos', title: 'List app infos', description: 'List App Info records for one app.', readOnly: true, risk: 'readonly', confirmation: 'none', defaultTimeoutMs: 45_000, cancellable: true, idempotent: true, scopes: ['appstoreconnect.apps.read'], resourceClaims: readRemote, argumentsSchema: { type: 'object', properties: { app_id: { type: 'string' }, limit: { type: 'number' } }, additionalProperties: false } },
|
|
520
554
|
{ actionId: 'list_builds', title: 'List builds', description: 'List recent builds for one app with processing state fields.', readOnly: true, risk: 'readonly', confirmation: 'none', defaultTimeoutMs: 45_000, cancellable: true, idempotent: true, scopes: ['appstoreconnect.apps.read'], resourceClaims: readRemote, argumentsSchema: { type: 'object', properties: { app_id: { type: 'string' }, limit: { type: 'number' } }, additionalProperties: false } },
|
|
@@ -565,6 +599,205 @@ function actions(): AssistantPluginActionDescriptor[] {
|
|
|
565
599
|
];
|
|
566
600
|
}
|
|
567
601
|
|
|
602
|
+
|
|
603
|
+
type AscScreenshotResource = {
|
|
604
|
+
id: string;
|
|
605
|
+
attributes?: {
|
|
606
|
+
locale?: string; platform?: string; appStoreState?: string; screenshotDisplayType?: string; fileName?: string; fileSize?: number;
|
|
607
|
+
sourceFileChecksum?: string | null; assetDeliveryState?: { state?: string; errors?: unknown[] };
|
|
608
|
+
uploadOperations?: Array<{ method: string; url: string; offset: number; length: number;
|
|
609
|
+
requestHeaders?: Array<{ name: string; value: string }> }>;
|
|
610
|
+
};
|
|
611
|
+
relationships?: Record<string, { data?: { id: string } | null }>;
|
|
612
|
+
};
|
|
613
|
+
type AscScreenshotResponse = { data: AscScreenshotResource };
|
|
614
|
+
type AscScreenshotList = { data: AscScreenshotResource[] };
|
|
615
|
+
function safeScreenshot(resource: AscScreenshotResource): Record<string, unknown> {
|
|
616
|
+
return { id: resource.id, fileName: resource.attributes?.fileName, fileSize: resource.attributes?.fileSize,
|
|
617
|
+
sourceFileChecksum: resource.attributes?.sourceFileChecksum ?? null,
|
|
618
|
+
state: resource.attributes?.assetDeliveryState?.state,
|
|
619
|
+
processingErrorCount: resource.attributes?.assetDeliveryState?.errors?.length ?? 0 };
|
|
620
|
+
}
|
|
621
|
+
async function verifyScreenshotOwner(config: AppStoreConnectPluginConfig, args: Record<string, unknown>): Promise<string> {
|
|
622
|
+
const app = requiredArg(args, 'app_id'), versionId = requiredArg(args, 'version_id');
|
|
623
|
+
const locId = requiredArg(args, 'localization_id'), locale = requiredArg(args, 'locale');
|
|
624
|
+
// Use the exact App's version and that version's localization collections:
|
|
625
|
+
// JSON:API relationships may contain only links, not linkage data.
|
|
626
|
+
const versions = await apiRequest<AscScreenshotList>(config, {
|
|
627
|
+
path: '/v1/apps/' + encodeURIComponent(app) + '/appStoreVersions', query: { limit: 200 },
|
|
628
|
+
});
|
|
629
|
+
const exactVersion = versions.data?.find((v) => v.id === versionId);
|
|
630
|
+
if (!exactVersion || exactVersion.attributes?.platform !== 'IOS' ||
|
|
631
|
+
exactVersion.attributes?.appStoreState !== 'PREPARE_FOR_SUBMISSION')
|
|
632
|
+
throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'Screenshot target must be an editable iOS version of the specified App.', { retryable: false });
|
|
633
|
+
const localizations = await apiRequest<AscScreenshotList>(config, {
|
|
634
|
+
path: '/v1/appStoreVersions/' + encodeURIComponent(versionId) + '/appStoreVersionLocalizations',
|
|
635
|
+
query: { 'filter[locale]': locale, limit: 200 },
|
|
636
|
+
});
|
|
637
|
+
if (!localizations.data?.some((loc) => loc.id === locId && loc.attributes?.locale === locale))
|
|
638
|
+
throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'Screenshot version/locale ownership mismatch.', { retryable: false });
|
|
639
|
+
return locId;
|
|
640
|
+
}
|
|
641
|
+
function screenshotType(args: Record<string, unknown>): string {
|
|
642
|
+
const display = requiredArg(args, 'display_type');
|
|
643
|
+
if (!/^APP_(IPHONE|IPAD|WATCH|APPLE_TV|DESKTOP|APPLE_VISION_PRO)[A-Z0-9_]*$/.test(display))
|
|
644
|
+
throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'Unsupported screenshot display type.', { retryable: false });
|
|
645
|
+
return display;
|
|
646
|
+
}
|
|
647
|
+
async function listScreenshotSets(config: AppStoreConnectPluginConfig, localizationId: string): Promise<AscScreenshotResource[]> {
|
|
648
|
+
const response = await apiRequest<AscScreenshotList>(config, {
|
|
649
|
+
path: '/v1/appStoreVersionLocalizations/' + encodeURIComponent(localizationId) + '/appScreenshotSets', query: { limit: 100 },
|
|
650
|
+
});
|
|
651
|
+
if (!Array.isArray(response.data)) throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Malformed screenshot sets.', { retryable: false });
|
|
652
|
+
return response.data;
|
|
653
|
+
}
|
|
654
|
+
async function findScreenshotSet(config: AppStoreConnectPluginConfig, locId: string, display: string, create: boolean): Promise<string | undefined> {
|
|
655
|
+
const matches = (await listScreenshotSets(config, locId)).filter((s) => s.attributes?.screenshotDisplayType === display);
|
|
656
|
+
if (matches.length > 1) throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Duplicate device screenshot sets.', { retryable: false });
|
|
657
|
+
if (matches.length) return matches[0].id;
|
|
658
|
+
if (!create) return undefined;
|
|
659
|
+
const created = await apiRequest<AscScreenshotResponse>(config, { path: '/v1/appScreenshotSets', method: 'POST',
|
|
660
|
+
body: { data: { type: 'appScreenshotSets', attributes: { screenshotDisplayType: display },
|
|
661
|
+
relationships: { appStoreVersionLocalization: { data: { type: 'appStoreVersionLocalizations', id: locId } } } } } });
|
|
662
|
+
if (!created.data?.id) throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Apple did not return a screenshot set ID.', { retryable: false });
|
|
663
|
+
return created.data.id;
|
|
664
|
+
}
|
|
665
|
+
async function listScreenshots(config: AppStoreConnectPluginConfig, setId: string): Promise<AscScreenshotResource[]> {
|
|
666
|
+
const response = await apiRequest<AscScreenshotList>(config, {
|
|
667
|
+
path: '/v1/appScreenshotSets/' + encodeURIComponent(setId) + '/appScreenshots', query: { limit: 100 },
|
|
668
|
+
});
|
|
669
|
+
if (!Array.isArray(response.data)) throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Malformed screenshot inventory.', { retryable: false });
|
|
670
|
+
return response.data;
|
|
671
|
+
}
|
|
672
|
+
async function screenshotFile(repoRoot: string, inputPath: string) {
|
|
673
|
+
const root = await fsPromises.realpath(repoRoot);
|
|
674
|
+
const path = await fsPromises.realpath(resolve(root, inputPath));
|
|
675
|
+
const rel = relative(root, path);
|
|
676
|
+
if (!rel || rel === '..' || rel.startsWith('../') || isAbsolute(rel))
|
|
677
|
+
throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'Screenshot file must be inside the authorized checkout.', { retryable: false });
|
|
678
|
+
const stat = await fsPromises.stat(path);
|
|
679
|
+
if (!stat.isFile() || stat.size === 0 || stat.size > 25 * 1024 * 1024)
|
|
680
|
+
throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'Screenshot must be a nonempty image under 25 MiB.', { retryable: false });
|
|
681
|
+
const bytes = await fsPromises.readFile(path), name = basename(path), ext = extname(name).toLowerCase();
|
|
682
|
+
const jpeg = (ext === '.jpg' || ext === '.jpeg') && bytes[0] === 0xff && bytes[1] === 0xd8;
|
|
683
|
+
const png = ext === '.png' && bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]));
|
|
684
|
+
if (!jpeg && !png) throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'Screenshot image extension/signature mismatch.', { retryable: false });
|
|
685
|
+
return { bytes, name, relativePath: rel, sha256: createHash('sha256').update(bytes).digest('hex'), md5: createHash('md5').update(bytes).digest('hex') };
|
|
686
|
+
}
|
|
687
|
+
async function uploadScreenshotParts(parts: NonNullable<NonNullable<AscScreenshotResource['attributes']>['uploadOperations']>, bytes: Buffer): Promise<void> {
|
|
688
|
+
const ordered = [...parts].sort((a, b) => a.offset - b.offset);
|
|
689
|
+
let cursor = 0;
|
|
690
|
+
for (const part of ordered) {
|
|
691
|
+
if (!Number.isSafeInteger(part.offset) || !Number.isSafeInteger(part.length) || part.length <= 0 ||
|
|
692
|
+
part.offset !== cursor || part.length + cursor > bytes.length || part.method !== 'PUT')
|
|
693
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Invalid or non-contiguous Apple upload range.', { retryable: false });
|
|
694
|
+
const url = new URL(part.url);
|
|
695
|
+
if (url.protocol !== 'https:' || !(url.hostname === 'apple.com' || url.hostname.endsWith('.apple.com')) ||
|
|
696
|
+
url.username || url.password)
|
|
697
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Unexpected Apple upload host.', { retryable: false });
|
|
698
|
+
for (const h of part.requestHeaders ?? [])
|
|
699
|
+
if (!/^(content-type|content-md5|x-amz-[a-z0-9-]+|x-apple-[a-z0-9-]+)$/i.test(h.name))
|
|
700
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Unexpected Apple upload header.', { retryable: false });
|
|
701
|
+
cursor += part.length;
|
|
702
|
+
}
|
|
703
|
+
if (!ordered.length || cursor !== bytes.length)
|
|
704
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Apple upload operations do not cover the file.', { retryable: false });
|
|
705
|
+
for (const part of ordered) {
|
|
706
|
+
const controller = new AbortController(), timer = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
|
|
707
|
+
try {
|
|
708
|
+
const response = await fetch(part.url, { method: 'PUT',
|
|
709
|
+
headers: Object.fromEntries((part.requestHeaders ?? []).map((h) => [h.name, h.value])),
|
|
710
|
+
body: new Uint8Array(bytes.subarray(part.offset, part.offset + part.length)), redirect: 'manual', signal: controller.signal });
|
|
711
|
+
if (!response.ok) throw new Error('UPLOAD_HTTP_ERROR');
|
|
712
|
+
} catch {
|
|
713
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Screenshot part outcome is unknown. Reconcile reservation before retry.', {
|
|
714
|
+
retryable: false, details: { offset: part.offset, length: part.length } });
|
|
715
|
+
} finally { clearTimeout(timer); }
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
async function waitForScreenshotProcessing(config: AppStoreConnectPluginConfig, screenshotId: string, md5: string):
|
|
719
|
+
Promise<{ resource: AscScreenshotResource; complete: boolean }> {
|
|
720
|
+
// Apple commits asynchronously: UPLOAD_COMPLETE means accepted, not processed.
|
|
721
|
+
// Bounded polling never repeats a reservation or an uncertain upload/commit.
|
|
722
|
+
const deadline = Date.now() + 45_000;
|
|
723
|
+
for (;;) {
|
|
724
|
+
const response = await apiRequest<AscScreenshotResponse>(config, {
|
|
725
|
+
path: '/v1/appScreenshots/' + encodeURIComponent(screenshotId),
|
|
726
|
+
timeoutMs: 15_000,
|
|
727
|
+
});
|
|
728
|
+
const resource = response.data;
|
|
729
|
+
if (!resource || resource.id !== screenshotId)
|
|
730
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Apple screenshot identity readback failed; inspect before retry.', {
|
|
731
|
+
retryable: false, details: { screenshotId } });
|
|
732
|
+
const checksum = resource.attributes?.sourceFileChecksum?.toLowerCase();
|
|
733
|
+
if (checksum && checksum !== md5)
|
|
734
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Apple screenshot checksum mismatch; inspect before retry.', {
|
|
735
|
+
retryable: false, details: { screenshotId } });
|
|
736
|
+
const state = resource.attributes?.assetDeliveryState?.state;
|
|
737
|
+
if (state === 'FAILED')
|
|
738
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Apple screenshot processing failed; inspect before retry.', {
|
|
739
|
+
retryable: false, details: { screenshotId, processingErrorCount: resource.attributes?.assetDeliveryState?.errors?.length ?? 0 } });
|
|
740
|
+
if (state === 'COMPLETE') {
|
|
741
|
+
if (checksum !== md5)
|
|
742
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Apple screenshot completed without a confirmed checksum; inspect before retry.', {
|
|
743
|
+
retryable: false, details: { screenshotId } });
|
|
744
|
+
return { resource, complete: true };
|
|
745
|
+
}
|
|
746
|
+
if (Date.now() >= deadline) {
|
|
747
|
+
if (state !== 'UPLOAD_COMPLETE')
|
|
748
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Apple screenshot commit state is unresolved; inspect before retry.', {
|
|
749
|
+
retryable: false, details: { screenshotId, state: state ?? null } });
|
|
750
|
+
return { resource, complete: false };
|
|
751
|
+
}
|
|
752
|
+
await new Promise<void>((resolve) => setTimeout(resolve, Math.min(2_500, deadline - Date.now())));
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
async function uploadOfficialScreenshot(config: AppStoreConnectPluginConfig, args: Record<string, unknown>, repoRoot: string): Promise<Record<string, unknown>> {
|
|
756
|
+
const file = await screenshotFile(repoRoot, requiredArg(args, 'file_path'));
|
|
757
|
+
if (args.expected_sha256 && (stringValue(args.expected_sha256)?.toLowerCase() !== file.sha256))
|
|
758
|
+
throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'Screenshot SHA-256 differs from expected.', { retryable: false });
|
|
759
|
+
const display = screenshotType(args), loc = await verifyScreenshotOwner(config, args);
|
|
760
|
+
const existingSet = await findScreenshotSet(config, loc, display, false);
|
|
761
|
+
const existing = existingSet ? await listScreenshots(config, existingSet) : [];
|
|
762
|
+
const sameName = existing.filter((r) => r.attributes?.fileName === file.name);
|
|
763
|
+
if (sameName.length > 1)
|
|
764
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Multiple screenshots share the source filename; inspect before retry.', {
|
|
765
|
+
retryable: false, details: { screenshotIds: sameName.map((r) => r.id) } });
|
|
766
|
+
const complete = sameName.find((r) => r.attributes?.sourceFileChecksum?.toLowerCase() === file.md5 &&
|
|
767
|
+
r.attributes?.assetDeliveryState?.state === 'COMPLETE');
|
|
768
|
+
if (complete) return { applied: false, alreadyPresent: true, processingComplete: true, setId: existingSet, screenshot: safeScreenshot(complete) };
|
|
769
|
+
const committed = sameName.find((r) => r.attributes?.sourceFileChecksum?.toLowerCase() === file.md5 &&
|
|
770
|
+
r.attributes?.assetDeliveryState?.state === 'UPLOAD_COMPLETE');
|
|
771
|
+
if (committed) {
|
|
772
|
+
const processed = await waitForScreenshotProcessing(config, committed.id, file.md5);
|
|
773
|
+
return { applied: false, alreadyPresent: true, processingComplete: processed.complete, setId: existingSet,
|
|
774
|
+
screenshot: safeScreenshot(processed.resource) };
|
|
775
|
+
}
|
|
776
|
+
if (sameName.length) throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Same filename has different, failed or uncommitted contents; inspect before retry.', {
|
|
777
|
+
retryable: false, details: { screenshotIds: sameName.map((r) => r.id), states: sameName.map((r) => r.attributes?.assetDeliveryState?.state) } });
|
|
778
|
+
if (existing.length >= 10) throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'Device set has ten screenshots already.', { retryable: false });
|
|
779
|
+
if (args.dry_run === true) return { dryRun: true, appId: args.app_id, versionId: args.version_id, locale: args.locale,
|
|
780
|
+
displayType: display, setId: existingSet ?? null, wouldCreateSet: !existingSet,
|
|
781
|
+
file: { relativePath: file.relativePath, name: file.name, size: file.bytes.length, sha256: file.sha256 } };
|
|
782
|
+
const setId = existingSet ?? await findScreenshotSet(config, loc, display, true);
|
|
783
|
+
if (!setId) throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Could not resolve screenshot set.', { retryable: false });
|
|
784
|
+
const reservation = await apiRequest<AscScreenshotResponse>(config, { path: '/v1/appScreenshots', method: 'POST',
|
|
785
|
+
body: { data: { type: 'appScreenshots', attributes: { fileName: file.name, fileSize: file.bytes.length },
|
|
786
|
+
relationships: { appScreenshotSet: { data: { type: 'appScreenshotSets', id: setId } } } } } });
|
|
787
|
+
const r = reservation.data;
|
|
788
|
+
if (!r?.id || !r.attributes?.uploadOperations)
|
|
789
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Apple reservation is incomplete; reconcile before retry.', { retryable: false });
|
|
790
|
+
await uploadScreenshotParts(r.attributes.uploadOperations, file.bytes);
|
|
791
|
+
await apiRequest<AscScreenshotResponse>(config, { path: '/v1/appScreenshots/' + encodeURIComponent(r.id),
|
|
792
|
+
method: 'PATCH', body: { data: { type: 'appScreenshots', id: r.id,
|
|
793
|
+
attributes: { uploaded: true, sourceFileChecksum: file.md5 } } } });
|
|
794
|
+
const processed = await waitForScreenshotProcessing(config, r.id, file.md5);
|
|
795
|
+
return { applied: true, setId, sha256: file.sha256, processingComplete: processed.complete,
|
|
796
|
+
screenshot: safeScreenshot(processed.resource),
|
|
797
|
+
...(processed.complete ? {} : { note: 'Apple accepted the upload but processing remains pending. Read the exact screenshot set before further action.' }) };
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
|
|
568
801
|
function appId(args: Record<string, unknown>, config: AppStoreConnectPluginConfig): string {
|
|
569
802
|
const value = stringValue(args.app_id) ?? config.defaultAppId;
|
|
570
803
|
if (!value) throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'app_id is required when no default_app_id is configured.', { retryable: false });
|
|
@@ -678,6 +911,10 @@ function mockResponse(actionId: string, args: Record<string, unknown>, config: A
|
|
|
678
911
|
readinessMode: 'mock_provider_ready',
|
|
679
912
|
};
|
|
680
913
|
}
|
|
914
|
+
if (actionId === 'list_app_screenshot_sets') return { data: [{ id: stableMockId('screenshot_set', args), displayType: stringValue(args.display_type) ?? 'APP_IPHONE_61' }], provider: 'mock' };
|
|
915
|
+
if (actionId === 'list_app_screenshots') return { setId: stableMockId('screenshot_set', args), data: [], provider: 'mock' };
|
|
916
|
+
if (actionId === 'upload_app_screenshot' || actionId === 'reorder_app_screenshots')
|
|
917
|
+
throw new AssistantPluginError('PLUGIN_ACTION_NOT_SUPPORTED', 'Mock mode cannot perform screenshot uploads or reordering.', { retryable: false });
|
|
681
918
|
if (actionId === 'list_apps') return { data: [{ type: 'apps', id, attributes: { name: 'Mock App', bundleId: stringValue(args.bundle_id) ?? 'com.example.app', sku: 'MOCK' } }], meta: { provider: 'mock' } };
|
|
682
919
|
if (actionId === 'list_app_store_versions') return { data: [{ type: 'appStoreVersions', id: stableMockId('version', { id }), attributes: { versionString: '1.0.0', appStoreState: 'PREPARE_FOR_SUBMISSION', platform: 'IOS' } }] };
|
|
683
920
|
if (actionId === 'list_app_store_version_localizations') {
|
|
@@ -860,15 +1097,16 @@ export async function executeAppStoreConnectPluginAction(input: AssistantPluginA
|
|
|
860
1097
|
if (config.provider === 'mock') return mockResponse(input.actionId, input.args, config);
|
|
861
1098
|
const auth = resolveAuth(config);
|
|
862
1099
|
if (input.actionId === 'auth_status') {
|
|
1100
|
+
const liveAuth = await resolveLiveAuthStatus(config);
|
|
863
1101
|
return {
|
|
864
|
-
ready: config.enabled &&
|
|
865
|
-
provider:
|
|
866
|
-
issuerId:
|
|
867
|
-
keyId:
|
|
868
|
-
credentialSource:
|
|
869
|
-
errors:
|
|
870
|
-
warnings:
|
|
871
|
-
userFacingStatus: userFacingAscStatus(config,
|
|
1102
|
+
ready: config.enabled && liveAuth.ready,
|
|
1103
|
+
provider: liveAuth.provider,
|
|
1104
|
+
issuerId: liveAuth.issuerId ? 'configured' : undefined,
|
|
1105
|
+
keyId: liveAuth.keyId ? 'configured' : undefined,
|
|
1106
|
+
credentialSource: liveAuth.credentialSource,
|
|
1107
|
+
errors: liveAuth.errors,
|
|
1108
|
+
warnings: liveAuth.warnings,
|
|
1109
|
+
userFacingStatus: userFacingAscStatus(config, liveAuth),
|
|
872
1110
|
};
|
|
873
1111
|
}
|
|
874
1112
|
if (!config.enabled || !auth.ready) throw new AssistantPluginError('PLUGIN_NOT_READY', 'App Store Connect plugin is not ready.', { retryable: false, details: { enabled: config.enabled, errors: auth.errors } });
|
|
@@ -887,12 +1125,46 @@ export async function executeAppStoreConnectPluginAction(input: AssistantPluginA
|
|
|
887
1125
|
case 'list_profiles':
|
|
888
1126
|
return apiRequest(config, { path: '/v1/profiles', query: { 'filter[name]': stringValue(input.args.name), 'filter[profileType]': stringValue(input.args.profile_type), limit: limit(input.args.limit) } });
|
|
889
1127
|
case 'list_app_store_versions':
|
|
890
|
-
return apiRequest(config, { path:
|
|
1128
|
+
return apiRequest(config, { path: `/v1/apps/${encodeURIComponent(appId(input.args, config))}/appStoreVersions`, query: { limit: limit(input.args.limit) } });
|
|
891
1129
|
case 'list_app_store_version_localizations':
|
|
892
1130
|
return apiRequest(config, {
|
|
893
1131
|
path: `/v1/appStoreVersions/${encodeURIComponent(requiredArg(input.args, 'version_id'))}/appStoreVersionLocalizations`,
|
|
894
1132
|
query: { limit: limit(input.args.limit) },
|
|
895
1133
|
});
|
|
1134
|
+
case 'list_app_screenshot_sets': {
|
|
1135
|
+
const locId = await verifyScreenshotOwner(config, input.args);
|
|
1136
|
+
const sets = await listScreenshotSets(config, locId);
|
|
1137
|
+
return { data: sets.map((s) => ({ id: s.id, displayType: s.attributes?.screenshotDisplayType })) };
|
|
1138
|
+
}
|
|
1139
|
+
case 'list_app_screenshots': {
|
|
1140
|
+
const loc = await verifyScreenshotOwner(config, input.args);
|
|
1141
|
+
const display = screenshotType(input.args);
|
|
1142
|
+
const setId = await findScreenshotSet(config, loc, display, false);
|
|
1143
|
+
return { setId: setId ?? null, data: setId ? (await listScreenshots(config, setId)).map(safeScreenshot) : [] };
|
|
1144
|
+
}
|
|
1145
|
+
case 'upload_app_screenshot':
|
|
1146
|
+
return uploadOfficialScreenshot(config, input.args, input.repoRoot);
|
|
1147
|
+
case 'reorder_app_screenshots': {
|
|
1148
|
+
const loc = await verifyScreenshotOwner(config, input.args);
|
|
1149
|
+
const setId = await findScreenshotSet(config, loc, screenshotType(input.args), false);
|
|
1150
|
+
if (!setId) throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'Cannot reorder a missing screenshot set.', { retryable: false });
|
|
1151
|
+
const original = await listScreenshots(config, setId);
|
|
1152
|
+
const next = input.args.screenshot_ids;
|
|
1153
|
+
if (!Array.isArray(next) || next.some((id) => typeof id !== 'string') ||
|
|
1154
|
+
next.length !== original.length || new Set(next).size !== original.length ||
|
|
1155
|
+
original.some((entry) => !next.includes(entry.id) || !entry.attributes?.sourceFileChecksum ||
|
|
1156
|
+
entry.attributes?.assetDeliveryState?.state !== 'COMPLETE'))
|
|
1157
|
+
throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'Reorder requires exactly all committed IDs in the same screenshot set.', { retryable: false });
|
|
1158
|
+
if (next.every((id, i) => id === original[i].id))
|
|
1159
|
+
return { applied: false, alreadyOrdered: true, setId, screenshotIds: next };
|
|
1160
|
+
if (input.args.dry_run === true) return { dryRun: true, setId, screenshotIds: next };
|
|
1161
|
+
await apiRequest(config, { path: '/v1/appScreenshotSets/' + encodeURIComponent(setId) + '/relationships/appScreenshots',
|
|
1162
|
+
method: 'PATCH', body: { data: next.map((id) => ({ type: 'appScreenshots', id })) } });
|
|
1163
|
+
const checked = await listScreenshots(config, setId);
|
|
1164
|
+
if (!next.every((id, i) => id === checked[i]?.id))
|
|
1165
|
+
throw new AssistantPluginError('PLUGIN_PROVIDER_ERROR', 'Apple screenshot order does not match the requested order after write.', { retryable: false });
|
|
1166
|
+
return { applied: true, setId, screenshotIds: next };
|
|
1167
|
+
}
|
|
896
1168
|
case 'get_app_info':
|
|
897
1169
|
case 'list_app_infos':
|
|
898
1170
|
return apiRequest(config, { path: `/v1/apps/${encodeURIComponent(appId(input.args, config))}/appInfos`, query: { include: 'appInfoLocalizations', limit: limit(input.args.limit) } });
|