@moretea-labs/forge 1.8.0 → 1.8.1
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 +70 -7
- package/CHANGELOG.md +14 -0
- package/CLAUDE.md +17 -2
- package/CONTRIBUTING.md +3 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/adapters/chatgpt/browser-delivery-host.ts +7 -1
- package/adapters/chatgpt/browser-delivery-runtime.ts +529 -56
- package/adapters/chatgpt/controller-binding-store.ts +101 -22
- package/adapters/chatgpt/controller-round-host.ts +15 -25
- package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
- package/adapters/chatgpt/provider-delivery.ts +228 -1
- package/adapters/chatgpt/work-conversation-binding-store.ts +79 -53
- package/adapters/computer/chatgpt-extension-target.ts +463 -0
- package/adapters/computer/chatgpt-target-router.ts +103 -0
- package/adapters/computer/chrome-extension/background.js +385 -0
- package/adapters/computer/chrome-extension/content.js +378 -0
- package/adapters/computer/chrome-extension/core.js +24 -0
- package/adapters/computer/chrome-extension/manifest.json +30 -0
- package/adapters/computer/desktop-operator-discovery.ts +11 -31
- package/adapters/computer/interaction-target-authority.ts +142 -18
- package/adapters/mcp/auth.ts +0 -1
- package/adapters/mcp/instructions.ts +5 -4
- package/adapters/mcp/multi-repository.ts +3 -19
- package/adapters/mcp/oauth.ts +73 -0
- package/adapters/mcp/paths.ts +4 -1
- package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
- package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
- package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
- package/adapters/mcp/runtime-gateway/context-adapter.ts +411 -73
- package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
- package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
- package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
- package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
- package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
- package/adapters/mcp/runtime-gateway/execution-tools.ts +8 -42
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
- package/adapters/mcp/runtime-gateway/plugin-adapter.ts +117 -45
- package/adapters/mcp/runtime-gateway/process-tools.ts +190 -22
- package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
- package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
- package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
- package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
- package/adapters/mcp/runtime-gateway/router.ts +18 -504
- package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +14 -65
- package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +113 -173
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +15 -5
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +1 -0
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +358 -266
- package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +261 -3122
- package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
- package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
- package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
- package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
- package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
- package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
- package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
- package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
- package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
- package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
- package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
- package/adapters/mcp/server.ts +67 -23
- package/adapters/mcp/setup.ts +1 -3
- package/adapters/mcp/tool-mapping/legacy-tool-service.ts +44 -170
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +4 -9
- package/adapters/mcp/tool-mapping/repository-tools.ts +133 -142
- package/adapters/mcp/toolset-names.ts +5 -0
- package/adapters/mcp/toolset.ts +6 -5
- package/adapters/mcp/transports/http-observation.ts +365 -0
- package/adapters/mcp/transports/http.ts +154 -677
- package/adapters/mcp/transports/oauth-http.ts +322 -0
- package/adapters/mcp/transports/session-registry.ts +6 -0
- package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
- package/assets/plugin-registry.v1.json +6 -4
- package/assets/reference-configs/agentic-development-flow.md +25 -0
- package/assets/reference-configs/global-working-rules.md +19 -0
- package/assets/skill-version.json +2 -2
- package/docs/architecture/CURRENT.md +111 -41
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
- package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
- package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
- package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
- package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
- package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
- package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
- package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
- package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
- package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
- package/docs/architecture/domains/verification.md +1 -0
- package/docs/architecture/domains/workflow-engine.md +6 -0
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/forge-plugin-management.md +2 -2
- package/docs/operations/controller-performance-and-502.md +17 -0
- package/docs/operations/controller-reliability-runbook.md +2 -2
- package/docs/operations/features.md +1 -1
- package/docs/operations/features.zh-CN.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +2 -0
- package/docs/operations/releasing.md +2 -0
- package/docs/operations/standalone-disaster-recovery.md +14 -6
- package/docs/wiki/Implementation.md +1 -1
- package/package.json +25 -14
- package/packages/kernel/cognition/api/index.ts +6 -0
- package/packages/kernel/cognition/application/activation-service.ts +451 -0
- package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
- package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
- package/packages/kernel/cognition/application/memory-service.ts +64 -0
- package/packages/kernel/cognition/domain/learning.ts +106 -0
- package/packages/kernel/cognition/domain/memory.ts +254 -0
- package/packages/kernel/controller/api/index.ts +1 -0
- package/packages/kernel/controller/application/continuation-service.ts +281 -0
- package/packages/kernel/controller/application/controller-round-service.ts +12 -0
- package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
- package/packages/kernel/controller/domain/controller-round.ts +4 -1
- package/packages/kernel/controller/domain/execution-quality.ts +3 -1
- package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
- package/packages/kernel/controller/infrastructure/controller-session-store.ts +297 -71
- package/packages/kernel/controller/ports/controller-host.ts +2 -0
- package/packages/kernel/identity/api/index.ts +10 -0
- package/packages/kernel/identity/domain/activity-projection.ts +43 -0
- package/packages/kernel/identity/domain/capability-broker.ts +60 -0
- package/packages/kernel/identity/domain/grant.ts +72 -0
- package/packages/kernel/identity/domain/owned-resource.ts +116 -0
- package/packages/kernel/identity/domain/user-request.ts +93 -0
- package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
- package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
- package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
- package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
- package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
- package/packages/kernel/scheduler/api/index.ts +0 -2
- package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
- package/packages/kernel/scheduler/application/settlement.ts +0 -15
- package/packages/kernel/scheduler/domain/schedule.ts +87 -0
- package/packages/kernel/scheduler/infrastructure/schedule-store.ts +153 -133
- package/packages/kernel/work/api/index.ts +3 -2
- package/packages/kernel/work/application/work-service.ts +17 -42
- package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
- package/packages/kernel/work/domain/engineering-design.ts +10 -5
- package/packages/kernel/work/domain/engineering-profile.ts +8 -12
- package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
- package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
- package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
- package/packages/kernel/work/domain/implementation-review.ts +14 -331
- package/packages/kernel/work/domain/objective-graph.ts +119 -0
- package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
- package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
- package/packages/kernel/work/domain/state-machine.ts +25 -63
- package/packages/kernel/work/domain/types.ts +57 -51
- package/packages/kernel/work/infrastructure/work-contract-store.ts +819 -728
- package/packages/kernel/work/ports/work-contract-store.ts +5 -2
- package/packages/plugin-runtime/browser/session-authority.ts +2 -1
- package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
- package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
- package/packages/plugin-runtime/computer/index.ts +2 -0
- package/packages/plugin-runtime/computer/target-authority.ts +26 -1
- package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
- package/packages/protocols/computer/contract.ts +27 -1
- package/scripts/activate-source-baseline.ts +7 -9
- package/scripts/canary-controller-semantic-wait.ts +12 -24
- package/scripts/check-mcp-compatibility.ts +48 -136
- package/scripts/check-runtime-architecture.mjs +622 -217
- package/scripts/forge-local-recovery-helper.mjs +93 -15
- package/scripts/lib/project-init-lib.sh +3 -0
- package/scripts/open-source-audit-allowlist.txt +1 -2
- package/scripts/run-bounded-command.mjs +5 -0
- package/scripts/run-governed-gate.ts +0 -1
- package/scripts/run-mobile-monitor-bridge.ts +0 -1
- package/scripts/smoke-control-plane-failure-domain.ts +94 -0
- package/scripts/smoke-mcp-http-runtime.ts +5 -0
- package/scripts/smoke-runtime-recovery.ts +12 -43
- package/scripts/smoke-schedule-engine.ts +23 -15
- package/scripts/smoke-unattended-transport-recovery.ts +223 -0
- package/scripts/smoke-user-request-continuation-restart.ts +232 -0
- package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
- package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
- package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
- package/scripts/smoke-workflow-supervisor.ts +103 -0
- package/scripts/verify-forge-runtime.sh +2 -1
- package/src/cli/agent-jobs/executor-health.ts +11 -34
- package/src/cli/agent-jobs/integration.ts +18 -49
- package/src/cli/agent-jobs/job-manager.ts +7 -3
- package/src/cli/commands/brain-assistant.ts +27 -13
- package/src/cli/commands/brain.ts +13 -15
- package/src/cli/commands/chatgpt.ts +1 -163
- package/src/cli/commands/recovery.ts +135 -121
- package/src/cli/commands/runtime.ts +3 -3
- package/src/cli/commands/setup-profile.ts +8 -0
- package/src/cli/controller/check-runner.ts +13 -2
- package/src/cli/controller/completion-backlog.ts +3 -3
- package/src/cli/controller/completion-orchestrator.ts +4 -43
- package/src/cli/controller/completion-target.ts +3 -72
- package/src/cli/controller/context/source-materializer.ts +81 -100
- package/src/cli/controller/context-pack.ts +10 -8
- package/src/cli/controller/execution-completion.ts +4 -7
- package/src/cli/controller/execution-policy.ts +36 -153
- package/src/cli/controller/governance.ts +2 -3
- package/src/cli/controller/issue-store.ts +4 -99
- package/src/cli/controller/launch-agents.ts +59 -18
- package/src/cli/controller/operational-plan.ts +24 -51
- package/src/cli/controller/runtime-config.ts +5 -1
- package/src/cli/controller/stuck-state-migration.ts +2 -3
- package/src/cli/controller/systemd-user.ts +39 -1
- package/src/cli/editing/edit-session.ts +1 -7
- package/src/cli/local-bridge/console-automations.ts +18 -13
- package/src/cli/local-bridge/console-view-models.ts +3 -12
- package/src/cli/local-bridge/facade-api.ts +64 -191
- package/src/cli/local-bridge/server.ts +24 -147
- package/src/cli/local-bridge/types.ts +0 -1
- package/src/cli/mcp/oauth-client-retirement.ts +74 -0
- package/src/cli/repositories/command-executor.ts +29 -23
- package/src/cli/repositories/command-scope.ts +35 -16
- package/src/cli/repositories/controller-home.ts +48 -0
- package/src/cli/repositories/ephemeral-workspace.ts +20 -30
- package/src/cli/repositories/git-command-executor.ts +2 -2
- package/src/cli/repositories/registry.ts +77 -11
- package/src/cli/repositories/structured-git.ts +62 -2
- package/src/cli/repository/session-cache.ts +92 -6
- package/src/runtime/context/assistant-context.ts +20 -7
- package/src/runtime/context/assistant-work-context.ts +89 -27
- package/src/runtime/context/automatic-learning.ts +565 -0
- package/src/runtime/context/cognitive-attention.ts +173 -0
- package/src/runtime/context/cognitive-skill-canary.ts +158 -0
- package/src/runtime/context/context-closure.ts +46 -9
- package/src/runtime/context/context-pack-process.ts +103 -0
- package/src/runtime/context/context-plane.ts +1 -9
- package/src/runtime/context/direct-controller-learning.ts +298 -0
- package/src/runtime/context/semantic-navigation-contract.ts +9 -0
- package/src/runtime/context/semantic-navigation.ts +6 -34
- package/src/runtime/context/typescript-navigation-process.ts +145 -0
- package/src/runtime/context/typescript-navigation.ts +89 -3
- package/src/runtime/control-plane/cleanup-artifact-retention.ts +212 -9
- package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
- package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
- package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
- package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
- package/src/runtime/control-plane/execution/session-store.ts +31 -1
- package/src/runtime/control-plane/execution/validation.ts +6 -8
- package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
- package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
- package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
- package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
- package/src/runtime/control-plane/execution/work-handle-authority.ts +188 -109
- package/src/runtime/control-plane/execution/work-handle-store.ts +19 -43
- package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
- package/src/runtime/control-plane/execution/work-operation-service.ts +43 -27
- package/src/runtime/control-plane/execution/work-preparation-service.ts +126 -266
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
- package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +173 -186
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -84
- package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
- package/src/runtime/control-plane/facade/capability-registry.ts +362 -37
- package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
- package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
- package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
- package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
- package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
- package/src/runtime/control-plane/facade/index.ts +0 -1
- package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
- package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
- package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
- package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
- package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
- package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
- package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
- package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
- package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
- package/src/runtime/control-plane/facade/types.ts +49 -108
- package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
- package/src/runtime/control-plane/generated-cache-retention.ts +97 -1
- package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +239 -112
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +2 -1
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
- package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
- package/src/runtime/control-plane/governance/access-policy.ts +19 -2
- package/src/runtime/control-plane/governance/authorization.ts +20 -3
- package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +28 -300
- package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
- package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
- package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
- package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
- package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
- package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
- package/src/runtime/control-plane/release-retention.ts +135 -47
- package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
- package/src/runtime/control-plane/runtime-cleanup.ts +290 -21
- package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
- package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
- package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
- package/src/runtime/diagnostics/incident-repair.ts +313 -146
- package/src/runtime/diagnostics/mcp-timing.ts +114 -0
- package/src/runtime/evidence/artifact-store.ts +158 -40
- package/src/runtime/evidence/evidence-store.ts +112 -8
- package/src/runtime/evidence/output-handle-index.ts +225 -0
- package/src/runtime/evidence/result-store.ts +158 -44
- package/src/runtime/execution/jobs/store.ts +3 -4
- package/src/runtime/execution/managed-workspace.ts +57 -0
- package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
- package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
- package/src/runtime/execution/process-runtime/check-result.ts +105 -1
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
- package/src/runtime/execution/process-runtime/command-facade.ts +79 -27
- package/src/runtime/execution/process-runtime/gc.ts +15 -2
- package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
- package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
- package/src/runtime/execution/process-runtime/index.ts +3 -0
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
- package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
- package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
- package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
- package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
- package/src/runtime/execution/process-runtime/runtime.ts +35 -2
- package/src/runtime/execution/process-runtime/store.ts +30 -2
- package/src/runtime/execution/process-runtime/types.ts +6 -1
- package/src/runtime/execution/workers/executor.ts +2 -6
- package/src/runtime/platform/service-inventory.ts +130 -0
- package/src/runtime/platform/service-manager.ts +8 -0
- package/src/runtime/plugins/action-application.ts +85 -28
- package/src/runtime/plugins/app-store-connect-adapter.ts +38 -14
- package/src/runtime/plugins/browser-adapter.ts +757 -34
- package/src/runtime/plugins/browser-automation-service.ts +23 -3
- package/src/runtime/plugins/browser-macos-bridge.ts +321 -29
- package/src/runtime/plugins/browser-manifest-surface.ts +45 -11
- package/src/runtime/plugins/browser-native-session-service.ts +63 -13
- package/src/runtime/plugins/browser-registration.ts +16 -0
- package/src/runtime/plugins/browser-runtime.ts +14 -1
- package/src/runtime/plugins/browser-session-authority.ts +2 -2
- package/src/runtime/plugins/browser-session-store.ts +46 -76
- package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
- package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
- package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
- package/src/runtime/plugins/computer-registration.ts +222 -11
- package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
- package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
- package/src/runtime/plugins/external-adapter.ts +42 -6
- package/src/runtime/plugins/external-registration.ts +21 -1
- package/src/runtime/plugins/gmail-adapter.ts +23 -2
- package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
- package/src/runtime/plugins/google-shared.ts +14 -7
- package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
- package/src/runtime/plugins/ios-adapter.ts +1 -1
- package/src/runtime/plugins/lightweight-action.ts +208 -2
- package/src/runtime/plugins/local-system-adapter.ts +12 -2
- package/src/runtime/plugins/managed-process-adapter.ts +12 -5
- package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
- package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +602 -428
- package/src/runtime/plugins/types.ts +20 -0
- package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
- package/src/runtime/projections/invalidation.ts +7 -3
- package/src/runtime/projections/materialized-view.ts +80 -36
- package/src/runtime/recovery/actions.ts +3 -3
- package/src/runtime/recovery/capability-action-application.ts +46 -45
- package/src/runtime/recovery/lifecycle-inventory.ts +29 -29
- package/src/runtime/recovery/maintenance-executor.ts +374 -123
- package/src/runtime/recovery/store.ts +29 -11
- package/src/runtime/release/release-coordinator.ts +296 -0
- package/src/runtime/release/release-session.ts +716 -0
- package/src/runtime/release/release-state-migration.ts +25 -0
- package/src/runtime/resources/leases/store.ts +56 -25
- package/src/runtime/root/computer-composition.ts +191 -6
- package/src/runtime/root/controller-progression-composition.ts +192 -0
- package/src/runtime/root/controller-round-composition.ts +20 -1
- package/src/runtime/root/deployment-topology.ts +106 -0
- package/src/runtime/root/entry.ts +4 -3
- package/src/runtime/root/known-good-recovery.ts +184 -0
- package/src/runtime/root/local-bridge.ts +0 -1
- package/src/runtime/root/mcp-transport.ts +111 -18
- package/src/runtime/root/ownership.ts +261 -9
- package/src/runtime/root/package-connector-service.ts +105 -19
- package/src/runtime/root/package-runtime-release.ts +117 -18
- package/src/runtime/root/package-runtime-service.ts +17 -11
- package/src/runtime/root/release-execution-canary.ts +44 -12
- package/src/runtime/root/release-loader.ts +90 -8
- package/src/runtime/root/release-manifest.ts +80 -6
- package/src/runtime/root/release-materialize.ts +372 -28
- package/src/runtime/root/release-store.ts +395 -36
- package/src/runtime/root/runtime-lane.ts +191 -0
- package/src/runtime/root/runtime.ts +159 -27
- package/src/runtime/root/scheduled-controller-composition.ts +28 -3
- package/src/runtime/root/service-runner.ts +2 -2
- package/src/runtime/root/service.ts +36 -33
- package/src/runtime/root/status.ts +48 -0
- package/src/runtime/root/types.ts +32 -3
- package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
- package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
- package/src/runtime/root/write-fence.ts +50 -2
- package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
- package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
- package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
- package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
- package/src/runtime/shared/process-environment.ts +20 -9
- package/src/runtime/shared/response-budget.ts +1 -3
- package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
- package/src/runtime/standalone-recovery/core.ts +3702 -342
- package/src/runtime/standalone-recovery/entry.ts +469 -39
- package/src/runtime/standalone-recovery/installer.ts +262 -148
- package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
- package/src/runtime/standalone-recovery/operation-lock.ts +1 -1
- package/src/runtime/standalone-recovery/performance.ts +54 -16
- package/src/runtime/standalone-recovery/release.ts +53 -5
- package/src/runtime/standalone-recovery/service-labels.ts +5 -2
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
- package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +10 -3
- package/src/runtime/workflow/schedules/engine.ts +138 -172
- package/src/runtime/workflow/schedules/work-continuation.ts +44 -5
- package/src/runtime/workflows/runtime.ts +15 -19
- package/src/testing/test-governance.ts +5 -1
- package/supervisor/chatgpt-conversation.ts +23 -0
- package/supervisor/client.ts +201 -0
- package/supervisor/control-plane.ts +868 -0
- package/supervisor/entry.ts +15 -0
- package/supervisor/forge-validators.ts +80 -0
- package/supervisor/index.ts +5 -0
- package/supervisor/native-browser-adapter.ts +786 -0
- package/supervisor/native-messaging/host.ts +39 -0
- package/supervisor/native-messaging/manifest.ts +26 -0
- package/supervisor/native-messaging/protocol.ts +27 -0
- package/supervisor/paths.ts +18 -0
- package/supervisor/protocol.ts +202 -0
- package/supervisor/server.ts +404 -0
- package/supervisor/store.ts +1451 -0
- package/supervisor/tsconfig.json +8 -0
- package/supervisor/types.ts +255 -0
- package/adapters/chatgpt/controller-host.ts +0 -119
- package/adapters/mcp/controller-round-compatibility.ts +0 -184
- package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
- package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
- package/packages/kernel/progression/api/index.ts +0 -2
- package/packages/kernel/progression/application/projector.ts +0 -211
- package/packages/kernel/progression/domain/types.ts +0 -116
- package/packages/kernel/progression/index.ts +0 -1
- package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
- package/packages/kernel/scheduler/domain/continuation.ts +0 -38
- package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
- package/packages/kernel/work/domain/admission-policy.ts +0 -34
- package/scripts/benchmark-background-check-overlap.ts +0 -228
- package/scripts/benchmark-computer-hotpath.ts +0 -255
- package/scripts/benchmark-controller-hotpath.ts +0 -212
- package/scripts/benchmark-controller-round2.ts +0 -191
- package/scripts/benchmark-ios-agent-device.ts +0 -511
- package/scripts/benchmark-mcp-host.sh +0 -117
- package/scripts/benchmark-mcp-transport.ts +0 -169
- package/scripts/benchmark-operational-memory-activation.ts +0 -235
- package/scripts/benchmark-operational-shadow.ts +0 -28
- package/scripts/benchmark-quality-harness.ts +0 -146
- package/scripts/benchmark-route-session-concurrency.ts +0 -915
- package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
- package/scripts/benchmark-thin-harness.ts +0 -251
- package/scripts/benchmark-typescript-navigation.ts +0 -186
- package/scripts/benchmark-work-efficiency.ts +0 -334
- package/scripts/build-controller-ui.ts +0 -28
- package/scripts/check-npm-release.sh +0 -32
- package/scripts/check-public-release-surface.sh +0 -19
- package/scripts/check-release-published.sh +0 -57
- package/scripts/check-release-readiness.sh +0 -37
- package/scripts/check-release-version.mjs +0 -74
- package/scripts/check-tarball-install-smoke.sh +0 -150
- package/scripts/package-source-archive.sh +0 -147
- package/scripts/public-release-files.txt +0 -39
- package/scripts/public-release.ts +0 -174
- package/scripts/publish-release-tarball.sh +0 -27
- package/scripts/route-nl-vs-ts-eval.ts +0 -679
- package/scripts/stage-runtime-release.ts +0 -44
- package/src/cli/controller/progress.ts +0 -656
- package/src/cli/controller/work-mode.ts +0 -181
- package/src/cli/local-bridge/console-assets.ts +0 -17
- package/src/cli/local-bridge/dashboard.ts +0 -17
- package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
- package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
- package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
- package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
- package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/styles.css +0 -28
- package/src/cli/local-bridge/frontend/src/types.ts +0 -15
- package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
- package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
- package/src/cli/local-bridge/ui-dist/app.css +0 -1
- package/src/cli/local-bridge/ui-dist/app.js +0 -11228
- package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
- package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
- package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
- package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
- package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
- package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
- package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
- package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
- package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
- package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
- package/src/runtime/control-plane/routing/index.ts +0 -1
- package/src/runtime/control-plane/routing/route-policy.ts +0 -401
- package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
|
@@ -19,8 +19,7 @@ import {
|
|
|
19
19
|
releaseControllerCheckSubscription,
|
|
20
20
|
runControllerCheckAsync,
|
|
21
21
|
} from '../../../cli/controller/check-runner';
|
|
22
|
-
import {
|
|
23
|
-
import type { RepositoryRecord } from '../../../cli/repositories/types';
|
|
22
|
+
import { commandExecutionScopeKey, type RepositoryCommandScopeTarget } from '../../../cli/repositories/command-scope';
|
|
24
23
|
import { readJsonFile, sanitizeFileComponent, writeJsonAtomic } from '../../shared/json-files';
|
|
25
24
|
import {
|
|
26
25
|
defaultProcessIdentityProbe,
|
|
@@ -30,6 +29,17 @@ import {
|
|
|
30
29
|
} from '../../shared/process-identity';
|
|
31
30
|
import { terminateProcessTree } from '../../shared/process-tree';
|
|
32
31
|
import { runBoundedProcess } from '../thin-harness/async-process';
|
|
32
|
+
import { recordProcessHandleIndexEntry } from './handle-index';
|
|
33
|
+
import {
|
|
34
|
+
FORGE_INSTANCE_PROCESS_SCOPE_KEY,
|
|
35
|
+
isWorkspaceProcessScopeKey,
|
|
36
|
+
legacyWorkspaceScopeRoot,
|
|
37
|
+
normalizeProcessScopeKey,
|
|
38
|
+
processScopeExecutionTarget,
|
|
39
|
+
processScopeFromKey,
|
|
40
|
+
processScopeKey,
|
|
41
|
+
processScopeRoot,
|
|
42
|
+
} from './process-scope';
|
|
33
43
|
import { PROCESS_LOG_TAIL_BYTES, type ProcessHandle, type ProcessLogSlice, type WaitProcessOptions } from './types';
|
|
34
44
|
|
|
35
45
|
const EMPTY_EFFECTS = {
|
|
@@ -66,7 +76,12 @@ interface LightweightExitObservation {
|
|
|
66
76
|
interface LightweightEntry {
|
|
67
77
|
processId: string;
|
|
68
78
|
controllerHome: string;
|
|
69
|
-
|
|
79
|
+
/** Canonical Process scope partition key (`repo_*` repository id, or the ForgeInstance scope key). */
|
|
80
|
+
scopeKey: string;
|
|
81
|
+
/** Repository placement when this handle targets a repository; absent for ForgeInstance targets. */
|
|
82
|
+
repoId?: string;
|
|
83
|
+
/** Owning principal recorded from the invoking MCP/Runtime context. */
|
|
84
|
+
principalId?: string;
|
|
70
85
|
workId?: string;
|
|
71
86
|
commandId: string;
|
|
72
87
|
requestFingerprint: string;
|
|
@@ -101,7 +116,9 @@ export function hasActiveLightweightProcesses(controllerHome: string): boolean {
|
|
|
101
116
|
|
|
102
117
|
interface LightweightRunningReceipt {
|
|
103
118
|
schemaVersion: 1;
|
|
104
|
-
repoId
|
|
119
|
+
/** Canonical scope partition key. Legacy receipts carry only `repoId`. */
|
|
120
|
+
scopeKey?: string;
|
|
121
|
+
repoId?: string;
|
|
105
122
|
processId: string;
|
|
106
123
|
commandId?: string;
|
|
107
124
|
requestFingerprint?: string;
|
|
@@ -113,7 +130,9 @@ interface LightweightRunningReceipt {
|
|
|
113
130
|
|
|
114
131
|
interface LightweightTerminalReceipt {
|
|
115
132
|
schemaVersion: 1;
|
|
116
|
-
repoId
|
|
133
|
+
/** Canonical scope partition key. Legacy receipts carry only `repoId`. */
|
|
134
|
+
scopeKey?: string;
|
|
135
|
+
repoId?: string;
|
|
117
136
|
processId: string;
|
|
118
137
|
commandId?: string;
|
|
119
138
|
requestFingerprint?: string;
|
|
@@ -121,20 +140,44 @@ interface LightweightTerminalReceipt {
|
|
|
121
140
|
handle: ProcessHandle;
|
|
122
141
|
}
|
|
123
142
|
|
|
124
|
-
function runningReceiptRoot(controllerHome: string,
|
|
125
|
-
return join(
|
|
143
|
+
function runningReceiptRoot(controllerHome: string, scopeKey: string): string {
|
|
144
|
+
return join(processScopeRoot(controllerHome, scopeKey), 'process-runtime', 'lightweight-running');
|
|
126
145
|
}
|
|
127
146
|
|
|
128
|
-
function runningReceiptPath(controllerHome: string,
|
|
129
|
-
return join(runningReceiptRoot(controllerHome,
|
|
147
|
+
function runningReceiptPath(controllerHome: string, scopeKey: string, processId: string): string {
|
|
148
|
+
return join(runningReceiptRoot(controllerHome, scopeKey), `${sanitizeFileComponent(processId)}.json`);
|
|
130
149
|
}
|
|
131
150
|
|
|
132
|
-
function terminalReceiptRoot(controllerHome: string,
|
|
133
|
-
return join(
|
|
151
|
+
function terminalReceiptRoot(controllerHome: string, scopeKey: string): string {
|
|
152
|
+
return join(processScopeRoot(controllerHome, scopeKey), 'process-runtime', 'lightweight-terminal');
|
|
134
153
|
}
|
|
135
154
|
|
|
136
|
-
function terminalReceiptPath(controllerHome: string,
|
|
137
|
-
return join(terminalReceiptRoot(controllerHome,
|
|
155
|
+
function terminalReceiptPath(controllerHome: string, scopeKey: string, processId: string): string {
|
|
156
|
+
return join(terminalReceiptRoot(controllerHome, scopeKey), `${sanitizeFileComponent(processId)}.json`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Bounded migration read: a workspace-scoped receipt written before the
|
|
161
|
+
* workspace partition existed still resolves, instead of reporting a running
|
|
162
|
+
* command as missing. Repository scopes never take this path.
|
|
163
|
+
*/
|
|
164
|
+
function existingReceiptPath(
|
|
165
|
+
controllerHome: string,
|
|
166
|
+
scopeKey: string,
|
|
167
|
+
processId: string,
|
|
168
|
+
build: (controllerHome: string, scopeKey: string, processId: string) => string,
|
|
169
|
+
): string {
|
|
170
|
+
const current = build(controllerHome, scopeKey, processId);
|
|
171
|
+
if (existsSync(current) || !isWorkspaceProcessScopeKey(scopeKey)) return current;
|
|
172
|
+
const legacyRoot = legacyWorkspaceScopeRoot(controllerHome, scopeKey);
|
|
173
|
+
if (!legacyRoot) return current;
|
|
174
|
+
const legacy = join(
|
|
175
|
+
legacyRoot,
|
|
176
|
+
'process-runtime',
|
|
177
|
+
build === runningReceiptPath ? 'lightweight-running' : 'lightweight-terminal',
|
|
178
|
+
`${sanitizeFileComponent(processId)}.json`,
|
|
179
|
+
);
|
|
180
|
+
return existsSync(legacy) ? legacy : current;
|
|
138
181
|
}
|
|
139
182
|
|
|
140
183
|
function boundedAppend(current: string, chunk: string, maxBytes: number): string {
|
|
@@ -169,8 +212,8 @@ function captureProcessIdentity(pid: number): ExpectedProcessIdentity | undefine
|
|
|
169
212
|
return { pid, processStartTime, executableFingerprint: executableFingerprint(command) };
|
|
170
213
|
}
|
|
171
214
|
|
|
172
|
-
function removeRunningReceipt(controllerHome: string,
|
|
173
|
-
try { rmSync(runningReceiptPath(controllerHome,
|
|
215
|
+
function removeRunningReceipt(controllerHome: string, scopeKey: string, processId: string): void {
|
|
216
|
+
try { rmSync(runningReceiptPath(controllerHome, scopeKey, processId), { force: true }); } catch { /* best effort */ }
|
|
174
217
|
}
|
|
175
218
|
|
|
176
219
|
function persistRunningReceipt(entry: LightweightEntry, force = false): void {
|
|
@@ -182,12 +225,13 @@ function persistRunningReceipt(entry: LightweightEntry, force = false): void {
|
|
|
182
225
|
if (!force && entry.runningReceiptUpdatedAtMs !== undefined
|
|
183
226
|
&& now - entry.runningReceiptUpdatedAtMs < RUNNING_RECEIPT_PERSIST_INTERVAL_MS) return;
|
|
184
227
|
try {
|
|
185
|
-
const root = runningReceiptRoot(entry.controllerHome, entry.
|
|
228
|
+
const root = runningReceiptRoot(entry.controllerHome, entry.scopeKey);
|
|
186
229
|
mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
187
|
-
const path = runningReceiptPath(entry.controllerHome, entry.
|
|
230
|
+
const path = runningReceiptPath(entry.controllerHome, entry.scopeKey, entry.processId);
|
|
188
231
|
const receipt: LightweightRunningReceipt = {
|
|
189
232
|
schemaVersion: 1,
|
|
190
|
-
|
|
233
|
+
scopeKey: entry.scopeKey,
|
|
234
|
+
...(entry.repoId ? { repoId: entry.repoId } : {}),
|
|
191
235
|
processId: entry.processId,
|
|
192
236
|
commandId: entry.commandId,
|
|
193
237
|
requestFingerprint: entry.requestFingerprint,
|
|
@@ -204,12 +248,12 @@ function persistRunningReceipt(entry: LightweightEntry, force = false): void {
|
|
|
204
248
|
}
|
|
205
249
|
}
|
|
206
250
|
|
|
207
|
-
function readRunningReceipt(controllerHome: string,
|
|
208
|
-
const path =
|
|
251
|
+
function readRunningReceipt(controllerHome: string, scopeKey: string, processId: string): LightweightRunningReceipt | undefined {
|
|
252
|
+
const path = existingReceiptPath(controllerHome, scopeKey, processId, runningReceiptPath);
|
|
209
253
|
if (!existsSync(path)) return undefined;
|
|
210
254
|
try {
|
|
211
255
|
const receipt = readJsonFile<LightweightRunningReceipt>(path);
|
|
212
|
-
if (receipt.schemaVersion !== 1 || receipt.repoId !==
|
|
256
|
+
if (receipt.schemaVersion !== 1 || (receipt.scopeKey ?? receipt.repoId) !== scopeKey || receipt.processId !== processId) return undefined;
|
|
213
257
|
if (receipt.handle?.processId !== processId || receipt.handle.completed) return undefined;
|
|
214
258
|
return receipt;
|
|
215
259
|
} catch {
|
|
@@ -261,18 +305,19 @@ function pruneTerminalReceipts(root: string, keepPath: string): void {
|
|
|
261
305
|
|
|
262
306
|
function persistTerminalReceipt(controllerHome: string, entry: LightweightEntry): void {
|
|
263
307
|
if (!entry.result || !entry.finishedAtMs) return;
|
|
264
|
-
const existing = readTerminalReceipt(controllerHome, entry.
|
|
308
|
+
const existing = readTerminalReceipt(controllerHome, entry.scopeKey, entry.processId);
|
|
265
309
|
if (existing) {
|
|
266
|
-
removeRunningReceipt(controllerHome, entry.
|
|
310
|
+
removeRunningReceipt(controllerHome, entry.scopeKey, entry.processId);
|
|
267
311
|
return;
|
|
268
312
|
}
|
|
269
313
|
try {
|
|
270
|
-
const root = terminalReceiptRoot(controllerHome, entry.
|
|
314
|
+
const root = terminalReceiptRoot(controllerHome, entry.scopeKey);
|
|
271
315
|
mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
272
|
-
const path = terminalReceiptPath(controllerHome, entry.
|
|
316
|
+
const path = terminalReceiptPath(controllerHome, entry.scopeKey, entry.processId);
|
|
273
317
|
const receipt: LightweightTerminalReceipt = {
|
|
274
318
|
schemaVersion: 1,
|
|
275
|
-
|
|
319
|
+
scopeKey: entry.scopeKey,
|
|
320
|
+
...(entry.repoId ? { repoId: entry.repoId } : {}),
|
|
276
321
|
processId: entry.processId,
|
|
277
322
|
commandId: entry.commandId,
|
|
278
323
|
requestFingerprint: entry.requestFingerprint,
|
|
@@ -281,19 +326,19 @@ function persistTerminalReceipt(controllerHome: string, entry: LightweightEntry)
|
|
|
281
326
|
};
|
|
282
327
|
writeJsonAtomic(path, receipt);
|
|
283
328
|
try { chmodSync(path, 0o600); } catch { /* Windows or restricted filesystem. */ }
|
|
284
|
-
removeRunningReceipt(controllerHome, entry.
|
|
329
|
+
removeRunningReceipt(controllerHome, entry.scopeKey, entry.processId);
|
|
285
330
|
pruneTerminalReceipts(root, path);
|
|
286
331
|
} catch {
|
|
287
332
|
// A receipt failure must never turn a completed local command into a failure.
|
|
288
333
|
}
|
|
289
334
|
}
|
|
290
335
|
|
|
291
|
-
function readTerminalReceipt(controllerHome: string,
|
|
292
|
-
const path =
|
|
336
|
+
function readTerminalReceipt(controllerHome: string, scopeKey: string, processId: string): LightweightTerminalReceipt | undefined {
|
|
337
|
+
const path = existingReceiptPath(controllerHome, scopeKey, processId, terminalReceiptPath);
|
|
293
338
|
if (!existsSync(path)) return undefined;
|
|
294
339
|
try {
|
|
295
340
|
const receipt = readJsonFile<LightweightTerminalReceipt>(path);
|
|
296
|
-
if (receipt.schemaVersion !== 1 || receipt.repoId !==
|
|
341
|
+
if (receipt.schemaVersion !== 1 || (receipt.scopeKey ?? receipt.repoId) !== scopeKey || receipt.processId !== processId) return undefined;
|
|
297
342
|
if (!receipt.handle?.completed || receipt.handle.processId !== processId) return undefined;
|
|
298
343
|
const finishedAtMs = Date.parse(receipt.finishedAt);
|
|
299
344
|
if (!Number.isFinite(finishedAtMs) || Date.now() - finishedAtMs > TERMINAL_RECEIPT_RETENTION_MS) {
|
|
@@ -323,24 +368,24 @@ function recoveredRequestMetrics(): LightweightCommandMetrics {
|
|
|
323
368
|
*/
|
|
324
369
|
function findPersistedHandleForCommand(
|
|
325
370
|
controllerHome: string,
|
|
326
|
-
|
|
371
|
+
scopeKey: string,
|
|
327
372
|
commandId: string,
|
|
328
373
|
requestFingerprint: string,
|
|
329
374
|
): ProcessHandle | undefined {
|
|
330
|
-
const roots = [terminalReceiptRoot(controllerHome,
|
|
375
|
+
const roots = [terminalReceiptRoot(controllerHome, scopeKey), runningReceiptRoot(controllerHome, scopeKey)];
|
|
331
376
|
for (const root of roots) {
|
|
332
377
|
if (!existsSync(root)) continue;
|
|
333
378
|
for (const file of readdirSync(root)) {
|
|
334
379
|
if (!file.endsWith('.json')) continue;
|
|
335
380
|
try {
|
|
336
381
|
const receipt = readJsonFile<LightweightRunningReceipt | LightweightTerminalReceipt>(join(root, file));
|
|
337
|
-
if (receipt.schemaVersion !== 1 || receipt.repoId !==
|
|
382
|
+
if (receipt.schemaVersion !== 1 || (receipt.scopeKey ?? receipt.repoId) !== scopeKey || !receipt.processId) continue;
|
|
338
383
|
const persistedCommandId = receipt.commandId ?? receipt.handle?.commandId;
|
|
339
384
|
if (persistedCommandId !== commandId) continue;
|
|
340
385
|
if (!receipt.requestFingerprint || receipt.requestFingerprint !== requestFingerprint) {
|
|
341
386
|
throw new Error(`PROCESS_REQUEST_CONFLICT: command id ${commandId} cannot be safely replayed after Runtime restart`);
|
|
342
387
|
}
|
|
343
|
-
return getLightweightProcessHandle(controllerHome,
|
|
388
|
+
return getLightweightProcessHandle(controllerHome, scopeKey, receipt.processId);
|
|
344
389
|
} catch (error) {
|
|
345
390
|
if (error instanceof Error && error.message.startsWith('PROCESS_REQUEST_CONFLICT:')) throw error;
|
|
346
391
|
// A corrupt or concurrently pruned receipt is not an execution result.
|
|
@@ -399,18 +444,21 @@ function persistRecoveredTerminalReceipt(
|
|
|
399
444
|
receipt: LightweightRunningReceipt,
|
|
400
445
|
handle: ProcessHandle,
|
|
401
446
|
): ProcessHandle {
|
|
402
|
-
const
|
|
447
|
+
const scopeKey = receipt.scopeKey ?? receipt.repoId;
|
|
448
|
+
if (!scopeKey) return handle;
|
|
449
|
+
const existing = readTerminalReceipt(controllerHome, scopeKey, receipt.processId);
|
|
403
450
|
if (existing) {
|
|
404
|
-
removeRunningReceipt(controllerHome,
|
|
451
|
+
removeRunningReceipt(controllerHome, scopeKey, receipt.processId);
|
|
405
452
|
return existing.handle;
|
|
406
453
|
}
|
|
407
454
|
try {
|
|
408
|
-
const root = terminalReceiptRoot(controllerHome,
|
|
455
|
+
const root = terminalReceiptRoot(controllerHome, scopeKey);
|
|
409
456
|
mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
410
|
-
const path = terminalReceiptPath(controllerHome,
|
|
457
|
+
const path = terminalReceiptPath(controllerHome, scopeKey, receipt.processId);
|
|
411
458
|
const terminal: LightweightTerminalReceipt = {
|
|
412
459
|
schemaVersion: 1,
|
|
413
|
-
|
|
460
|
+
scopeKey,
|
|
461
|
+
...(receipt.repoId ? { repoId: receipt.repoId } : {}),
|
|
414
462
|
processId: receipt.processId,
|
|
415
463
|
commandId: receipt.commandId,
|
|
416
464
|
requestFingerprint: receipt.requestFingerprint,
|
|
@@ -419,7 +467,7 @@ function persistRecoveredTerminalReceipt(
|
|
|
419
467
|
};
|
|
420
468
|
writeJsonAtomic(path, terminal);
|
|
421
469
|
try { chmodSync(path, 0o600); } catch { /* Windows or restricted filesystem. */ }
|
|
422
|
-
removeRunningReceipt(controllerHome,
|
|
470
|
+
removeRunningReceipt(controllerHome, scopeKey, receipt.processId);
|
|
423
471
|
pruneTerminalReceipts(root, path);
|
|
424
472
|
} catch {
|
|
425
473
|
// Recovery evidence persistence must not trigger command re-execution or unsafe signalling.
|
|
@@ -555,13 +603,16 @@ function entryHandle(entry: LightweightEntry): ProcessHandle {
|
|
|
555
603
|
|
|
556
604
|
export interface StartLightweightCommandInput {
|
|
557
605
|
controllerHome: string;
|
|
558
|
-
|
|
606
|
+
/** Repository identity is optional: an arbitrary workspace target carries a workspace scope key. */
|
|
607
|
+
repository: RepositoryCommandScopeTarget;
|
|
559
608
|
execution: ExecuteRepositoryCommandInput;
|
|
560
609
|
interactiveWaitMs: number;
|
|
561
610
|
timeoutMs: number;
|
|
562
611
|
maxOutputBytes?: number;
|
|
563
612
|
workId?: string;
|
|
564
613
|
commandId?: string;
|
|
614
|
+
/** Authenticated principal recorded with the handle for principal-bound attachment. */
|
|
615
|
+
principalId?: string;
|
|
565
616
|
/** Start repository preparation on the next event-loop turn so the caller can receive a handle first. */
|
|
566
617
|
deferStart?: boolean;
|
|
567
618
|
/** Reuse an equivalent active local build/test even when a later caller has a different request id. */
|
|
@@ -588,10 +639,15 @@ export interface StartLightweightCheckInput {
|
|
|
588
639
|
timeoutMs: number;
|
|
589
640
|
workId?: string;
|
|
590
641
|
commandId?: string;
|
|
642
|
+
/** Authenticated principal recorded with the handle for principal-bound attachment. */
|
|
643
|
+
principalId?: string;
|
|
591
644
|
}
|
|
592
645
|
|
|
593
646
|
export interface StartLightweightInternalProcessInput {
|
|
594
|
-
repoId
|
|
647
|
+
/** Canonical Process scope key. Defaults to `repoId` for repository-scoped internal processes. */
|
|
648
|
+
scopeKey?: string;
|
|
649
|
+
/** Repository placement when this process targets a repository; absent for ForgeInstance targets. */
|
|
650
|
+
repoId?: string;
|
|
595
651
|
executable: string;
|
|
596
652
|
args: readonly string[];
|
|
597
653
|
cwd: string;
|
|
@@ -603,15 +659,21 @@ export interface StartLightweightInternalProcessInput {
|
|
|
603
659
|
workId?: string;
|
|
604
660
|
commandId?: string;
|
|
605
661
|
signal?: AbortSignal;
|
|
662
|
+
/** Authenticated principal recorded with the handle for principal-bound attachment. */
|
|
663
|
+
principalId?: string;
|
|
606
664
|
}
|
|
607
665
|
|
|
608
666
|
export async function startLightweightRepositoryCommand(
|
|
609
667
|
input: StartLightweightCommandInput,
|
|
610
668
|
): Promise<{ handle: ProcessHandle; metrics: LightweightCommandMetrics }> {
|
|
611
669
|
sweep();
|
|
670
|
+
// Repository targets keep their repository partition; an arbitrary workspace
|
|
671
|
+
// target is scoped by its workspace id instead of a synthetic repository id.
|
|
672
|
+
const scope = processScopeFromKey(commandExecutionScopeKey(input.repository));
|
|
673
|
+
const scopeKey = processScopeKey(scope);
|
|
612
674
|
const stableCommandId = input.commandId?.trim();
|
|
613
675
|
const requestFingerprint = JSON.stringify({
|
|
614
|
-
repoId: input.repository
|
|
676
|
+
repoId: commandExecutionScopeKey(input.repository),
|
|
615
677
|
command: input.execution.command,
|
|
616
678
|
cwd: input.execution.cwd ?? '.',
|
|
617
679
|
timeoutMs: input.timeoutMs,
|
|
@@ -620,7 +682,7 @@ export async function startLightweightRepositoryCommand(
|
|
|
620
682
|
if (stableCommandId) {
|
|
621
683
|
const existing = [...entries.values()].find((entry) => (
|
|
622
684
|
entry.controllerHome === input.controllerHome
|
|
623
|
-
&& entry.
|
|
685
|
+
&& entry.scopeKey === scopeKey
|
|
624
686
|
&& entry.commandId === stableCommandId
|
|
625
687
|
));
|
|
626
688
|
if (existing) {
|
|
@@ -643,7 +705,7 @@ export async function startLightweightRepositoryCommand(
|
|
|
643
705
|
}
|
|
644
706
|
const recovered = findPersistedHandleForCommand(
|
|
645
707
|
input.controllerHome,
|
|
646
|
-
|
|
708
|
+
scopeKey,
|
|
647
709
|
stableCommandId,
|
|
648
710
|
requestFingerprint,
|
|
649
711
|
);
|
|
@@ -651,7 +713,7 @@ export async function startLightweightRepositoryCommand(
|
|
|
651
713
|
}
|
|
652
714
|
if (input.reuseActiveEquivalent) {
|
|
653
715
|
const existing = [...entries.values()].find((entry) => (
|
|
654
|
-
entry.
|
|
716
|
+
entry.scopeKey === scopeKey
|
|
655
717
|
&& entry.requestFingerprint === requestFingerprint
|
|
656
718
|
&& entry.result === undefined
|
|
657
719
|
));
|
|
@@ -675,7 +737,9 @@ export async function startLightweightRepositoryCommand(
|
|
|
675
737
|
const entry: LightweightEntry = {
|
|
676
738
|
processId,
|
|
677
739
|
controllerHome: input.controllerHome,
|
|
678
|
-
|
|
740
|
+
scopeKey,
|
|
741
|
+
...(scope.kind === 'repository' ? { repoId: commandExecutionScopeKey(input.repository) } : {}),
|
|
742
|
+
...(input.principalId ? { principalId: input.principalId } : {}),
|
|
679
743
|
workId: input.workId,
|
|
680
744
|
commandId: stableCommandId || processId,
|
|
681
745
|
requestFingerprint,
|
|
@@ -780,6 +844,16 @@ export async function startLightweightRepositoryCommand(
|
|
|
780
844
|
})
|
|
781
845
|
: startExecution();
|
|
782
846
|
entries.set(processId, entry);
|
|
847
|
+
// Instance-level locator: a lightweight handle must be attachable from the
|
|
848
|
+
// returned processId alone, including after Runtime memory loss.
|
|
849
|
+
recordProcessHandleIndexEntry(input.controllerHome, {
|
|
850
|
+
processId,
|
|
851
|
+
lane: 'lightweight',
|
|
852
|
+
target: processScopeExecutionTarget(input.controllerHome, processScopeFromKey(entry.scopeKey)),
|
|
853
|
+
principalId: entry.principalId,
|
|
854
|
+
workId: entry.workId,
|
|
855
|
+
commandId: entry.commandId,
|
|
856
|
+
});
|
|
783
857
|
persistRunningReceipt(entry, true);
|
|
784
858
|
|
|
785
859
|
if (entry.interactiveWaitMs > 0) {
|
|
@@ -811,18 +885,31 @@ export async function startLightweightInternalProcess(
|
|
|
811
885
|
input: StartLightweightInternalProcessInput,
|
|
812
886
|
): Promise<{ handle: ProcessHandle; metrics: LightweightCommandMetrics }> {
|
|
813
887
|
sweep();
|
|
888
|
+
const repoId = input.repoId?.trim() || undefined;
|
|
889
|
+
const scopeKey = normalizeProcessScopeKey(input.scopeKey?.trim() || repoId || '');
|
|
890
|
+
const scope = processScopeFromKey(scopeKey);
|
|
814
891
|
const stableCommandId = input.commandId?.trim();
|
|
892
|
+
// Retry identity is commandId + fingerprint(scope target, action, principal).
|
|
893
|
+
// An instance-scope request id is never a naked global namespace: a different
|
|
894
|
+
// principal presenting the same request id fails closed as a request conflict
|
|
895
|
+
// instead of attaching to another principal's process.
|
|
896
|
+
const principalId = input.principalId?.trim() || null;
|
|
815
897
|
const requestFingerprint = JSON.stringify({
|
|
816
|
-
|
|
898
|
+
scopeKey,
|
|
899
|
+
repoId: repoId ?? null,
|
|
817
900
|
executable: input.executable,
|
|
818
901
|
args: input.args,
|
|
819
902
|
cwd: input.cwd,
|
|
820
903
|
timeoutMs: input.timeoutMs,
|
|
904
|
+
// Only a principal-bound lane (the ForgeInstance host command lane) adds the
|
|
905
|
+
// principal to retry identity, so existing repository/plugin fingerprints
|
|
906
|
+
// keep their historical value instead of failing closed after an upgrade.
|
|
907
|
+
...(principalId ? { principalId } : {}),
|
|
821
908
|
});
|
|
822
909
|
if (stableCommandId) {
|
|
823
910
|
const existing = [...entries.values()].find((entry) => (
|
|
824
911
|
entry.controllerHome === input.controllerHome
|
|
825
|
-
&& entry.
|
|
912
|
+
&& entry.scopeKey === scopeKey
|
|
826
913
|
&& entry.commandId === stableCommandId
|
|
827
914
|
));
|
|
828
915
|
if (existing) {
|
|
@@ -845,7 +932,7 @@ export async function startLightweightInternalProcess(
|
|
|
845
932
|
}
|
|
846
933
|
const recovered = findPersistedHandleForCommand(
|
|
847
934
|
input.controllerHome,
|
|
848
|
-
|
|
935
|
+
scopeKey,
|
|
849
936
|
stableCommandId,
|
|
850
937
|
requestFingerprint,
|
|
851
938
|
);
|
|
@@ -858,7 +945,9 @@ export async function startLightweightInternalProcess(
|
|
|
858
945
|
const entry: LightweightEntry = {
|
|
859
946
|
processId,
|
|
860
947
|
controllerHome: input.controllerHome,
|
|
861
|
-
|
|
948
|
+
scopeKey,
|
|
949
|
+
...(repoId ? { repoId } : {}),
|
|
950
|
+
...(input.principalId?.trim() ? { principalId: input.principalId.trim() } : {}),
|
|
862
951
|
workId: input.workId,
|
|
863
952
|
commandId: stableCommandId || processId,
|
|
864
953
|
requestFingerprint,
|
|
@@ -906,6 +995,14 @@ export async function startLightweightInternalProcess(
|
|
|
906
995
|
return result;
|
|
907
996
|
});
|
|
908
997
|
entries.set(processId, entry);
|
|
998
|
+
recordProcessHandleIndexEntry(entry.controllerHome, {
|
|
999
|
+
processId,
|
|
1000
|
+
lane: 'lightweight',
|
|
1001
|
+
target: processScopeExecutionTarget(entry.controllerHome, processScopeFromKey(entry.scopeKey)),
|
|
1002
|
+
principalId: entry.principalId,
|
|
1003
|
+
workId: entry.workId,
|
|
1004
|
+
commandId: entry.commandId,
|
|
1005
|
+
});
|
|
909
1006
|
persistRunningReceipt(entry, true);
|
|
910
1007
|
|
|
911
1008
|
if (entry.interactiveWaitMs > 0) {
|
|
@@ -933,6 +1030,68 @@ export async function startLightweightInternalProcess(
|
|
|
933
1030
|
};
|
|
934
1031
|
}
|
|
935
1032
|
|
|
1033
|
+
export interface StartLightweightHostCommandInput {
|
|
1034
|
+
controllerHome: string;
|
|
1035
|
+
/** Typed argv command; `command[0]` is the executable. */
|
|
1036
|
+
command?: readonly string[];
|
|
1037
|
+
/** Explicit broad host-shell form. Authorized by the same host process grant as argv. */
|
|
1038
|
+
shellCommand?: string;
|
|
1039
|
+
cwd: string;
|
|
1040
|
+
env?: NodeJS.ProcessEnv;
|
|
1041
|
+
interactiveWaitMs: number;
|
|
1042
|
+
timeoutMs: number;
|
|
1043
|
+
maxOutputBytes?: number;
|
|
1044
|
+
workId?: string;
|
|
1045
|
+
commandId?: string;
|
|
1046
|
+
signal?: AbortSignal;
|
|
1047
|
+
principalId?: string;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/** Platform shell used for the explicit `shell_command` form. Mirrors the Process Runner convention. */
|
|
1051
|
+
export function hostShellInvocation(shellCommand: string): readonly string[] {
|
|
1052
|
+
const command = shellCommand.trim();
|
|
1053
|
+
if (!command) throw new Error('HOST_COMMAND_SHELL_STRING_REQUIRED');
|
|
1054
|
+
return process.platform === 'win32'
|
|
1055
|
+
? ['cmd.exe', '/c', command]
|
|
1056
|
+
: ['/bin/bash', '-lc', command];
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
function hostCommandArgv(input: StartLightweightHostCommandInput): readonly string[] {
|
|
1060
|
+
const shellCommand = input.shellCommand?.trim();
|
|
1061
|
+
if (shellCommand) return hostShellInvocation(shellCommand);
|
|
1062
|
+
const argv = (input.command ?? []).map((entry) => String(entry));
|
|
1063
|
+
if (argv.length === 0 || !argv[0]) throw new Error('HOST_COMMAND_ARGV_REQUIRED');
|
|
1064
|
+
return argv;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* Mode-free host-local command lane. The target is the ForgeInstance, `cwd` is
|
|
1069
|
+
* an execution argument, and no repository registration or checkout identity is
|
|
1070
|
+
* required. Authorization is the caller's responsibility: this lane performs no
|
|
1071
|
+
* command parsing and never becomes a path sandbox.
|
|
1072
|
+
*/
|
|
1073
|
+
export async function startLightweightHostCommand(
|
|
1074
|
+
input: StartLightweightHostCommandInput,
|
|
1075
|
+
): Promise<{ handle: ProcessHandle; metrics: LightweightCommandMetrics }> {
|
|
1076
|
+
const argv = hostCommandArgv(input);
|
|
1077
|
+
const executable = argv[0]!;
|
|
1078
|
+
return startLightweightInternalProcess({
|
|
1079
|
+
controllerHome: input.controllerHome,
|
|
1080
|
+
scopeKey: FORGE_INSTANCE_PROCESS_SCOPE_KEY,
|
|
1081
|
+
executable,
|
|
1082
|
+
args: argv.slice(1),
|
|
1083
|
+
cwd: input.cwd,
|
|
1084
|
+
env: input.env,
|
|
1085
|
+
interactiveWaitMs: input.interactiveWaitMs,
|
|
1086
|
+
timeoutMs: input.timeoutMs,
|
|
1087
|
+
maxOutputBytes: input.maxOutputBytes,
|
|
1088
|
+
workId: input.workId,
|
|
1089
|
+
commandId: input.commandId,
|
|
1090
|
+
signal: input.signal,
|
|
1091
|
+
principalId: input.principalId,
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
|
|
936
1095
|
export async function startLightweightControllerCheck(
|
|
937
1096
|
input: StartLightweightCheckInput,
|
|
938
1097
|
): Promise<{ handle: ProcessHandle; metrics: LightweightCommandMetrics }> {
|
|
@@ -947,7 +1106,7 @@ export async function startLightweightControllerCheck(
|
|
|
947
1106
|
if (stableCommandId) {
|
|
948
1107
|
const existing = [...entries.values()].find((entry) => (
|
|
949
1108
|
entry.controllerHome === input.controllerHome
|
|
950
|
-
&& entry.
|
|
1109
|
+
&& entry.scopeKey === input.repoId
|
|
951
1110
|
&& entry.commandId === stableCommandId
|
|
952
1111
|
));
|
|
953
1112
|
if (existing) {
|
|
@@ -982,7 +1141,9 @@ export async function startLightweightControllerCheck(
|
|
|
982
1141
|
const entry: LightweightEntry = {
|
|
983
1142
|
processId,
|
|
984
1143
|
controllerHome: input.controllerHome,
|
|
1144
|
+
scopeKey: input.repoId,
|
|
985
1145
|
repoId: input.repoId,
|
|
1146
|
+
...(input.principalId ? { principalId: input.principalId } : {}),
|
|
986
1147
|
workId: input.workId,
|
|
987
1148
|
commandId: stableCommandId || processId,
|
|
988
1149
|
requestFingerprint,
|
|
@@ -1031,6 +1192,14 @@ export async function startLightweightControllerCheck(
|
|
|
1031
1192
|
return result;
|
|
1032
1193
|
});
|
|
1033
1194
|
entries.set(processId, entry);
|
|
1195
|
+
recordProcessHandleIndexEntry(entry.controllerHome, {
|
|
1196
|
+
processId,
|
|
1197
|
+
lane: 'lightweight',
|
|
1198
|
+
target: processScopeExecutionTarget(entry.controllerHome, processScopeFromKey(entry.scopeKey)),
|
|
1199
|
+
principalId: entry.principalId,
|
|
1200
|
+
workId: entry.workId,
|
|
1201
|
+
commandId: entry.commandId,
|
|
1202
|
+
});
|
|
1034
1203
|
persistRunningReceipt(entry, true);
|
|
1035
1204
|
|
|
1036
1205
|
if (entry.interactiveWaitMs > 0) {
|
|
@@ -1058,10 +1227,10 @@ export async function startLightweightControllerCheck(
|
|
|
1058
1227
|
};
|
|
1059
1228
|
}
|
|
1060
1229
|
|
|
1061
|
-
function requireEntry(
|
|
1230
|
+
function requireEntry(scopeKey: string, processId: string): LightweightEntry {
|
|
1062
1231
|
const entry = entries.get(processId);
|
|
1063
1232
|
if (!entry) throw new Error(`PROCESS_NOT_FOUND: ${processId}`);
|
|
1064
|
-
if (entry.
|
|
1233
|
+
if (entry.scopeKey !== scopeKey) throw new Error(`PROCESS_SCOPE_MISMATCH: process ${processId} belongs to ${entry.scopeKey}, not ${scopeKey}`);
|
|
1065
1234
|
return entry;
|
|
1066
1235
|
}
|
|
1067
1236
|
|
|
@@ -1069,17 +1238,27 @@ export function isLightweightProcessId(processId: string): boolean {
|
|
|
1069
1238
|
return processId.startsWith('lightweight:');
|
|
1070
1239
|
}
|
|
1071
1240
|
|
|
1241
|
+
/** Repository placement of a lightweight handle this Runtime still owns in memory. */
|
|
1242
|
+
export function lightweightProcessRepositoryId(processId: string): string | undefined {
|
|
1243
|
+
return entries.get(processId)?.repoId;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
/** Canonical Process scope key of a lightweight handle this Runtime still owns in memory. */
|
|
1247
|
+
export function lightweightProcessScopeKey(processId: string): string | undefined {
|
|
1248
|
+
return entries.get(processId)?.scopeKey;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1072
1251
|
/** Test seam for proving terminal receipt recovery across Runtime-memory loss. */
|
|
1073
1252
|
export function clearLightweightProcessMemoryForTest(): void {
|
|
1074
1253
|
entries.clear();
|
|
1075
1254
|
}
|
|
1076
1255
|
|
|
1077
|
-
export function getLightweightProcessHandle(controllerHome: string,
|
|
1256
|
+
export function getLightweightProcessHandle(controllerHome: string, scopeKey: string, processId: string): ProcessHandle | undefined {
|
|
1078
1257
|
const entry = entries.get(processId);
|
|
1079
|
-
if (entry?.
|
|
1080
|
-
const terminal = readTerminalReceipt(controllerHome,
|
|
1258
|
+
if (entry?.scopeKey === scopeKey) return entryHandle(entry);
|
|
1259
|
+
const terminal = readTerminalReceipt(controllerHome, scopeKey, processId);
|
|
1081
1260
|
if (terminal) return terminal.handle;
|
|
1082
|
-
const running = readRunningReceipt(controllerHome,
|
|
1261
|
+
const running = readRunningReceipt(controllerHome, scopeKey, processId);
|
|
1083
1262
|
if (!running) return undefined;
|
|
1084
1263
|
if (running.exitObservation) {
|
|
1085
1264
|
return persistRecoveredTerminalReceipt(controllerHome, running, completedObservedExitHandle(running));
|
|
@@ -1094,20 +1273,20 @@ export function getLightweightProcessHandle(controllerHome: string, repoId: stri
|
|
|
1094
1273
|
|
|
1095
1274
|
export async function waitForLightweightProcess(
|
|
1096
1275
|
controllerHome: string,
|
|
1097
|
-
|
|
1276
|
+
scopeKey: string,
|
|
1098
1277
|
processId: string,
|
|
1099
1278
|
options: WaitProcessOptions = {},
|
|
1100
1279
|
): Promise<ProcessHandle> {
|
|
1101
1280
|
const entry = entries.get(processId);
|
|
1102
1281
|
if (!entry) {
|
|
1103
|
-
const terminal = readTerminalReceipt(controllerHome,
|
|
1282
|
+
const terminal = readTerminalReceipt(controllerHome, scopeKey, processId);
|
|
1104
1283
|
if (terminal) return terminal.handle;
|
|
1105
|
-
let running = readRunningReceipt(controllerHome,
|
|
1284
|
+
let running = readRunningReceipt(controllerHome, scopeKey, processId);
|
|
1106
1285
|
if (!running) throw new Error(`PROCESS_NOT_FOUND: ${processId}`);
|
|
1107
1286
|
const timeoutMs = Math.max(1, options.timeoutMs ?? 15_000);
|
|
1108
1287
|
const deadline = Date.now() + timeoutMs;
|
|
1109
1288
|
while (true) {
|
|
1110
|
-
const recoveredTerminal = readTerminalReceipt(controllerHome,
|
|
1289
|
+
const recoveredTerminal = readTerminalReceipt(controllerHome, scopeKey, processId);
|
|
1111
1290
|
if (recoveredTerminal) return recoveredTerminal.handle;
|
|
1112
1291
|
if (running.exitObservation) {
|
|
1113
1292
|
return persistRecoveredTerminalReceipt(controllerHome, running, completedObservedExitHandle(running));
|
|
@@ -1124,10 +1303,10 @@ export async function waitForLightweightProcess(
|
|
|
1124
1303
|
const timer = setTimeout(resolve, Math.min(50, Math.max(1, deadline - Date.now())));
|
|
1125
1304
|
timer.unref?.();
|
|
1126
1305
|
});
|
|
1127
|
-
running = readRunningReceipt(controllerHome,
|
|
1306
|
+
running = readRunningReceipt(controllerHome, scopeKey, processId) ?? running;
|
|
1128
1307
|
}
|
|
1129
1308
|
}
|
|
1130
|
-
if (entry.
|
|
1309
|
+
if (entry.scopeKey !== scopeKey) throw new Error(`PROCESS_SCOPE_MISMATCH: process ${processId} belongs to ${entry.scopeKey}, not ${scopeKey}`);
|
|
1131
1310
|
if (entry.result) return entryHandle(entry);
|
|
1132
1311
|
const timeoutMs = Math.max(1, options.timeoutMs ?? 15_000);
|
|
1133
1312
|
await Promise.race([
|
|
@@ -1151,12 +1330,12 @@ export async function cancelAllLightweightProcesses(controllerHome: string): Pro
|
|
|
1151
1330
|
return active.length;
|
|
1152
1331
|
}
|
|
1153
1332
|
|
|
1154
|
-
export async function cancelLightweightProcess(controllerHome: string,
|
|
1333
|
+
export async function cancelLightweightProcess(controllerHome: string, scopeKey: string, processId: string): Promise<ProcessHandle> {
|
|
1155
1334
|
const entry = entries.get(processId);
|
|
1156
1335
|
if (!entry) {
|
|
1157
|
-
const terminal = readTerminalReceipt(controllerHome,
|
|
1336
|
+
const terminal = readTerminalReceipt(controllerHome, scopeKey, processId);
|
|
1158
1337
|
if (terminal) return terminal.handle;
|
|
1159
|
-
const running = readRunningReceipt(controllerHome,
|
|
1338
|
+
const running = readRunningReceipt(controllerHome, scopeKey, processId);
|
|
1160
1339
|
if (!running) throw new Error(`PROCESS_NOT_FOUND: ${processId}`);
|
|
1161
1340
|
if (running.exitObservation) {
|
|
1162
1341
|
return persistRecoveredTerminalReceipt(controllerHome, running, completedObservedExitHandle(running));
|
|
@@ -1171,7 +1350,7 @@ export async function cancelLightweightProcess(controllerHome: string, repoId: s
|
|
|
1171
1350
|
await terminateProcessTree(pid, { gracePeriodMs: 200, killAfterMs: 1_000, pollIntervalMs: 25 });
|
|
1172
1351
|
return persistRecoveredTerminalReceipt(controllerHome, running, cancelledRecoveredHandle(running));
|
|
1173
1352
|
}
|
|
1174
|
-
if (entry.
|
|
1353
|
+
if (entry.scopeKey !== scopeKey) throw new Error(`PROCESS_SCOPE_MISMATCH: process ${processId} belongs to ${entry.scopeKey}, not ${scopeKey}`);
|
|
1175
1354
|
if (!entry.result) {
|
|
1176
1355
|
entry.abort.abort();
|
|
1177
1356
|
await entry.promise;
|
|
@@ -1181,13 +1360,13 @@ export async function cancelLightweightProcess(controllerHome: string, repoId: s
|
|
|
1181
1360
|
|
|
1182
1361
|
export function readLightweightProcessLogs(
|
|
1183
1362
|
controllerHome: string,
|
|
1184
|
-
|
|
1363
|
+
scopeKey: string,
|
|
1185
1364
|
processId: string,
|
|
1186
1365
|
maxBytes = 32 * 1024,
|
|
1187
1366
|
): ProcessLogSlice | undefined {
|
|
1188
1367
|
const entry = entries.get(processId);
|
|
1189
1368
|
if (!entry) {
|
|
1190
|
-
const terminal = readTerminalReceipt(controllerHome,
|
|
1369
|
+
const terminal = readTerminalReceipt(controllerHome, scopeKey, processId);
|
|
1191
1370
|
if (terminal) {
|
|
1192
1371
|
const stdout = capProcessOutput(terminal.handle.stdout ?? '', maxBytes);
|
|
1193
1372
|
const stderr = capProcessOutput(terminal.handle.stderr ?? '', maxBytes);
|
|
@@ -1201,7 +1380,7 @@ export function readLightweightProcessLogs(
|
|
|
1201
1380
|
|| Buffer.byteLength(terminal.handle.stderr ?? '', 'utf8') > maxBytes,
|
|
1202
1381
|
};
|
|
1203
1382
|
}
|
|
1204
|
-
const running = readRunningReceipt(controllerHome,
|
|
1383
|
+
const running = readRunningReceipt(controllerHome, scopeKey, processId);
|
|
1205
1384
|
if (!running) return undefined;
|
|
1206
1385
|
const stdout = capProcessOutput(running.handle.stdoutTail ?? '', maxBytes);
|
|
1207
1386
|
const stderr = capProcessOutput(running.handle.stderrTail ?? '', maxBytes);
|
|
@@ -1215,7 +1394,7 @@ export function readLightweightProcessLogs(
|
|
|
1215
1394
|
|| Buffer.byteLength(running.handle.stderrTail ?? '', 'utf8') > maxBytes,
|
|
1216
1395
|
};
|
|
1217
1396
|
}
|
|
1218
|
-
if (entry.
|
|
1397
|
+
if (entry.scopeKey !== scopeKey) return undefined;
|
|
1219
1398
|
const rawStdout = entry.result?.stdout ?? entry.stdout;
|
|
1220
1399
|
const rawStderr = entry.result?.stderr ?? entry.stderr;
|
|
1221
1400
|
const visibleStdout = visibleOutput(rawStdout, maxBytes);
|