@moretea-labs/forge 1.5.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -0
- package/CHANGELOG.md +46 -0
- package/CLAUDE.md +2 -0
- package/DESIGN.md +7 -2
- package/README.md +4 -4
- package/README.zh-CN.md +2 -2
- package/SKILL.md +2 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/agents/openai.yaml +1 -1
- package/assets/hooks/hook-input.sh +11 -8
- package/assets/hooks/lib/session-state.sh +10 -7
- package/assets/hooks/lib/workflow-state.sh +13 -177
- package/assets/hooks/post-tool-observer.sh +8 -2
- package/assets/hooks/pre-edit-guard.sh +8 -39
- package/assets/hooks/prompt-guard.sh +7 -83
- package/assets/hooks/session-start-context.sh +56 -1
- package/assets/partials/05-workflow.partial.md +1 -1
- package/assets/partials-agents/03-orchestration.partial.md +1 -1
- package/assets/plugin-registry.v1.json +54 -3
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/harness-overview.md +1 -1
- package/assets/reference-configs/hook-operations.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +3 -3
- package/assets/skill-version.json +2 -2
- package/assets/templates/contract.template.md +2 -7
- package/assets/templates/helpers/capture-plan.sh +2 -2
- package/assets/templates/helpers/check-task-workflow.sh +4 -4
- package/assets/templates/helpers/contract-worktree.sh +1 -21
- package/assets/templates/helpers/ensure-task-workflow.sh +13 -38
- package/assets/templates/helpers/migrate-project-template.sh +22 -45
- package/assets/templates/helpers/new-plan.sh +1 -1
- package/assets/templates/helpers/plan-to-todo.sh +12 -37
- package/assets/templates/helpers/ship-worktrees.sh +2 -29
- package/assets/templates/helpers/sprint-backlog.sh +6 -6
- package/assets/templates/helpers/verify-contract.sh +1 -111
- package/assets/templates/helpers/verify-sprint.sh +3 -180
- package/assets/templates/plan.template.md +1 -1
- package/assets/templates/review.template.md +9 -34
- package/assets/workflow-contract.v1.json +10 -19
- package/docs/README.md +10 -10
- package/docs/architecture/CURRENT.md +170 -0
- package/docs/architecture/EVOLUTION.md +42 -0
- package/docs/architecture/current/README.md +4 -156
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
- package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
- package/docs/architecture/history/README.md +7 -0
- package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
- package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
- package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
- package/docs/architecture/history.md +3 -34
- package/docs/architecture/index.md +15 -98
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
- package/docs/architecture/versions/1.6.md +38 -0
- package/docs/architecture/versions/1.7.md +41 -0
- package/docs/forge-chatgpt-browser-engine.md +2 -2
- package/docs/forge-chatgpt-mcp-setup.md +4 -28
- package/docs/forge-chatgpt-supervised-automation.md +3 -3
- package/docs/forge-github-issue-launcher.md +1 -1
- package/docs/forge-runtime-self-healing-loop.md +1 -1
- package/docs/operations/controller-browser-plugin.md +38 -22
- package/docs/operations/controller-performance-and-502.md +124 -0
- package/docs/operations/controller-reliability-runbook.md +1 -1
- package/docs/operations/features.md +3 -3
- package/docs/operations/github-repository.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +5 -3
- package/docs/tutorials/01-install-and-start.md +1 -1
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/wiki/Architecture.md +6 -6
- package/docs/wiki/Implementation.md +2 -2
- package/docs/wiki/Installation.md +1 -1
- package/docs/wiki/Integrations.md +2 -2
- package/docs/wiki/Quick-Start.md +1 -1
- package/docs/wiki/Work-Lifecycle.md +1 -1
- package/package.json +29 -10
- package/scripts/activate-source-baseline.ts +17 -13
- package/scripts/benchmark-background-check-overlap.ts +228 -0
- package/scripts/benchmark-mcp-host.sh +117 -0
- package/scripts/benchmark-mcp-transport.ts +170 -0
- package/scripts/benchmark-quality-harness.ts +146 -0
- package/scripts/benchmark-route-session-concurrency.ts +207 -6
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
- package/scripts/benchmark-typescript-navigation.ts +186 -0
- package/scripts/benchmark-work-efficiency.ts +334 -0
- package/scripts/capture-plan.sh +3 -3
- package/scripts/check-agent-tooling.sh +8 -35
- package/scripts/check-architecture-sync.sh +17 -86
- package/scripts/check-mcp-compatibility.ts +14 -0
- package/scripts/check-public-docs.sh +14 -1
- package/scripts/check-runtime-architecture.mjs +107 -64
- package/scripts/check-stable-baseline.ts +92 -0
- package/scripts/check-task-workflow.sh +4 -4
- package/scripts/contract-worktree.sh +1 -21
- package/scripts/ensure-task-workflow.sh +22 -55
- package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
- package/scripts/install-standalone-recovery.ts +24 -0
- package/scripts/lib/project-init-lib.sh +15 -44
- package/scripts/migrate-chatgpt-automation-schedules.ts +64 -0
- package/scripts/migrate-project-template.sh +23 -1179
- package/scripts/new-plan.sh +1 -1
- package/scripts/plan-to-todo.sh +11 -36
- package/scripts/run-governed-gate.ts +2 -1
- package/scripts/ship-worktrees.sh +2 -29
- package/scripts/smoke-ios-physical-device.ts +4 -2
- package/scripts/smoke-runtime-recovery.ts +1 -35
- package/scripts/smoke-schedule-engine.ts +1 -20
- package/scripts/sprint-backlog.sh +1 -1
- package/scripts/verify-contract.sh +1 -111
- package/scripts/verify-forge-runtime.sh +0 -1
- package/scripts/verify-sprint.sh +3 -180
- package/scripts/workflow-contract.ts +1 -5
- package/src/cli/commands/chatgpt.ts +31 -2
- package/src/cli/commands/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +37 -10
- package/src/cli/commands/recovery.ts +25 -3
- package/src/cli/commands/runtime.ts +55 -3
- package/src/cli/commands/security.ts +12 -1
- package/src/cli/commands/setup-profile.ts +31 -21
- package/src/cli/controller/check-runner.ts +106 -3
- package/src/cli/controller/composite-result.ts +1 -1
- package/src/cli/controller/context/focus.ts +51 -0
- package/src/cli/controller/context/instruction-context.ts +114 -0
- package/src/cli/controller/context/known-paths.ts +76 -0
- package/src/cli/controller/context/query-planning.ts +110 -0
- package/src/cli/controller/context/rule-resolution.ts +532 -0
- package/src/cli/controller/context/source-materializer.ts +278 -0
- package/src/cli/controller/context/structural.ts +16 -0
- package/src/cli/controller/context/types.ts +286 -0
- package/src/cli/controller/context-pack.ts +898 -430
- package/src/cli/controller/launch-agents.ts +77 -2
- package/src/cli/controller/operational-plan.ts +2 -2
- package/src/cli/controller/work-mode.ts +6 -4
- package/src/cli/editing/edit-session.ts +60 -7
- package/src/cli/github/github.ts +133 -0
- package/src/cli/hook/prompt-guard-decision.ts +17 -18
- package/src/cli/hook/prompt-intents.ts +1 -1
- package/src/cli/installer/managed-entries.ts +15 -1
- package/src/cli/local-bridge/console-automations.ts +225 -67
- package/src/cli/local-bridge/console-view-models.ts +3 -35
- package/src/cli/local-bridge/facade-api.ts +2 -217
- package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +153 -3
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +183 -3
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/lib/api.ts +18 -11
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/styles.css +27 -11
- package/src/cli/local-bridge/frontend/src/types.ts +8 -7
- package/src/cli/local-bridge/job-store.ts +1 -490
- package/src/cli/local-bridge/server.ts +29 -532
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +5101 -4967
- package/src/cli/mcp/auth.ts +5 -5
- package/src/cli/mcp/instructions.ts +3 -2
- package/src/cli/mcp/legacy-tool-service.ts +0 -189
- package/src/cli/mcp/multi-repository.ts +16 -5
- package/src/cli/mcp/oauth.ts +175 -26
- package/src/cli/mcp/paths.ts +8 -2
- package/src/cli/mcp/repository-tools.ts +356 -101
- package/src/cli/mcp/server.ts +625 -54
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/toolset-selection.ts +1 -1
- package/src/cli/mcp/toolset.ts +42 -5
- package/src/cli/mcp/transports/http.ts +125 -15
- package/src/cli/mcp/transports/session-registry.ts +67 -5
- package/src/cli/mcp/types.ts +3 -3
- package/src/cli/repositories/command-classifier.ts +209 -14
- package/src/cli/repositories/command-executor.ts +55 -521
- package/src/cli/repositories/command-process.ts +108 -0
- package/src/cli/repositories/command-scope.ts +99 -41
- package/src/cli/repositories/controller-home.ts +7 -8
- package/src/cli/repositories/git-command-executor.ts +2 -0
- package/src/cli/repositories/locks.ts +53 -16
- package/src/cli/repositories/repository-snapshot.ts +121 -0
- package/src/cli/repositories/safe-patch.ts +6 -4
- package/src/cli/repositories/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +110 -10
- package/src/cli/repository/inspector.ts +565 -62
- package/src/cli/repository/session-cache.ts +58 -17
- package/src/cli/v81-entry.ts +1 -4
- package/src/effects/fs-transaction.ts +85 -17
- package/src/runtime/context/codegraph-read-provider.ts +233 -2
- package/src/runtime/context/codegraph-sidecar.cjs +74 -40
- package/src/runtime/context/generic-lsp-provider.ts +355 -0
- package/src/runtime/context/lsp-client.ts +283 -0
- package/src/runtime/context/semantic-navigation.ts +275 -0
- package/src/runtime/context/swift-navigation.ts +565 -0
- package/src/runtime/context/typescript-navigation.ts +226 -0
- package/src/runtime/control-plane/dispatch-priority.ts +28 -0
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +196 -2
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
- package/src/runtime/control-plane/execution/session-store.ts +18 -0
- package/src/runtime/control-plane/execution/validation.ts +15 -2
- package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
- package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +175 -8
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -21
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +87 -9
- package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
- package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
- package/src/runtime/control-plane/facade/controller-session-store.ts +144 -14
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +9 -2
- package/src/runtime/control-plane/facade/goal-workloop.ts +885 -105
- package/src/runtime/control-plane/facade/index.ts +1 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +211 -26
- package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
- package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
- package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
- package/src/runtime/control-plane/facade/types.ts +55 -11
- package/src/runtime/control-plane/facade/work-contract-store.ts +204 -73
- package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
- package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
- package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +145 -0
- package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +273 -542
- package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
- package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
- package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
- package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
- package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +50 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +642 -51
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
- package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +15 -11
- package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
- package/src/runtime/control-plane/release-retention.ts +62 -2
- package/src/runtime/control-plane/routing/route-policy.ts +7 -16
- package/src/runtime/control-plane/runtime-status-client.ts +0 -2
- package/src/runtime/diagnostics/mcp-timing.ts +19 -0
- package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
- package/src/runtime/diagnostics/performance.ts +24 -1
- package/src/runtime/evidence/event-ledger.ts +1 -1
- package/src/runtime/execution/jobs/store.ts +58 -4
- package/src/runtime/execution/jobs/types.ts +1 -1
- package/src/runtime/execution/managed-workspace.ts +203 -1
- package/src/runtime/execution/process-runtime/check-facade.ts +52 -14
- package/src/runtime/execution/process-runtime/check-result.ts +63 -2
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +346 -40
- package/src/runtime/execution/process-runtime/gc.ts +98 -12
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +57 -6
- package/src/runtime/execution/process-runtime/resource-claims.ts +97 -8
- package/src/runtime/execution/process-runtime/runtime.ts +59 -4
- package/src/runtime/execution/process-runtime/store.ts +7 -0
- package/src/runtime/execution/process-runtime/types.ts +2 -0
- package/src/runtime/execution/thin-harness/async-process.ts +12 -2
- package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
- package/src/runtime/execution/workers/executor.ts +0 -48
- package/src/runtime/gateway/mcp/execution-tools.ts +1219 -126
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +185 -83
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2555 -1616
- package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
- package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
- package/src/runtime/plugins/browser-adapter.ts +2925 -318
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff-host.ts +6 -31
- package/src/runtime/plugins/browser-handoff.ts +92 -5
- package/src/runtime/plugins/browser-macos-bridge.ts +586 -45
- package/src/runtime/plugins/browser-node-bridge.ts +6 -34
- package/src/runtime/plugins/browser-provider-registry.ts +109 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +152 -0
- package/src/runtime/plugins/browser-runtime.ts +183 -0
- package/src/runtime/plugins/browser-session-authority.ts +332 -0
- package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +15 -12
- package/src/runtime/plugins/external-adapter.ts +324 -3
- package/src/runtime/plugins/external-registration.ts +84 -5
- package/src/runtime/plugins/external-unix-socket.ts +7 -1
- package/src/runtime/plugins/first-party-registry.ts +4 -2
- package/src/runtime/plugins/github-adapter.ts +125 -0
- package/src/runtime/plugins/gmail-adapter.ts +28 -2
- package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
- package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
- package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
- package/src/runtime/plugins/ios-adapter.ts +106 -16
- package/src/runtime/plugins/ios-agent-device.ts +234 -64
- package/src/runtime/plugins/ios-physical-device.ts +1143 -392
- package/src/runtime/plugins/lightweight-action.ts +153 -0
- package/src/runtime/plugins/local-system-adapter.ts +125 -8
- package/src/runtime/plugins/macos-capability-broker.ts +55 -9
- package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
- package/src/runtime/plugins/plugin-management-adapter.ts +181 -0
- package/src/runtime/plugins/resend-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +366 -24
- package/src/runtime/plugins/types.ts +39 -2
- package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
- package/src/runtime/projections/git-status-sampler.ts +16 -16
- package/src/runtime/projections/materialized-view.ts +28 -10
- package/src/runtime/recovery/actions.ts +0 -10
- package/src/runtime/recovery/classifier.ts +0 -9
- package/src/runtime/recovery/maintenance-executor.ts +415 -18
- package/src/runtime/recovery/probe.ts +0 -1
- package/src/runtime/recovery/types.ts +0 -1
- package/src/runtime/root/mcp-transport.ts +180 -10
- package/src/runtime/root/package-connector-service.ts +186 -8
- package/src/runtime/root/package-runtime-release.ts +143 -17
- package/src/runtime/root/package-runtime-service.ts +430 -22
- package/src/runtime/root/release-manifest.ts +7 -2
- package/src/runtime/root/release-materialize.ts +162 -19
- package/src/runtime/root/release-store.ts +48 -11
- package/src/runtime/root/runtime.ts +23 -5
- package/src/runtime/root/service.ts +100 -27
- package/src/runtime/root/types.ts +2 -0
- package/src/runtime/safe-tooling/index.ts +0 -1
- package/src/runtime/safe-tooling/ios-development.ts +321 -63
- package/src/runtime/safe-tooling/types.ts +0 -30
- package/src/runtime/shared/trusted-executable.ts +62 -0
- package/src/runtime/shared/trusted-node-executable.ts +48 -0
- package/src/runtime/standalone-recovery/core.ts +702 -94
- package/src/runtime/standalone-recovery/entry.ts +99 -23
- package/src/runtime/standalone-recovery/installer.ts +19 -3
- package/src/runtime/standalone-recovery/service-labels.ts +2 -0
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
- package/src/runtime/workflow/schedules/browser-probe.ts +258 -0
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
- package/src/runtime/workflow/schedules/engine.ts +509 -80
- package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
- package/src/runtime/workflow/schedules/settlement.ts +48 -4
- package/src/runtime/workflow/schedules/store.ts +131 -10
- package/src/runtime/workflow/schedules/types.ts +6 -3
- package/src/runtime/workflow/schedules/work-continuation.ts +120 -34
- package/src/testing/test-governance.ts +8 -40
- package/assets/reference-configs/heartbeat-triage.md +0 -57
- package/assets/templates/helpers/harness-trace-grade.sh +0 -150
- package/assets/templates/helpers/heartbeat-triage.sh +0 -361
- package/assets/templates/helpers/maintenance-triage.sh +0 -167
- package/bin/forge-desktop-helper.mjs +0 -204
- package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
- package/docs/architecture/current/architecture-invariants.md +0 -331
- package/docs/architecture/current/automation-and-schedule-engine.md +0 -453
- package/docs/architecture/current/codegraph-context-provider.md +0 -226
- package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
- package/docs/architecture/current/controller-repository-decoupling.md +0 -148
- package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -354
- package/docs/architecture/current/entity-model.md +0 -592
- package/docs/architecture/current/external-plugin-governance.md +0 -396
- package/docs/architecture/current/failure-recovery.md +0 -447
- package/docs/architecture/current/governance.md +0 -213
- package/docs/architecture/current/human-interaction-plane.md +0 -87
- package/docs/architecture/current/implementation-status.md +0 -128
- package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
- package/docs/architecture/current/legacy-governance.md +0 -58
- package/docs/architecture/current/local-workspace-target-grants.md +0 -70
- package/docs/architecture/current/migration-roadmap.md +0 -105
- package/docs/architecture/current/multi-repository-execution.md +0 -371
- package/docs/architecture/current/operations-runbook.md +0 -45
- package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
- package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
- package/docs/architecture/current/repository-access-modes.md +0 -102
- package/docs/architecture/current/route-policy.md +0 -15
- package/docs/architecture/current/route-session-concurrency.md +0 -85
- package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
- package/docs/architecture/current/runtime-directory-map.md +0 -49
- package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
- package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
- package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
- package/docs/architecture/current/system-overview.md +0 -144
- package/docs/architecture/current/target-requirements-traceability.md +0 -202
- package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
- package/docs/architecture/current/thin-harness-v1.md +0 -311
- package/docs/architecture/current/verification-and-release-gates.md +0 -391
- package/docs/forge-autonomous-goal-loop.md +0 -9
- package/docs/forge-provider-configuration.md +0 -7
- package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -83
- package/docs/operations/controller-desktop-plugin.md +0 -112
- package/docs/operations/gmail-assistant-routines.md +0 -186
- package/docs/operations/personal-assistant-operator-guide.md +0 -61
- package/docs/operations/provider-configuration.md +0 -31
- package/scripts/harness-trace-grade.sh +0 -150
- package/scripts/heartbeat-triage.sh +0 -361
- package/scripts/maintenance-triage.sh +0 -167
- package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
- package/src/cli/repositories/goal-registry.ts +0 -239
- package/src/runtime/assistant/action-proposals.ts +0 -279
- package/src/runtime/assistant/intent.ts +0 -395
- package/src/runtime/assistant/model-provider.ts +0 -460
- package/src/runtime/assistant/openapi.ts +0 -223
- package/src/runtime/assistant/policy.ts +0 -89
- package/src/runtime/assistant/readiness.ts +0 -258
- package/src/runtime/assistant/routine-runtime.ts +0 -477
- package/src/runtime/assistant/schedule-binding.ts +0 -171
- package/src/runtime/assistant/standing-grants.ts +0 -375
- package/src/runtime/assistant/store.ts +0 -243
- package/src/runtime/assistant/types.ts +0 -135
- package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
- package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
- package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
- package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
- package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
- package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
- package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
- package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
- package/src/runtime/control-plane/goal-loop/index.ts +0 -13
- package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
- package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
- package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
- package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
- package/src/runtime/control-plane/goal-loop/types.ts +0 -378
- package/src/runtime/control-plane/startup-recovery.ts +0 -198
- package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
- package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
- package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
- package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
- package/src/runtime/plugins/desktop-adapter.ts +0 -374
- package/src/runtime/safe-tooling/browser-safe.ts +0 -133
- package/src/runtime/workflow/findings/store.ts +0 -204
- package/src/runtime/workflow/findings/types.ts +0 -58
- package/src/runtime/workflow/portfolio/engine.ts +0 -20
- package/src/runtime/workflow/portfolio/store.ts +0 -185
- package/src/runtime/workflow/portfolio/types.ts +0 -29
package/scripts/verify-sprint.sh
CHANGED
|
@@ -20,54 +20,6 @@ json_escape() {
|
|
|
20
20
|
printf '%s' "$value"
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
review_card_field() {
|
|
24
|
-
local file="$1"
|
|
25
|
-
local label="$2"
|
|
26
|
-
[[ -n "$file" && -f "$file" ]] || return 1
|
|
27
|
-
awk -v wanted="$label" '
|
|
28
|
-
function trim(s) {
|
|
29
|
-
gsub(/^[[:space:]]+/, "", s)
|
|
30
|
-
gsub(/[[:space:]]+$/, "", s)
|
|
31
|
-
return s
|
|
32
|
-
}
|
|
33
|
-
BEGIN { wanted = tolower(wanted) }
|
|
34
|
-
/^##[[:space:]]+Human Review Card[[:space:]]*$/ { in_section = 1; next }
|
|
35
|
-
in_section && /^##[[:space:]]+/ { exit }
|
|
36
|
-
!in_section { next }
|
|
37
|
-
/^[[:space:]]*-[[:space:]]*/ {
|
|
38
|
-
line = $0
|
|
39
|
-
sub(/^[[:space:]]*-[[:space:]]*/, "", line)
|
|
40
|
-
key = line
|
|
41
|
-
sub(/:.*/, "", key)
|
|
42
|
-
key = tolower(trim(key))
|
|
43
|
-
if (key == wanted) {
|
|
44
|
-
sub(/^[^:]*:[[:space:]]*/, "", line)
|
|
45
|
-
print trim(line)
|
|
46
|
-
exit
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
' "$file"
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
normalize_status_token() {
|
|
53
|
-
local value="$1"
|
|
54
|
-
value="$(printf '%s' "$value" | sed -E 's/[;,].*$//; s/[[:space:]].*$//; s/^[[:space:]]+//; s/[[:space:]]+$//' | tr '[:upper:]' '[:lower:]')"
|
|
55
|
-
printf '%s' "$value"
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
field_has_concrete_value() {
|
|
59
|
-
local value="$1"
|
|
60
|
-
local token
|
|
61
|
-
token="$(normalize_status_token "$value")"
|
|
62
|
-
[[ -n "$token" ]] || return 1
|
|
63
|
-
case "$token" in
|
|
64
|
-
tbd|todo|n/a|na|none|unknown|unavailable|pending|...)
|
|
65
|
-
return 1
|
|
66
|
-
;;
|
|
67
|
-
esac
|
|
68
|
-
return 0
|
|
69
|
-
}
|
|
70
|
-
|
|
71
23
|
read_contract_task_profile() {
|
|
72
24
|
local file="$1"
|
|
73
25
|
awk '/^> \*\*Task Profile\*\*:/ {sub(/^.*> \*\*Task Profile\*\*:[[:space:]]*/, ""); gsub(/\r/, ""); print; exit}' "$file" | xargs
|
|
@@ -304,25 +256,14 @@ if [[ -f ".ai/hooks/lib/workflow-state.sh" ]]; then
|
|
|
304
256
|
# shellcheck source=/dev/null
|
|
305
257
|
. ".ai/hooks/lib/workflow-state.sh"
|
|
306
258
|
contract_file="$(workflow_active_contract || true)"
|
|
307
|
-
review_file="$(workflow_active_review || true)"
|
|
308
259
|
checks_file="$(workflow_checks_file)"
|
|
309
260
|
else
|
|
310
261
|
contract_file="$(find tasks/contracts -maxdepth 1 -name '*.contract.md' -type f 2>/dev/null | sort | head -n 1)"
|
|
311
|
-
if [[ -n "$contract_file" ]]; then
|
|
312
|
-
contract_slug="$(basename "$contract_file" | sed -E 's/\.contract\.md$//')"
|
|
313
|
-
review_file="tasks/reviews/${contract_slug}.review.md"
|
|
314
|
-
else
|
|
315
|
-
review_file=""
|
|
316
|
-
fi
|
|
317
262
|
checks_file=".ai/harness/checks/latest.json"
|
|
318
263
|
fi
|
|
319
264
|
if [[ -z "$contract_file" || ! -f "$contract_file" ]]; then
|
|
320
265
|
contract_file="$(active_plan_declared_path "Task Contract" || active_plan_declared_path "Sprint Contract" || true)"
|
|
321
266
|
fi
|
|
322
|
-
if [[ -z "$review_file" || ! -f "$review_file" ]]; then
|
|
323
|
-
review_file="$(active_plan_declared_path "Task Review" || active_plan_declared_path "Sprint Review" || true)"
|
|
324
|
-
fi
|
|
325
|
-
|
|
326
267
|
[[ -n "$contract_file" && -f "$contract_file" ]] || { echo "No active sprint contract found" >&2; exit 1; }
|
|
327
268
|
|
|
328
269
|
generated_at="$(date '+%Y-%m-%dT%H:%M:%S%z')"
|
|
@@ -378,74 +319,9 @@ if [[ -n "$contract_output" ]]; then
|
|
|
378
319
|
printf '%s\n' "$contract_output"
|
|
379
320
|
fi
|
|
380
321
|
|
|
381
|
-
review_status="fail"
|
|
382
|
-
review_message="Task review recommends pass and Human Review Card verdict is pass."
|
|
383
|
-
review_card_verdict=""
|
|
384
|
-
review_card_external=""
|
|
385
|
-
review_card_change_type=""
|
|
386
|
-
review_card_rollback=""
|
|
387
|
-
if [[ -z "$review_file" || ! -f "$review_file" ]]; then
|
|
388
|
-
review_message="Missing task review file."
|
|
389
|
-
echo "Missing task review file" >&2
|
|
390
|
-
else
|
|
391
|
-
review_card_verdict="$(normalize_status_token "$(review_card_field "$review_file" "Verdict" || true)")"
|
|
392
|
-
review_card_external="$(review_card_field "$review_file" "External acceptance" || true)"
|
|
393
|
-
review_card_change_type="$(normalize_status_token "$(review_card_field "$review_file" "Change type" || true)")"
|
|
394
|
-
review_card_rollback="$(review_card_field "$review_file" "Rollback" || true)"
|
|
395
|
-
fi
|
|
396
|
-
|
|
397
|
-
if [[ -n "$review_file" && -f "$review_file" ]]; then
|
|
398
|
-
if ! grep -Eq '^> \*\*Recommendation\*\*:[[:space:]]*pass([[:space:]]*)$' "$review_file"; then
|
|
399
|
-
review_message="Task review does not recommend pass."
|
|
400
|
-
echo "Task review does not recommend pass" >&2
|
|
401
|
-
elif [[ -z "$review_card_verdict" ]]; then
|
|
402
|
-
review_message="Task review is missing Human Review Card verdict."
|
|
403
|
-
echo "Task review is missing Human Review Card verdict" >&2
|
|
404
|
-
elif [[ "$review_card_verdict" != "pass" ]]; then
|
|
405
|
-
review_message="Human Review Card verdict is not pass: $review_card_verdict"
|
|
406
|
-
echo "Human Review Card verdict is not pass: $review_card_verdict" >&2
|
|
407
|
-
elif [[ -n "$task_profile" && "$review_card_change_type" != "$task_profile" ]]; then
|
|
408
|
-
review_message="Human Review Card change type does not match task_profile: ${review_card_change_type:-missing} != $task_profile"
|
|
409
|
-
echo "$review_message" >&2
|
|
410
|
-
elif ! field_has_concrete_value "$review_card_rollback"; then
|
|
411
|
-
review_message="Human Review Card rollback is missing or not concrete."
|
|
412
|
-
echo "$review_message" >&2
|
|
413
|
-
else
|
|
414
|
-
review_status="pass"
|
|
415
|
-
fi
|
|
416
|
-
fi
|
|
417
|
-
|
|
418
|
-
external_status="missing"
|
|
419
|
-
external_reviewer=""
|
|
420
|
-
external_source=""
|
|
421
|
-
external_message="External acceptance status is unavailable."
|
|
422
|
-
if declare -F workflow_external_acceptance_status >/dev/null 2>&1; then
|
|
423
|
-
external_row="$(workflow_external_acceptance_status "$review_file")"
|
|
424
|
-
IFS=$'\t' read -r external_status external_reviewer external_source external_message <<< "$external_row"
|
|
425
|
-
fi
|
|
426
|
-
card_external_status="$(normalize_status_token "$review_card_external")"
|
|
427
|
-
case "$external_status" in
|
|
428
|
-
missing|unavailable|"")
|
|
429
|
-
case "$card_external_status" in
|
|
430
|
-
pass|manual_override|not_required)
|
|
431
|
-
external_status="$card_external_status"
|
|
432
|
-
external_message="Human Review Card external acceptance: $review_card_external"
|
|
433
|
-
;;
|
|
434
|
-
esac
|
|
435
|
-
;;
|
|
436
|
-
esac
|
|
437
|
-
|
|
438
322
|
status="fail"
|
|
439
323
|
exit_code=1
|
|
440
|
-
|
|
441
|
-
pass|manual_override|not_required)
|
|
442
|
-
external_gate="pass"
|
|
443
|
-
;;
|
|
444
|
-
*)
|
|
445
|
-
external_gate="fail"
|
|
446
|
-
;;
|
|
447
|
-
esac
|
|
448
|
-
if [[ "$contract_exit" -eq 0 && "$review_status" == "pass" && "$external_gate" == "pass" && "$allowed_paths_status" == "pass" ]]; then
|
|
324
|
+
if [[ "$contract_exit" -eq 0 && "$allowed_paths_status" == "pass" ]]; then
|
|
449
325
|
status="pass"
|
|
450
326
|
exit_code=0
|
|
451
327
|
fi
|
|
@@ -456,10 +332,6 @@ fi
|
|
|
456
332
|
if [[ -z "$failure_class" && "$status" != "pass" ]]; then
|
|
457
333
|
if [[ "$contract_exit" -ne 0 ]]; then
|
|
458
334
|
failure_class="contract"
|
|
459
|
-
elif [[ "$review_status" != "pass" ]]; then
|
|
460
|
-
failure_class="review"
|
|
461
|
-
elif [[ "$external_gate" != "pass" ]]; then
|
|
462
|
-
failure_class="external_acceptance"
|
|
463
335
|
elif [[ "$allowed_paths_status" != "pass" ]]; then
|
|
464
336
|
failure_class="allowed_paths"
|
|
465
337
|
else
|
|
@@ -467,9 +339,9 @@ if [[ -z "$failure_class" && "$status" != "pass" ]]; then
|
|
|
467
339
|
fi
|
|
468
340
|
fi
|
|
469
341
|
if [[ "$status" == "pass" ]]; then
|
|
470
|
-
next_step="finish contract worktree or archive completed task"
|
|
342
|
+
next_step="perform a fresh semantic impact review, then finish contract worktree or archive completed task"
|
|
471
343
|
else
|
|
472
|
-
next_step="resolve failing contract
|
|
344
|
+
next_step="resolve failing contract or allowed_paths evidence"
|
|
473
345
|
fi
|
|
474
346
|
handoff_current_exists=false
|
|
475
347
|
handoff_resume_exists=false
|
|
@@ -492,17 +364,6 @@ if command -v jq >/dev/null 2>&1 && jq -e . "$contract_report" >/dev/null 2>&1;
|
|
|
492
364
|
--arg contract_status "$([[ "$contract_exit" -eq 0 ]] && printf pass || printf fail)" \
|
|
493
365
|
--arg contract_command "$contract_command" \
|
|
494
366
|
--argjson contract_exit "$contract_exit" \
|
|
495
|
-
--arg review_file "${review_file:-}" \
|
|
496
|
-
--arg review_status "$review_status" \
|
|
497
|
-
--arg review_message "$review_message" \
|
|
498
|
-
--arg review_card_verdict "$review_card_verdict" \
|
|
499
|
-
--arg review_card_change_type "$review_card_change_type" \
|
|
500
|
-
--arg review_card_external "$review_card_external" \
|
|
501
|
-
--arg review_card_rollback "$review_card_rollback" \
|
|
502
|
-
--arg external_status "$external_status" \
|
|
503
|
-
--arg external_reviewer "$external_reviewer" \
|
|
504
|
-
--arg external_source "$external_source" \
|
|
505
|
-
--arg external_message "$external_message" \
|
|
506
367
|
--arg worktree "$worktree_path" \
|
|
507
368
|
--arg branch "$branch_name" \
|
|
508
369
|
--arg diff_base_ref "$diff_base_ref" \
|
|
@@ -538,8 +399,6 @@ if command -v jq >/dev/null 2>&1 && jq -e . "$contract_report" >/dev/null 2>&1;
|
|
|
538
399
|
],
|
|
539
400
|
guards: [
|
|
540
401
|
{name: "contract", status: $contract_status},
|
|
541
|
-
{name: "review", status: $review_status},
|
|
542
|
-
{name: "external_acceptance", status: $external_status},
|
|
543
402
|
{name: "allowed_paths", status: ($allowed_paths_check.status // "unavailable")}
|
|
544
403
|
],
|
|
545
404
|
handoffs: [
|
|
@@ -563,23 +422,6 @@ if command -v jq >/dev/null 2>&1 && jq -e . "$contract_report" >/dev/null 2>&1;
|
|
|
563
422
|
report: ($contract_report[0] // {}),
|
|
564
423
|
task_profile: $task_profile,
|
|
565
424
|
allowed_paths: $allowed_paths
|
|
566
|
-
},
|
|
567
|
-
review: {
|
|
568
|
-
file: $review_file,
|
|
569
|
-
status: $review_status,
|
|
570
|
-
message: $review_message,
|
|
571
|
-
card: {
|
|
572
|
-
verdict: $review_card_verdict,
|
|
573
|
-
change_type: $review_card_change_type,
|
|
574
|
-
external_acceptance: $review_card_external,
|
|
575
|
-
rollback: $review_card_rollback
|
|
576
|
-
}
|
|
577
|
-
},
|
|
578
|
-
external_acceptance: {
|
|
579
|
-
status: $external_status,
|
|
580
|
-
reviewer: $external_reviewer,
|
|
581
|
-
source: $external_source,
|
|
582
|
-
message: $external_message
|
|
583
425
|
}
|
|
584
426
|
}' > "$checks_report"
|
|
585
427
|
else
|
|
@@ -617,8 +459,6 @@ else
|
|
|
617
459
|
],
|
|
618
460
|
"guards": [
|
|
619
461
|
{"name": "contract", "status": "$([[ "$contract_exit" -eq 0 ]] && printf pass || printf fail)"},
|
|
620
|
-
{"name": "review", "status": "$(json_escape "$review_status")"},
|
|
621
|
-
{"name": "external_acceptance", "status": "$(json_escape "$external_status")"},
|
|
622
462
|
{"name": "allowed_paths", "status": "$(json_escape "$allowed_paths_status")"}
|
|
623
463
|
],
|
|
624
464
|
"handoffs": [
|
|
@@ -644,23 +484,6 @@ else
|
|
|
644
484
|
"exit_code": $contract_exit,
|
|
645
485
|
"task_profile": "$(json_escape "$task_profile")",
|
|
646
486
|
"allowed_paths": []
|
|
647
|
-
},
|
|
648
|
-
"review": {
|
|
649
|
-
"file": "$(json_escape "${review_file:-}")",
|
|
650
|
-
"status": "$(json_escape "$review_status")",
|
|
651
|
-
"message": "$(json_escape "$review_message")",
|
|
652
|
-
"card": {
|
|
653
|
-
"verdict": "$(json_escape "$review_card_verdict")",
|
|
654
|
-
"change_type": "$(json_escape "$review_card_change_type")",
|
|
655
|
-
"external_acceptance": "$(json_escape "$review_card_external")",
|
|
656
|
-
"rollback": "$(json_escape "$review_card_rollback")"
|
|
657
|
-
}
|
|
658
|
-
},
|
|
659
|
-
"external_acceptance": {
|
|
660
|
-
"status": "$(json_escape "$external_status")",
|
|
661
|
-
"reviewer": "$(json_escape "$external_reviewer")",
|
|
662
|
-
"source": "$(json_escape "$external_source")",
|
|
663
|
-
"message": "$(json_escape "$external_message")"
|
|
664
487
|
}
|
|
665
488
|
}
|
|
666
489
|
EOF_CHECKS
|
|
@@ -185,11 +185,7 @@ export function getHelperScripts(contract: WorkflowContract): string[] {
|
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
export function getHelperRuntimeDir(contract: WorkflowContract): string {
|
|
188
|
-
return
|
|
189
|
-
contract.helpers.runtimeDirectory ??
|
|
190
|
-
contract.helpers.compatibilityDirectory ??
|
|
191
|
-
"scripts"
|
|
192
|
-
);
|
|
188
|
+
return contract.helpers.runtimeDirectory ?? contract.helpers.compatibilityDirectory ?? "scripts";
|
|
193
189
|
}
|
|
194
190
|
|
|
195
191
|
export function getRequiredDirectories(contract: WorkflowContract): string[] {
|
|
@@ -13,7 +13,11 @@ import {
|
|
|
13
13
|
} from '../chatgpt-browser/engine';
|
|
14
14
|
import type { BrowserProviderName, BrowserSessionStatus, NativeBrowserChannel, ThinkingLevel } from '../chatgpt-browser/types';
|
|
15
15
|
import { durableControllerHome } from '../repositories/controller-home';
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
runWorkChatgptContinuation,
|
|
18
|
+
type ChatgptAutomationReasoning,
|
|
19
|
+
type ChatgptAutomationTabPolicy,
|
|
20
|
+
} from '../../runtime/control-plane/launcher/chatgpt-work-continuation';
|
|
17
21
|
|
|
18
22
|
interface BrowserCommonOptions {
|
|
19
23
|
repo?: string;
|
|
@@ -84,6 +88,9 @@ interface WorkChatgptContinueOptions extends BrowserCommonOptions {
|
|
|
84
88
|
title?: string;
|
|
85
89
|
session?: string;
|
|
86
90
|
conversationUrl?: string;
|
|
91
|
+
model?: string;
|
|
92
|
+
reasoning?: string;
|
|
93
|
+
tabPolicy?: string;
|
|
87
94
|
timeoutMs?: string;
|
|
88
95
|
}
|
|
89
96
|
|
|
@@ -109,6 +116,18 @@ interface BrowserFollowupOptions extends BrowserCommonOptions {
|
|
|
109
116
|
oracleBin?: string;
|
|
110
117
|
}
|
|
111
118
|
|
|
119
|
+
function parseAutomationReasoning(value?: string): ChatgptAutomationReasoning | undefined {
|
|
120
|
+
if (value === undefined) return undefined;
|
|
121
|
+
if (value === 'medium' || value === 'high' || value === 'xhigh') return value;
|
|
122
|
+
throw new Error(`invalid --reasoning "${value}" (expected: medium, high, xhigh)`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function parseAutomationTabPolicy(value?: string): ChatgptAutomationTabPolicy | undefined {
|
|
126
|
+
if (value === undefined) return undefined;
|
|
127
|
+
if (value === 'auto' || value === 'reuse' || value === 'new') return value;
|
|
128
|
+
throw new Error(`invalid --tab-policy "${value}" (expected: auto, reuse, new)`);
|
|
129
|
+
}
|
|
130
|
+
|
|
112
131
|
function parseProvider(value?: string): BrowserProviderName {
|
|
113
132
|
if (value === undefined || value === 'oracle') return 'oracle';
|
|
114
133
|
if (value === 'native') return 'native';
|
|
@@ -384,8 +403,11 @@ export function buildChatgptCommand(): Command {
|
|
|
384
403
|
.requiredOption('--work-id <work-id>', 'Stable Forge Work id')
|
|
385
404
|
.requiredOption('--prompt <text>', 'Bounded continuation prompt')
|
|
386
405
|
.option('--title <title>', 'Human-readable local conversation alias')
|
|
387
|
-
.option('--session <session-id>', '
|
|
406
|
+
.option('--session <session-id>', 'Saved browser session to seed or resume the Work binding')
|
|
388
407
|
.option('--conversation-url <url>', 'Explicit ChatGPT conversation URL to seed the binding')
|
|
408
|
+
.option('--model <label>', 'Requested ChatGPT automation model', 'gpt-5.6')
|
|
409
|
+
.option('--reasoning <level>', 'Reasoning level: medium|high|xhigh', 'high')
|
|
410
|
+
.option('--tab-policy <policy>', 'Browser tab policy: auto|reuse|new', 'auto')
|
|
389
411
|
.option('--timeout-ms <ms>', 'Assistant timeout in milliseconds')
|
|
390
412
|
.action((rawOpts: WorkChatgptContinueOptions) => {
|
|
391
413
|
void runChatgptAction(async () => {
|
|
@@ -398,6 +420,9 @@ export function buildChatgptCommand(): Command {
|
|
|
398
420
|
title: rawOpts.title,
|
|
399
421
|
browserSessionId: rawOpts.session,
|
|
400
422
|
conversationUrl: rawOpts.conversationUrl,
|
|
423
|
+
model: rawOpts.model,
|
|
424
|
+
reasoning: parseAutomationReasoning(rawOpts.reasoning),
|
|
425
|
+
tabPolicy: parseAutomationTabPolicy(rawOpts.tabPolicy),
|
|
401
426
|
timeoutMs: parsePositiveInteger('timeout-ms', rawOpts.timeoutMs),
|
|
402
427
|
});
|
|
403
428
|
console.log(JSON.stringify({
|
|
@@ -408,6 +433,10 @@ export function buildChatgptCommand(): Command {
|
|
|
408
433
|
conversationId: result.conversationId,
|
|
409
434
|
localAlias: result.localAlias,
|
|
410
435
|
resumedFromBinding: result.resumedFromBinding,
|
|
436
|
+
model: result.model,
|
|
437
|
+
reasoning: result.reasoning,
|
|
438
|
+
tabPolicy: result.tabPolicy,
|
|
439
|
+
executionPreferenceVerified: result.executionPreferenceVerified,
|
|
411
440
|
error: result.error,
|
|
412
441
|
}, null, 2));
|
|
413
442
|
});
|
|
@@ -17,7 +17,7 @@ import { Command } from 'commander';
|
|
|
17
17
|
import { runDoctor, type CheckStatus, type DoctorReport } from './doctor';
|
|
18
18
|
import { runStatus, type StatusReport } from './status';
|
|
19
19
|
import { runMcpSetupChatgpt } from '../mcp/setup';
|
|
20
|
-
import {
|
|
20
|
+
import { resolveControllerHome } from '../repositories/controller-home';
|
|
21
21
|
import {
|
|
22
22
|
configureSetupProfile,
|
|
23
23
|
detectSetupPlatform,
|
|
@@ -791,7 +791,7 @@ export function openSetupSession(options: SetupSessionOptions = {}): SetupSessio
|
|
|
791
791
|
const platform = options.platform ?? detectSetupPlatform({ env: options.env });
|
|
792
792
|
const target = options.target ?? setupHostTarget(profile);
|
|
793
793
|
const report = options.report ?? runInitHook({ ...options, target });
|
|
794
|
-
const controllerHome =
|
|
794
|
+
const controllerHome = resolveControllerHome(options.controllerHome);
|
|
795
795
|
const nextAction = profileNextAction(profile, platform, { controllerHome, accountHome: options.accountHome }) ?? report.agent_actions[0];
|
|
796
796
|
const now = (options.now ?? (() => new Date()))().toISOString();
|
|
797
797
|
const reuse = previous && previous.status !== 'closed';
|
|
@@ -1010,4 +1010,4 @@ export function buildSetupCommand(): Command {
|
|
|
1010
1010
|
});
|
|
1011
1011
|
|
|
1012
1012
|
return command;
|
|
1013
|
-
}
|
|
1013
|
+
}
|
package/src/cli/commands/mcp.ts
CHANGED
|
@@ -28,7 +28,7 @@ export interface McpServeOptions {
|
|
|
28
28
|
devRunnerAgents?: string;
|
|
29
29
|
devRunnerTimeoutMs?: string;
|
|
30
30
|
devRunnerMaxTimeoutMs?: string;
|
|
31
|
-
toolset?: 'core' | 'advanced' | 'full';
|
|
31
|
+
toolset?: 'facade' | 'core' | 'advanced' | 'full';
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
interface McpAccessOptions {
|
|
@@ -161,14 +161,14 @@ export function buildMcpCommand(): Command {
|
|
|
161
161
|
mcp
|
|
162
162
|
.command('serve')
|
|
163
163
|
.description('Start the forge MCP server')
|
|
164
|
-
.option('--repo <path>', 'Repository root to expose through the selected MCP profile'
|
|
164
|
+
.option('--repo <path>', 'Repository root to expose through the selected MCP profile')
|
|
165
165
|
.option('--controller-home <path>', 'Controller state root; defaults to repo _ops/controller-home when present')
|
|
166
166
|
.option('--transport <transport>', 'Transport: stdio|http', 'stdio')
|
|
167
167
|
.option('--host <host>', 'HTTP bind host', '127.0.0.1')
|
|
168
168
|
.option('--port <port>', 'HTTP bind port', '8765')
|
|
169
169
|
.option('--profile <profile>', 'MCP profile: planner|executor|orchestrator|controller', 'controller')
|
|
170
|
-
.option('--toolset <toolset>', 'Controller toolset: core|advanced|full (default
|
|
171
|
-
.option('--auth <mode>', 'HTTP auth mode: oauth|bearer', 'oauth')
|
|
170
|
+
.option('--toolset <toolset>', 'Controller toolset: facade|core|advanced|full (default advanced; facade is an explicit five-tool ChatGPT surface)')
|
|
171
|
+
.option('--auth <mode>', 'HTTP auth mode: oauth|bearer|none', 'oauth')
|
|
172
172
|
.option('--enable-chatgpt-browser', 'Expose tools that operate the user logged-in ChatGPT Web browser session')
|
|
173
173
|
.option('--enable-dev-runner', 'Enable local Codex/Claude task runners for controller or orchestrator profiles')
|
|
174
174
|
.option('--dev-runner-agents <agents>', 'Comma-separated dev runner agents: codex,claude')
|
|
@@ -181,7 +181,11 @@ export function buildMcpCommand(): Command {
|
|
|
181
181
|
const devRunnerMaxTimeoutMs = parsePositiveIntegerOption('dev-runner-max-timeout-ms', rawOpts.devRunnerMaxTimeoutMs);
|
|
182
182
|
if (rawOpts.transport === 'stdio') {
|
|
183
183
|
await startMcpStdio({
|
|
184
|
-
|
|
184
|
+
// stdio preserves its historical current-directory default.
|
|
185
|
+
// The HTTP controller Gateway deliberately leaves this unset so
|
|
186
|
+
// it can serve Controller Home without registering a launchd
|
|
187
|
+
// working directory as a repository.
|
|
188
|
+
repo: rawOpts.repo ?? '.',
|
|
185
189
|
controllerHome: rawOpts.controllerHome,
|
|
186
190
|
profile: rawOpts.profile,
|
|
187
191
|
toolset: rawOpts.toolset,
|
|
@@ -5,11 +5,11 @@ import { dirname, isAbsolute, join, resolve, sep } from 'path';
|
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { Command } from 'commander';
|
|
7
7
|
import { resolveControllerHome, controllerSystemRoot } from '../repositories/controller-home';
|
|
8
|
-
import { installExternalPluginRegistration, listExternalPluginRegistrations, type ExternalPluginRegistrationInput } from '../../runtime/plugins/external-registration';
|
|
8
|
+
import { installExternalPluginRegistration, listExternalPluginRegistrations, type ExternalPluginRegistration, type ExternalPluginRegistrationInput } from '../../runtime/plugins/external-registration';
|
|
9
9
|
import { createDesktopOperatorRegistrationInput } from '../../runtime/plugins/desktop-operator-registration';
|
|
10
10
|
import { controllerPluginRepository, getAssistantPluginManifest, syncAssistantPluginRegistry } from '../../runtime/plugins/store';
|
|
11
11
|
|
|
12
|
-
interface RegistryEntry { id:string; name:string; version:string; description:string; repository:string; ref:string; installer:string; platforms:NodeJS.Platform[]; }
|
|
12
|
+
export interface RegistryEntry { id:string; name:string; version:string; description:string; repository:string; ref:string; installer:string; providerVersion?:string; protocolVersion?:string; platforms:NodeJS.Platform[]; }
|
|
13
13
|
interface Registry { schemaVersion:1; plugins:RegistryEntry[]; }
|
|
14
14
|
interface CliOptions { json?:boolean; controllerHome?:string; refresh?:boolean; }
|
|
15
15
|
const packageRoot=resolve(dirname(fileURLToPath(import.meta.url)),'../../..');
|
|
@@ -24,11 +24,26 @@ function registry():Registry{
|
|
|
24
24
|
if(!plugin.repository.startsWith('https://github.com/moretea-labs/')||!plugin.repository.endsWith('.git'))throw new Error(`PLUGIN_CATALOG_UNTRUSTED_REPOSITORY: ${plugin.id}`);
|
|
25
25
|
if(!/^v\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?$/.test(plugin.ref))throw new Error(`PLUGIN_CATALOG_UNPINNED_REF: ${plugin.id}`);
|
|
26
26
|
if(plugin.installer!=='forge-plugin-install.mjs')throw new Error(`PLUGIN_CATALOG_INSTALLER_INVALID: ${plugin.id}`);
|
|
27
|
+
if(plugin.providerVersion!==undefined&&!/^\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?$/.test(plugin.providerVersion))throw new Error(`PLUGIN_CATALOG_PROVIDER_VERSION_INVALID: ${plugin.id}`);
|
|
28
|
+
if(plugin.protocolVersion!==undefined&&!/^\d+\.\d+$/.test(plugin.protocolVersion))throw new Error(`PLUGIN_CATALOG_PROTOCOL_VERSION_INVALID: ${plugin.id}`);
|
|
27
29
|
ids.add(plugin.id);
|
|
28
30
|
}
|
|
29
31
|
return value;
|
|
30
32
|
}
|
|
31
33
|
function within(root:string,relative:string):string{const target=resolve(root,relative);const base=`${resolve(root)}${sep}`;if(target!==resolve(root)&&!target.startsWith(base))throw new Error('PLUGIN_INSTALL_PATH_ESCAPE');return target;}
|
|
34
|
+
export function pluginCatalogCompatibility(entry:RegistryEntry,platform:NodeJS.Platform=process.platform):{compatible:boolean;reason?:string}{
|
|
35
|
+
if(!entry.platforms.includes(platform))return{compatible:false,reason:`unsupported platform: ${platform}`};
|
|
36
|
+
if(entry.providerVersion&&entry.providerVersion!==entry.version)return{compatible:false,reason:`catalog version ${entry.version} does not match pinned provider version ${entry.providerVersion}`};
|
|
37
|
+
return{compatible:true};
|
|
38
|
+
}
|
|
39
|
+
export function officialPluginCatalogItems(platform:NodeJS.Platform=process.platform){return registry().plugins.map(entry=>({...entry,...pluginCatalogCompatibility(entry,platform)}));}
|
|
40
|
+
export function externalPluginListItem(controllerHome:string,registration:ExternalPluginRegistration){
|
|
41
|
+
const base={pluginId:registration.pluginId,version:registration.pluginVersion,provider:registration.provider,enabled:registration.enabled,scope:registration.scope,transport:registration.transport.kind};
|
|
42
|
+
if(registration.scope==='repository')return{...base,healthScope:'repository_context_required' as const};
|
|
43
|
+
const repository=controllerPluginRepository(controllerHome);
|
|
44
|
+
try{return{...base,health:getAssistantPluginManifest(controllerHome,repository,registration.pluginId).health};}
|
|
45
|
+
catch(error){return{...base,health:{state:'error',message:error instanceof Error?error.message:String(error)}};}
|
|
46
|
+
}
|
|
32
47
|
function run(command:string,args:string[],cwd:string,timeoutMs=120000):string{
|
|
33
48
|
const result=spawnSync(command,args,{cwd,encoding:'utf8',timeout:timeoutMs,maxBuffer:32*1024*1024,shell:false,windowsHide:true});
|
|
34
49
|
if(result.error)throw new Error(`PLUGIN_INSTALL_COMMAND_FAILED: ${result.error.message}`);
|
|
@@ -40,17 +55,29 @@ function installerJson(stdout:string):Record<string,unknown>{
|
|
|
40
55
|
for(let i=lines.length-1;i>=0;i--){try{const x=JSON.parse(lines[i]);if(x&&typeof x==='object'&&!Array.isArray(x)&&x.schemaVersion===1)return x;}catch{}}
|
|
41
56
|
throw new Error('PLUGIN_INSTALLER_OUTPUT_INVALID');
|
|
42
57
|
}
|
|
43
|
-
function
|
|
58
|
+
export function installerNextSteps(result:Record<string,unknown>):string[]{
|
|
59
|
+
if(!Array.isArray(result.nextSteps))return[];
|
|
60
|
+
return result.nextSteps
|
|
61
|
+
.filter((value):value is string=>typeof value==='string')
|
|
62
|
+
.map(value=>value.replace(/[\u0000-\u001F\u007F]/g,' ').trim().slice(0,1000))
|
|
63
|
+
.filter(Boolean)
|
|
64
|
+
.slice(0,10);
|
|
65
|
+
}
|
|
66
|
+
export function registrationFrom(result:Record<string,unknown>,entry:RegistryEntry):ExternalPluginRegistrationInput{
|
|
44
67
|
if(result.registration){const input=result.registration as ExternalPluginRegistrationInput;if(input.pluginId!==entry.id)throw new Error('PLUGIN_INSTALLER_ID_MISMATCH');if(input.pluginVersion!==entry.version)throw new Error('PLUGIN_INSTALLER_VERSION_MISMATCH');return input;}
|
|
45
68
|
const facts=result.providerInstall as Record<string,unknown>|undefined;
|
|
46
69
|
if(!facts||facts.kind!=='desktop_operator'||entry.id!=='desktop_operator')throw new Error('PLUGIN_INSTALLER_REGISTRATION_MISSING');
|
|
47
|
-
|
|
70
|
+
const expectedProviderVersion=entry.providerVersion??entry.version;
|
|
71
|
+
const expectedProtocolVersion=entry.protocolVersion??'1.0';
|
|
72
|
+
if(facts.pluginVersion!==expectedProviderVersion)throw new Error(`PLUGIN_INSTALLER_PROVIDER_VERSION_MISMATCH: expected ${expectedProviderVersion} for ${entry.id}@${entry.version}, actual ${String(facts.pluginVersion??'missing')}`);
|
|
73
|
+
if(facts.protocolVersion!==expectedProtocolVersion)throw new Error(`PLUGIN_INSTALLER_PROTOCOL_VERSION_MISMATCH: expected ${expectedProtocolVersion} for ${entry.id}@${entry.version}, actual ${String(facts.protocolVersion??'missing')}`);
|
|
48
74
|
const socketPath=typeof facts.socketPath==='string'?facts.socketPath:'';const launchAgentLabel=typeof facts.launchAgentLabel==='string'?facts.launchAgentLabel:'';const expectedProgramContains=typeof facts.expectedProgramContains==='string'?facts.expectedProgramContains:'';
|
|
49
75
|
if(!isAbsolute(socketPath)||!launchAgentLabel||!expectedProgramContains)throw new Error('PLUGIN_INSTALLER_PROVIDER_FACTS_INVALID');
|
|
50
|
-
return createDesktopOperatorRegistrationInput({socketPath,launchAgentLabel,expectedProgramContains,pluginVersion:
|
|
76
|
+
return createDesktopOperatorRegistrationInput({socketPath,launchAgentLabel,expectedProgramContains,pluginVersion:expectedProviderVersion,protocolVersion:expectedProtocolVersion});
|
|
51
77
|
}
|
|
52
78
|
function install(entry:RegistryEntry,controllerHome:string):Record<string,unknown>{
|
|
53
|
-
|
|
79
|
+
const compatibility=pluginCatalogCompatibility(entry,process.platform);
|
|
80
|
+
if(!compatibility.compatible)throw new Error(`PLUGIN_CATALOG_INCOMPATIBLE: ${entry.id}@${entry.version}: ${compatibility.reason}`);
|
|
54
81
|
const packagesRoot=join(controllerSystemRoot(controllerHome),'plugins','packages');mkdirSync(packagesRoot,{recursive:true,mode:0o700});
|
|
55
82
|
const finalRoot=join(packagesRoot,entry.id),stage=join(packagesRoot,`.${entry.id}.${randomUUID()}.staging`),backup=join(packagesRoot,`.${entry.id}.${randomUUID()}.backup`);let backed=false;
|
|
56
83
|
try{
|
|
@@ -62,13 +89,13 @@ function install(entry:RegistryEntry,controllerHome:string):Record<string,unknow
|
|
|
62
89
|
const installed=installExternalPluginRegistration(controllerHome,registrationFrom(result,entry));
|
|
63
90
|
const repository=controllerPluginRepository(controllerHome);syncAssistantPluginRegistry(controllerHome,repository);const plugin=getAssistantPluginManifest(controllerHome,repository,entry.id);
|
|
64
91
|
if(backed)rmSync(backup,{recursive:true,force:true});
|
|
65
|
-
return{pluginId:entry.id,version:entry.version,packageRoot:finalRoot,registrationRevision:installed.revision,enabled:plugin.enabled,health:plugin.health};
|
|
92
|
+
return{pluginId:entry.id,version:entry.version,packageRoot:finalRoot,registrationRevision:installed.revision,enabled:plugin.enabled,health:plugin.health,nextSteps:installerNextSteps(result)};
|
|
66
93
|
}catch(error){rmSync(stage,{recursive:true,force:true});if(backed&&existsSync(finalRoot))rmSync(finalRoot,{recursive:true,force:true});if(backed&&existsSync(backup))renameSync(backup,finalRoot);throw error;}
|
|
67
94
|
}
|
|
68
95
|
export function buildPluginCommand():Command{
|
|
69
96
|
const root=new Command('plugin').description('Discover and install trusted Forge plugins');
|
|
70
|
-
root.command('catalog').description('List official plugins').option('--json','Output JSON').action((o:CliOptions)=>{const items=
|
|
71
|
-
root.command('list').description('List installed external plugins').option('--json','Output JSON').option('--controller-home <path>','Override Controller Home').option('--refresh','Probe providers').action((o:CliOptions)=>{const home=resolveControllerHome(o.controllerHome),repo=controllerPluginRepository(home);if(o.refresh)syncAssistantPluginRegistry(home,repo);const items=listExternalPluginRegistrations(home).map(r=>
|
|
72
|
-
root.command('install <plugin-id>').description('Install/update an official plugin from a pinned public release').option('--json','Output JSON').option('--controller-home <path>','Override Controller Home').action((id:string,o:CliOptions)=>{const entry=registry().plugins.find(x=>x.id===id);if(!entry)throw new Error(`PLUGIN_NOT_IN_OFFICIAL_CATALOG: ${id}`);const result=install(entry,resolveControllerHome(o.controllerHome));if(o.json)console.log(JSON.stringify(result,null,2));else
|
|
97
|
+
root.command('catalog').description('List official plugins').option('--json','Output JSON').action((o:CliOptions)=>{const items=officialPluginCatalogItems();if(o.json)console.log(JSON.stringify({schemaVersion:1,platform:process.platform,plugins:items},null,2));else items.forEach(x=>console.log(`${x.id}\t${x.version}\t${x.compatible?'compatible':`incompatible (${x.reason})`}\t${x.name}`));});
|
|
98
|
+
root.command('list').description('List installed external plugins').option('--json','Output JSON').option('--controller-home <path>','Override Controller Home').option('--refresh','Probe controller-scoped providers').action((o:CliOptions)=>{const home=resolveControllerHome(o.controllerHome),repo=controllerPluginRepository(home);if(o.refresh)syncAssistantPluginRegistry(home,repo);const items=listExternalPluginRegistrations(home).map(r=>externalPluginListItem(home,r));if(o.json)console.log(JSON.stringify({schemaVersion:1,plugins:items},null,2));else if(!items.length)console.log('No external Forge plugins installed.');else items.forEach(x=>console.log(`${x.pluginId}\t${x.version}\t${x.enabled?'enabled':'disabled'}\t${'healthScope' in x?'repository-context-required':((x.health as {state?:string})?.state??'unknown')}`));});
|
|
99
|
+
root.command('install <plugin-id>').description('Install/update an official plugin from a pinned public release').option('--json','Output JSON').option('--controller-home <path>','Override Controller Home').action((id:string,o:CliOptions)=>{const entry=registry().plugins.find(x=>x.id===id);if(!entry)throw new Error(`PLUGIN_NOT_IN_OFFICIAL_CATALOG: ${id}`);const result=install(entry,resolveControllerHome(o.controllerHome));if(o.json)console.log(JSON.stringify(result,null,2));else{console.log(`Installed ${entry.name} ${entry.version} (${(result.health as {state?:string})?.state??'unknown'}).`);for(const step of (result.nextSteps as string[]|undefined)??[])console.log(`- ${step}`);}});
|
|
73
100
|
return root;
|
|
74
101
|
}
|
|
@@ -310,7 +310,10 @@ export async function verifyRecoveryConnector(
|
|
|
310
310
|
body: initializeBody,
|
|
311
311
|
});
|
|
312
312
|
const challenge = response.headers.get('www-authenticate') ?? '';
|
|
313
|
-
const ok = response.status === 401
|
|
313
|
+
const ok = response.status === 401
|
|
314
|
+
&& /\bBearer\b/i.test(challenge)
|
|
315
|
+
&& challenge.includes('error="invalid_token"')
|
|
316
|
+
&& challenge.includes('oauth-protected-resource');
|
|
314
317
|
probes.unauthenticatedChallenge = { ok, status: response.status };
|
|
315
318
|
if (!ok) failures.push('unauthenticatedChallenge: Recovery MCP did not return the expected OAuth Bearer challenge.');
|
|
316
319
|
} catch (error) {
|
|
@@ -514,11 +517,15 @@ export function buildRecoveryCommand(): Command {
|
|
|
514
517
|
const home = resolveControllerHome(opts.controllerHome);
|
|
515
518
|
const repoRoot = resolve(opts.repo);
|
|
516
519
|
const current = loadRecoveryConfig(home);
|
|
517
|
-
const
|
|
520
|
+
const primaryConnectorBase = launchdService(
|
|
518
521
|
opts.primaryConnectorServiceLabel,
|
|
519
522
|
opts.primaryConnectorServicePlist,
|
|
520
523
|
'RECOVERY_PRIMARY_CONNECTOR',
|
|
521
524
|
) as PrimaryConnectorServiceConfig;
|
|
525
|
+
const primaryConnectorService: PrimaryConnectorServiceConfig = {
|
|
526
|
+
...primaryConnectorBase,
|
|
527
|
+
...(current.primaryConnectorService?.localMcpUrl ? { localMcpUrl: current.primaryConnectorService.localMcpUrl } : {}),
|
|
528
|
+
};
|
|
522
529
|
const installed = await installStandaloneRecovery({
|
|
523
530
|
controllerHome: home,
|
|
524
531
|
repoRoot,
|
|
@@ -526,6 +533,7 @@ export function buildRecoveryCommand(): Command {
|
|
|
526
533
|
publicMcpUrl: current.publicMcpUrl,
|
|
527
534
|
recoveryPublicUrl: current.recoveryPublicUrl,
|
|
528
535
|
recoveryTunnelService: current.recoveryTunnelService,
|
|
536
|
+
primaryPublicTunnelService: current.primaryPublicTunnelService,
|
|
529
537
|
primaryRuntimeService: current.primaryRuntimeService ?? { platform: 'launchd' },
|
|
530
538
|
primaryConnectorService,
|
|
531
539
|
});
|
|
@@ -622,6 +630,9 @@ export function buildRecoveryCommand(): Command {
|
|
|
622
630
|
.option('--recovery-tunnel-service-plist <path>', 'Absolute Recovery tunnel launchd plist path')
|
|
623
631
|
.option('--primary-connector-service-label <label>', 'Primary OAuth/Connector launchd label managed by standalone Recovery')
|
|
624
632
|
.option('--primary-connector-service-plist <path>', 'Absolute primary OAuth/Connector launchd plist path')
|
|
633
|
+
.option('--primary-connector-local-url <url>', 'Local primary OAuth/Connector MCP endpoint used to distinguish Connector from tunnel failures')
|
|
634
|
+
.option('--primary-tunnel-service-label <label>', 'Primary public MCP tunnel launchd label managed by standalone Recovery')
|
|
635
|
+
.option('--primary-tunnel-service-plist <path>', 'Absolute primary public MCP tunnel launchd plist path')
|
|
625
636
|
.option('--stage-only', 'Build and canary the Recovery release without activating services')
|
|
626
637
|
.action(async (opts: {
|
|
627
638
|
controllerHome: string;
|
|
@@ -632,13 +643,23 @@ export function buildRecoveryCommand(): Command {
|
|
|
632
643
|
recoveryTunnelServicePlist?: string;
|
|
633
644
|
primaryConnectorServiceLabel?: string;
|
|
634
645
|
primaryConnectorServicePlist?: string;
|
|
646
|
+
primaryConnectorLocalUrl?: string;
|
|
647
|
+
primaryTunnelServiceLabel?: string;
|
|
648
|
+
primaryTunnelServicePlist?: string;
|
|
635
649
|
stageOnly?: boolean;
|
|
636
650
|
}) => {
|
|
637
651
|
const home = resolveControllerHome(opts.controllerHome);
|
|
638
652
|
const port = Number(opts.port);
|
|
639
653
|
if (!Number.isInteger(port) || port < 1024 || port > 65535) throw new Error('RECOVERY_PORT_INVALID');
|
|
640
654
|
const recoveryTunnelService = launchdService(opts.recoveryTunnelServiceLabel, opts.recoveryTunnelServicePlist, 'RECOVERY_TUNNEL') as PublicTunnelServiceConfig | undefined;
|
|
641
|
-
const
|
|
655
|
+
const primaryConnectorBase = launchdService(opts.primaryConnectorServiceLabel, opts.primaryConnectorServicePlist, 'RECOVERY_PRIMARY_CONNECTOR') as PrimaryConnectorServiceConfig | undefined;
|
|
656
|
+
const primaryConnectorLocalUrl = endpoint(opts.primaryConnectorLocalUrl, 'RECOVERY_PRIMARY_CONNECTOR_LOCAL_URL');
|
|
657
|
+
if (primaryConnectorLocalUrl && !primaryConnectorBase) throw new Error('RECOVERY_PRIMARY_CONNECTOR_LABEL_REQUIRED_FOR_LOCAL_URL');
|
|
658
|
+
const primaryConnectorService = primaryConnectorBase
|
|
659
|
+
? { ...primaryConnectorBase, ...(primaryConnectorLocalUrl ? { localMcpUrl: primaryConnectorLocalUrl } : {}) }
|
|
660
|
+
: undefined;
|
|
661
|
+
const primaryPublicTunnelService = launchdService(opts.primaryTunnelServiceLabel, opts.primaryTunnelServicePlist, 'RECOVERY_PRIMARY_TUNNEL') as PublicTunnelServiceConfig | undefined;
|
|
662
|
+
if (primaryPublicTunnelService && !primaryConnectorService) throw new Error('RECOVERY_PRIMARY_CONNECTOR_REQUIRED_FOR_PRIMARY_TUNNEL');
|
|
642
663
|
const recoveryPublicUrl = endpoint(opts.recoveryPublicUrl, 'RECOVERY_PUBLIC_URL');
|
|
643
664
|
if (Boolean(recoveryTunnelService) !== Boolean(recoveryPublicUrl)) {
|
|
644
665
|
throw new Error('RECOVERY_PUBLIC_URL_AND_TUNNEL_SERVICE_MUST_BE_CONFIGURED_TOGETHER');
|
|
@@ -653,6 +674,7 @@ export function buildRecoveryCommand(): Command {
|
|
|
653
674
|
publicMcpUrl: endpoint(opts.publicMcpUrl, 'PUBLIC_MCP_URL'),
|
|
654
675
|
recoveryPublicUrl,
|
|
655
676
|
recoveryTunnelService,
|
|
677
|
+
primaryPublicTunnelService,
|
|
656
678
|
primaryConnectorService,
|
|
657
679
|
});
|
|
658
680
|
output({
|