@moretea-labs/forge 1.6.0 → 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 +26 -0
- package/CLAUDE.md +2 -0
- package/README.md +2 -2
- package/README.zh-CN.md +1 -1
- 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/prompt-guard.sh +5 -81
- 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 +1 -1
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/harness-overview.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 +11 -36
- 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/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 +26 -6
- package/docs/operations/controller-performance-and-502.md +124 -0
- package/docs/operations/controller-reliability-runbook.md +1 -1
- package/docs/operations/features.md +2 -2
- 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/wiki/Architecture.md +6 -6
- package/docs/wiki/Implementation.md +2 -2
- package/docs/wiki/Integrations.md +2 -2
- 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-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-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/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/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +1 -1
- 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 +785 -469
- 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/installer/managed-entries.ts +15 -1
- package/src/cli/local-bridge/console-automations.ts +54 -78
- package/src/cli/local-bridge/console-view-models.ts +1 -35
- package/src/cli/local-bridge/facade-api.ts +0 -217
- package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +23 -13
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +6 -4
- package/src/cli/local-bridge/frontend/src/lib/api.ts +1 -6
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -2
- package/src/cli/local-bridge/frontend/src/styles.css +1 -1
- package/src/cli/local-bridge/frontend/src/types.ts +5 -8
- package/src/cli/local-bridge/job-store.ts +1 -490
- package/src/cli/local-bridge/server.ts +0 -513
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +3703 -3757
- 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/repository-tools.ts +247 -107
- package/src/cli/mcp/server.ts +537 -111
- 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 +101 -14
- package/src/cli/mcp/transports/session-registry.ts +43 -5
- package/src/cli/mcp/types.ts +3 -3
- package/src/cli/repositories/command-classifier.ts +101 -19
- 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/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +61 -3
- package/src/cli/repository/inspector.ts +553 -63
- 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 +47 -8
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/session-store.ts +18 -0
- 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 +143 -8
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +85 -8
- 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 +132 -1
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +2 -0
- package/src/runtime/control-plane/facade/goal-workloop.ts +686 -129
- package/src/runtime/control-plane/facade/index.ts +1 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +185 -20
- 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 +22 -5
- package/src/runtime/control-plane/facade/work-contract-store.ts +175 -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 +355 -116
- 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/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 +13 -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 +51 -4
- package/src/runtime/execution/process-runtime/check-result.ts +53 -0
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +345 -40
- package/src/runtime/execution/process-runtime/gc.ts +38 -6
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +47 -4
- package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
- package/src/runtime/execution/process-runtime/runtime.ts +43 -3
- package/src/runtime/execution/process-runtime/store.ts +1 -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 +1192 -114
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +184 -82
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2224 -1589
- package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
- package/src/runtime/plugins/browser-adapter.ts +2901 -241
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff.ts +92 -2
- package/src/runtime/plugins/browser-macos-bridge.ts +582 -49
- 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 +8 -2
- package/src/runtime/plugins/external-adapter.ts +324 -3
- package/src/runtime/plugins/external-unix-socket.ts +7 -1
- package/src/runtime/plugins/first-party-registry.ts +2 -0
- package/src/runtime/plugins/github-adapter.ts +125 -0
- 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 +123 -6
- 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 +49 -8
- package/src/runtime/plugins/resend-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +269 -29
- package/src/runtime/plugins/types.ts +35 -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/maintenance-executor.ts +393 -28
- 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 +19 -0
- package/src/runtime/root/release-store.ts +48 -11
- package/src/runtime/root/runtime.ts +23 -5
- package/src/runtime/root/service.ts +100 -29
- package/src/runtime/root/types.ts +2 -0
- package/src/runtime/safe-tooling/ios-development.ts +321 -63
- 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 +700 -92
- 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 +81 -3
- package/src/runtime/workflow/schedules/engine.ts +287 -151
- 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 +2 -4
- package/src/runtime/workflow/schedules/work-continuation.ts +26 -13
- 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/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 -459
- package/docs/architecture/current/codegraph-context-provider.md +0 -238
- 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 -373
- package/docs/architecture/current/entity-model.md +0 -612
- 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 -169
- 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 -321
- 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 -93
- 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/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
|
@@ -19,6 +19,9 @@ export interface ExternalControllerLaunchReservation {
|
|
|
19
19
|
createdAt: string;
|
|
20
20
|
expiresAt: string;
|
|
21
21
|
pid?: number;
|
|
22
|
+
exitedAt?: string;
|
|
23
|
+
exitCode?: number;
|
|
24
|
+
exitSignal?: string;
|
|
22
25
|
releasedAt?: string;
|
|
23
26
|
releaseReason?: string;
|
|
24
27
|
}
|
|
@@ -128,6 +131,43 @@ export function attachExternalControllerLaunchPid(
|
|
|
128
131
|
);
|
|
129
132
|
}
|
|
130
133
|
|
|
134
|
+
export function recordExternalControllerLaunchExit(
|
|
135
|
+
options: LaunchReservationStoreOptions,
|
|
136
|
+
workId: string,
|
|
137
|
+
reservationId: string,
|
|
138
|
+
exit: { exitCode: number | null; signal: string | null },
|
|
139
|
+
): ExternalControllerLaunchReservation | undefined {
|
|
140
|
+
return withControllerLock(
|
|
141
|
+
options.controllerHome,
|
|
142
|
+
{ scope: 'task', repoId: options.repoId, taskId: `controller-launch-${workId}` },
|
|
143
|
+
`controller-launch-exit:${reservationId}`,
|
|
144
|
+
() => {
|
|
145
|
+
const existing = record(options, workId);
|
|
146
|
+
if (!existing || existing.value.reservationId !== reservationId || existing.value.releasedAt) return existing?.value;
|
|
147
|
+
const exitedAt = nowIso(options);
|
|
148
|
+
const next: ExternalControllerLaunchReservation = {
|
|
149
|
+
...existing.value,
|
|
150
|
+
expiresAt: exitedAt,
|
|
151
|
+
exitedAt,
|
|
152
|
+
...(exit.exitCode === null ? {} : { exitCode: exit.exitCode }),
|
|
153
|
+
...(exit.signal ? { exitSignal: exit.signal } : {}),
|
|
154
|
+
releasedAt: exitedAt,
|
|
155
|
+
releaseReason: `process_exit:code=${String(exit.exitCode ?? 'null')}:signal=${exit.signal ?? 'none'}`.slice(0, 240),
|
|
156
|
+
};
|
|
157
|
+
writeControlPlaneRecord(options.controllerHome, {
|
|
158
|
+
namespace: NAMESPACE,
|
|
159
|
+
scope: options.repoId,
|
|
160
|
+
key: workId,
|
|
161
|
+
schemaVersion: 1,
|
|
162
|
+
value: next,
|
|
163
|
+
action: 'external_controller_launch_exit',
|
|
164
|
+
expectedRevision: existing.revision,
|
|
165
|
+
});
|
|
166
|
+
return next;
|
|
167
|
+
},
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
131
171
|
export function releaseExternalControllerLaunchReservation(
|
|
132
172
|
options: LaunchReservationStoreOptions,
|
|
133
173
|
workId: string,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { spawn, spawnSync } from 'child_process';
|
|
1
|
+
import { spawn, spawnSync, type ChildProcess } from 'child_process';
|
|
2
2
|
import {
|
|
3
3
|
getHandoffItem,
|
|
4
4
|
getWorkContract,
|
|
@@ -7,12 +7,15 @@ import {
|
|
|
7
7
|
} from '../facade';
|
|
8
8
|
import {
|
|
9
9
|
attachExternalControllerLaunchPid,
|
|
10
|
+
recordExternalControllerLaunchExit,
|
|
10
11
|
releaseExternalControllerLaunchReservation,
|
|
11
12
|
reserveExternalControllerLaunch,
|
|
12
13
|
} from './launch-reservation-store';
|
|
13
14
|
import type { ControllerType } from '../facade/types';
|
|
15
|
+
import { getControllerSession } from '../facade/controller-session-store';
|
|
14
16
|
import { codexMcpConfigArgs, resolveProviderMcpBootstrap, type ProviderMcpBootstrap } from './provider-mcp-bootstrap';
|
|
15
17
|
import { getChatgptWorkConversationBinding } from './chatgpt-work-binding-store';
|
|
18
|
+
import { repositoryChildProcessEnvironment } from '../../shared/process-environment';
|
|
16
19
|
|
|
17
20
|
export interface ThinLauncherRequest {
|
|
18
21
|
controllerType: Exclude<ControllerType, 'human'>;
|
|
@@ -42,7 +45,35 @@ export interface ThinLauncherResult {
|
|
|
42
45
|
executable: string;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
const LAUNCHER_STARTUP_GRACE_MS = 250;
|
|
49
|
+
const CODEX_WORK_CLAIM_TIMEOUT_MS = 30_000;
|
|
50
|
+
const CODEX_WORK_CLAIM_POLL_INTERVAL_MS = 100;
|
|
51
|
+
|
|
52
|
+
interface ExternalControllerClaimExpectation {
|
|
53
|
+
controllerType: 'codex';
|
|
54
|
+
controllerId: string;
|
|
55
|
+
principalId: string;
|
|
56
|
+
sessionId: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ThinLauncherDependencies {
|
|
60
|
+
resolveProviderMcpBootstrap?: typeof resolveProviderMcpBootstrap;
|
|
61
|
+
claimTimeoutMs?: number;
|
|
62
|
+
claimPollIntervalMs?: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function launcherProcessEnvironment(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
|
|
66
|
+
const repositoryEnv = repositoryChildProcessEnvironment(env);
|
|
67
|
+
return {
|
|
68
|
+
...env,
|
|
69
|
+
PATH: repositoryEnv.PATH,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function resolveLauncherExecutable(
|
|
74
|
+
request: ThinLauncherRequest,
|
|
75
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
76
|
+
): string {
|
|
46
77
|
const configured = request.executable?.trim();
|
|
47
78
|
if (configured) return configured;
|
|
48
79
|
const executable = request.controllerType === 'codex'
|
|
@@ -50,13 +81,14 @@ function resolveLauncherExecutable(request: ThinLauncherRequest): string {
|
|
|
50
81
|
: request.controllerType === 'claude'
|
|
51
82
|
? 'claude'
|
|
52
83
|
: request.controllerType === 'chatgpt'
|
|
53
|
-
?
|
|
84
|
+
? env.FORGE_CLI_EXECUTABLE?.trim() || 'forge'
|
|
54
85
|
: '';
|
|
55
86
|
if (!executable) throw new Error(`LAUNCHER_EXECUTABLE_REQUIRED: ${request.controllerType} requires an external launcher executable`);
|
|
56
87
|
const probe = spawnSync(executable, ['--version'], {
|
|
57
88
|
cwd: request.cwd,
|
|
58
89
|
stdio: 'ignore',
|
|
59
90
|
timeout: 5_000,
|
|
91
|
+
env: launcherProcessEnvironment(env),
|
|
60
92
|
});
|
|
61
93
|
if (probe.error || probe.status !== 0) {
|
|
62
94
|
throw new Error(`LAUNCHER_EXECUTABLE_UNAVAILABLE: ${executable}`);
|
|
@@ -64,6 +96,141 @@ function resolveLauncherExecutable(request: ThinLauncherRequest): string {
|
|
|
64
96
|
return executable;
|
|
65
97
|
}
|
|
66
98
|
|
|
99
|
+
async function awaitExternalControllerStartup(
|
|
100
|
+
child: ChildProcess,
|
|
101
|
+
stores: { work: WorkContractStoreOptions & { controllerHome: string; repoId: string } },
|
|
102
|
+
workId: string,
|
|
103
|
+
reservationId: string,
|
|
104
|
+
claimExpectation?: ExternalControllerClaimExpectation,
|
|
105
|
+
options: { claimTimeoutMs?: number; claimPollIntervalMs?: number } = {},
|
|
106
|
+
): Promise<void> {
|
|
107
|
+
await new Promise<void>((resolve, reject) => {
|
|
108
|
+
let startupSettled = false;
|
|
109
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
110
|
+
const clearTimer = () => {
|
|
111
|
+
if (timer) clearTimeout(timer);
|
|
112
|
+
timer = undefined;
|
|
113
|
+
};
|
|
114
|
+
const releaseFailure = (reason: string) => {
|
|
115
|
+
try {
|
|
116
|
+
releaseExternalControllerLaunchReservation(stores.work, workId, reservationId, reason);
|
|
117
|
+
} catch {
|
|
118
|
+
// Preserve the primary startup failure if diagnostic persistence itself races or fails.
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const terminateUnclaimedChild = () => {
|
|
122
|
+
if (!child.pid || child.exitCode !== null || child.signalCode !== null) return;
|
|
123
|
+
try { child.kill('SIGTERM'); } catch { /* process may already be exiting */ }
|
|
124
|
+
};
|
|
125
|
+
const fail = (error: Error, reason: string, terminate = false) => {
|
|
126
|
+
if (startupSettled) return;
|
|
127
|
+
startupSettled = true;
|
|
128
|
+
clearTimer();
|
|
129
|
+
if (terminate) terminateUnclaimedChild();
|
|
130
|
+
releaseFailure(reason);
|
|
131
|
+
reject(error);
|
|
132
|
+
};
|
|
133
|
+
const expectedClaimMatches = (): { matches: boolean; mismatch?: string } => {
|
|
134
|
+
if (!claimExpectation) return { matches: true };
|
|
135
|
+
const owner = getControllerSession(stores.work, workId);
|
|
136
|
+
if (!owner) return { matches: false };
|
|
137
|
+
const ownerPrincipal = owner.principalId?.trim() || owner.controllerId;
|
|
138
|
+
const matches = owner.controllerType === claimExpectation.controllerType
|
|
139
|
+
&& owner.controllerId === claimExpectation.controllerId
|
|
140
|
+
&& ownerPrincipal === claimExpectation.principalId
|
|
141
|
+
&& owner.sessionId === claimExpectation.sessionId;
|
|
142
|
+
return matches
|
|
143
|
+
? { matches: true }
|
|
144
|
+
: {
|
|
145
|
+
matches: false,
|
|
146
|
+
mismatch: `observed type=${owner.controllerType} controller=${owner.controllerId} principal=${ownerPrincipal} session=${owner.sessionId}`,
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
child.once('error', (error) => {
|
|
151
|
+
fail(new Error(`LAUNCHER_STARTUP_FAILED: ${error.message}`), `spawn_error:${error.message}`);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
child.once('exit', (exitCode, signal) => {
|
|
155
|
+
try {
|
|
156
|
+
recordExternalControllerLaunchExit(stores.work, workId, reservationId, {
|
|
157
|
+
exitCode,
|
|
158
|
+
signal: signal ? String(signal) : null,
|
|
159
|
+
});
|
|
160
|
+
} catch {
|
|
161
|
+
// Exit evidence is best-effort after another authority has already released the reservation.
|
|
162
|
+
}
|
|
163
|
+
if (startupSettled) return;
|
|
164
|
+
startupSettled = true;
|
|
165
|
+
clearTimer();
|
|
166
|
+
const phase = claimExpectation ? 'before exact Work claim became live' : 'during startup grace';
|
|
167
|
+
reject(new Error(`LAUNCHER_STARTUP_FAILED: external Controller exited ${phase} (code=${String(exitCode ?? 'null')}, signal=${signal ?? 'none'})`));
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
if (!claimExpectation) {
|
|
171
|
+
timer = setTimeout(() => {
|
|
172
|
+
if (startupSettled) return;
|
|
173
|
+
startupSettled = true;
|
|
174
|
+
resolve();
|
|
175
|
+
}, LAUNCHER_STARTUP_GRACE_MS);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const claimTimeoutMs = Math.max(100, Math.min(options.claimTimeoutMs ?? CODEX_WORK_CLAIM_TIMEOUT_MS, 60_000));
|
|
180
|
+
const claimPollIntervalMs = Math.max(10, Math.min(options.claimPollIntervalMs ?? CODEX_WORK_CLAIM_POLL_INTERVAL_MS, 1_000));
|
|
181
|
+
const claimDeadline = Date.now() + claimTimeoutMs;
|
|
182
|
+
const pollClaim = () => {
|
|
183
|
+
if (startupSettled) return;
|
|
184
|
+
let observation: ReturnType<typeof expectedClaimMatches>;
|
|
185
|
+
try {
|
|
186
|
+
observation = expectedClaimMatches();
|
|
187
|
+
} catch (error) {
|
|
188
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
189
|
+
fail(new Error(`LAUNCHER_CLAIM_OBSERVATION_FAILED: ${message}`), `claim_observation_failed:${message}`, true);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (observation.mismatch) {
|
|
193
|
+
fail(
|
|
194
|
+
new Error(`LAUNCHER_CLAIM_MISMATCH: Work ${workId} expected type=${claimExpectation.controllerType} controller=${claimExpectation.controllerId} principal=${claimExpectation.principalId} session=${claimExpectation.sessionId}; ${observation.mismatch}`),
|
|
195
|
+
'claim_mismatch',
|
|
196
|
+
true,
|
|
197
|
+
);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (observation.matches) {
|
|
201
|
+
timer = setTimeout(() => {
|
|
202
|
+
if (startupSettled) return;
|
|
203
|
+
try {
|
|
204
|
+
const confirmation = expectedClaimMatches();
|
|
205
|
+
if (!confirmation.matches || confirmation.mismatch) {
|
|
206
|
+
fail(new Error(`LAUNCHER_CLAIM_LOST: Codex claim for exact Work ${workId} was not live after startup grace`), 'claim_lost', true);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
} catch (error) {
|
|
210
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
211
|
+
fail(new Error(`LAUNCHER_CLAIM_OBSERVATION_FAILED: ${message}`), `claim_observation_failed:${message}`, true);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
startupSettled = true;
|
|
215
|
+
timer = undefined;
|
|
216
|
+
resolve();
|
|
217
|
+
}, LAUNCHER_STARTUP_GRACE_MS);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (Date.now() >= claimDeadline) {
|
|
221
|
+
fail(
|
|
222
|
+
new Error(`LAUNCHER_CLAIM_TIMEOUT: Codex pid=${String(child.pid ?? 'unknown')} did not claim exact Work ${workId} through Forge MCP within ${claimTimeoutMs}ms`),
|
|
223
|
+
`claim_timeout:${claimTimeoutMs}ms`,
|
|
224
|
+
true,
|
|
225
|
+
);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
timer = setTimeout(pollClaim, claimPollIntervalMs);
|
|
229
|
+
};
|
|
230
|
+
pollClaim();
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
67
234
|
function assertChatgptConversationUrl(value: string | undefined): string | undefined {
|
|
68
235
|
const raw = value?.trim();
|
|
69
236
|
if (!raw) return undefined;
|
|
@@ -134,13 +301,14 @@ export function buildSuperControllerInvocation(
|
|
|
134
301
|
* provider process selection and prompt construction; the execution Kernel
|
|
135
302
|
* receives neither provider-specific arguments nor model output.
|
|
136
303
|
*/
|
|
137
|
-
export function launchSuperController(
|
|
304
|
+
export async function launchSuperController(
|
|
138
305
|
stores: {
|
|
139
306
|
work: WorkContractStoreOptions & { controllerHome: string; repoId: string };
|
|
140
307
|
handoff: HandoffInboxStoreOptions;
|
|
141
308
|
},
|
|
142
309
|
request: ThinLauncherRequest,
|
|
143
|
-
|
|
310
|
+
dependencies: ThinLauncherDependencies = {},
|
|
311
|
+
): Promise<ThinLauncherResult> {
|
|
144
312
|
const executable = resolveLauncherExecutable(request);
|
|
145
313
|
const work = getWorkContract(stores.work, request.workId);
|
|
146
314
|
if (!work) throw new Error(`WORK_NOT_FOUND: ${request.workId}`);
|
|
@@ -158,7 +326,7 @@ export function launchSuperController(
|
|
|
158
326
|
`Continue Forge Work ${work.workId} in repo ${work.repoId}.`,
|
|
159
327
|
handoff ? `Handoff: ${handoff.summary}\nNext: ${handoff.recommendedContinuationPrompt ?? handoff.recommendedPrompt}` : '',
|
|
160
328
|
request.continuationPrompt?.trim() ? `Continuation: ${request.continuationPrompt.trim()}` : '',
|
|
161
|
-
`First call rh_work
|
|
329
|
+
`No Controller ownership was preclaimed for this continued conversation. First call rh_work operation=controller_claim with repo_id=${work.repoId}, work_id=${work.workId}, and controller_type=chatgpt through your authenticated MCP session; do not invent controller_id/session_id. Only after that exact Work claim succeeds, call rh_work operation=continue with the same repo_id/work_id. Treat Forge Work/Plan/evidence as source of truth; do not invent new scope from chat history. If the claim does not succeed, do not mutate. Continue the next safe action, finalize only when acceptance passes, and create a HandoffItem when judgement is required.`,
|
|
162
330
|
].filter(Boolean).join('\n')
|
|
163
331
|
: [
|
|
164
332
|
`Work: ${work.workId}`,
|
|
@@ -167,21 +335,37 @@ export function launchSuperController(
|
|
|
167
335
|
`Current status: ${work.status}`,
|
|
168
336
|
handoff ? `Handoff: ${handoff.summary}\nNext: ${handoff.recommendedContinuationPrompt ?? handoff.recommendedPrompt}` : '',
|
|
169
337
|
request.continuationPrompt?.trim() ? `Continuation: ${request.continuationPrompt.trim()}` : '',
|
|
170
|
-
`No Controller ownership was preclaimed for you. First call rh_work
|
|
338
|
+
`No Controller ownership was preclaimed for you. First call rh_work operation=controller_claim with repo_id=${work.repoId}, work_id=${work.workId}, and controller_type=${request.controllerType} through your authenticated MCP session; do not invent controller_id/session_id. Only after that exact Work claim succeeds, call rh_work operation=continue with the same repo_id/work_id and continue the returned next safe action. If the claim does not succeed, do not mutate the repository: create no patch, command, commit, or test run until ownership is established. Then use the repository MCP facade, record verification evidence, finalize only when acceptance passes, and create a HandoffItem when judgement is required.`,
|
|
171
339
|
].filter(Boolean).join('\n');
|
|
172
340
|
try {
|
|
173
341
|
const mcpBootstrap = request.controllerType === 'codex'
|
|
174
|
-
? resolveProviderMcpBootstrap(stores.work.controllerHome, 'codex', reservation.reservationId)
|
|
342
|
+
? (dependencies.resolveProviderMcpBootstrap ?? resolveProviderMcpBootstrap)(stores.work.controllerHome, 'codex', reservation.reservationId)
|
|
175
343
|
: undefined;
|
|
176
344
|
const invocation = buildSuperControllerInvocation({ ...request, controllerHome: stores.work.controllerHome, repoId: work.repoId }, executable, prompt, mcpBootstrap);
|
|
177
345
|
const child = spawn(invocation.executable, invocation.args, {
|
|
178
346
|
cwd: request.cwd,
|
|
179
347
|
detached: true,
|
|
180
348
|
stdio: 'ignore',
|
|
181
|
-
env: mcpBootstrap?.env ?? process.env,
|
|
349
|
+
env: launcherProcessEnvironment(mcpBootstrap?.env ?? process.env),
|
|
182
350
|
});
|
|
183
|
-
child.unref();
|
|
184
351
|
attachExternalControllerLaunchPid(stores.work, work.workId, reservation.reservationId, child.pid);
|
|
352
|
+
await awaitExternalControllerStartup(
|
|
353
|
+
child,
|
|
354
|
+
stores,
|
|
355
|
+
work.workId,
|
|
356
|
+
reservation.reservationId,
|
|
357
|
+
mcpBootstrap ? {
|
|
358
|
+
controllerType: 'codex',
|
|
359
|
+
controllerId: mcpBootstrap.principalId,
|
|
360
|
+
principalId: mcpBootstrap.principalId,
|
|
361
|
+
sessionId: mcpBootstrap.sessionId,
|
|
362
|
+
} : undefined,
|
|
363
|
+
{
|
|
364
|
+
claimTimeoutMs: dependencies.claimTimeoutMs,
|
|
365
|
+
claimPollIntervalMs: dependencies.claimPollIntervalMs,
|
|
366
|
+
},
|
|
367
|
+
);
|
|
368
|
+
child.unref();
|
|
185
369
|
return { controllerType: request.controllerType, reservationId: reservation.reservationId, pid: child.pid, prompt, executable };
|
|
186
370
|
} catch (error) {
|
|
187
371
|
releaseExternalControllerLaunchReservation(stores.work, work.workId, reservation.reservationId, 'spawn_failed');
|