@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
|
@@ -9,6 +9,12 @@ import { readJsonFile, sanitizeFileComponent, writeJsonAtomic } from '../shared/
|
|
|
9
9
|
import { createFirstPartyPluginAdapterMap } from './first-party-registry';
|
|
10
10
|
import { getExternalPluginAdapter, listExternalPluginAdapters } from './external-adapter';
|
|
11
11
|
import { AssistantPluginError, toAssistantPluginError } from './errors';
|
|
12
|
+
import {
|
|
13
|
+
findActivePluginCapabilityAuthorization,
|
|
14
|
+
pluginCapabilityAuthorizationOwnerScope,
|
|
15
|
+
recordPluginCapabilityAuthorization,
|
|
16
|
+
type PluginCapabilityAuthorizationGrant,
|
|
17
|
+
} from './capability-authorization-grants';
|
|
12
18
|
import { markControllerContextProjectionDirty } from '../projections/controller-context';
|
|
13
19
|
import { classifyRepositoryCommand } from '../../cli/repositories/command-classifier';
|
|
14
20
|
import {
|
|
@@ -24,6 +30,7 @@ import type {
|
|
|
24
30
|
AssistantPluginActionDescriptor,
|
|
25
31
|
AssistantPluginActionExecutionInput,
|
|
26
32
|
AssistantPluginActionRequest,
|
|
33
|
+
AssistantPluginAuthorizationContext,
|
|
27
34
|
AssistantPluginManifest,
|
|
28
35
|
AssistantPluginRegistryIndex,
|
|
29
36
|
AssistantPluginRegistryIndexEntry,
|
|
@@ -44,7 +51,8 @@ export function assistantPluginScope(pluginId: string, controllerHome?: string):
|
|
|
44
51
|
return PLUGIN_ADAPTERS.get(pluginId)?.scope ?? (controllerHome ? getExternalPluginAdapter(controllerHome, pluginId)?.scope : undefined);
|
|
45
52
|
}
|
|
46
53
|
|
|
47
|
-
const
|
|
54
|
+
const PLUGIN_MANIFEST_LIVE_CACHE_TTL_MS = 5_000;
|
|
55
|
+
const PLUGIN_MANIFEST_STORED_CACHE_TTL_MS = Number.POSITIVE_INFINITY;
|
|
48
56
|
|
|
49
57
|
|
|
50
58
|
interface PluginManifestCacheEntry<T> {
|
|
@@ -83,6 +91,7 @@ export function controllerPluginRepository(controllerHome: string): RepositoryRe
|
|
|
83
91
|
|
|
84
92
|
function adapterMatchesRepository(adapter: AssistantPluginAdapter, repository: RepositoryRecord): boolean {
|
|
85
93
|
const scope = adapter.scope ?? 'repository';
|
|
94
|
+
if (scope === 'controller_with_repository_overlay') return true;
|
|
86
95
|
return repository.repoId === CONTROLLER_SCOPE_REPO_ID ? scope === 'controller' : scope === 'repository';
|
|
87
96
|
}
|
|
88
97
|
|
|
@@ -101,10 +110,11 @@ function itemCacheKey(controllerHome: string, repoId: string, pluginId: string,
|
|
|
101
110
|
function readPluginManifestCache<T>(
|
|
102
111
|
cache: Map<string, PluginManifestCacheEntry<T>>,
|
|
103
112
|
key: string,
|
|
113
|
+
maxAgeMs = PLUGIN_MANIFEST_LIVE_CACHE_TTL_MS,
|
|
104
114
|
): T | undefined {
|
|
105
115
|
const cached = cache.get(key);
|
|
106
116
|
if (!cached) return undefined;
|
|
107
|
-
if (Date.now() - cached.createdAt >
|
|
117
|
+
if (Number.isFinite(maxAgeMs) && Date.now() - cached.createdAt > maxAgeMs) {
|
|
108
118
|
cache.delete(key);
|
|
109
119
|
return undefined;
|
|
110
120
|
}
|
|
@@ -231,8 +241,11 @@ function cachedManifestForRepository(
|
|
|
231
241
|
repoId: string,
|
|
232
242
|
pluginId: string,
|
|
233
243
|
): AssistantPluginManifest | undefined {
|
|
234
|
-
return readPluginManifestCache(
|
|
235
|
-
|
|
244
|
+
return readPluginManifestCache(
|
|
245
|
+
pluginManifestItemCache,
|
|
246
|
+
itemCacheKey(controllerHome, repoId, pluginId, true),
|
|
247
|
+
PLUGIN_MANIFEST_STORED_CACHE_TTL_MS,
|
|
248
|
+
) ?? readPluginManifestCache(pluginManifestItemCache, itemCacheKey(controllerHome, repoId, pluginId, false));
|
|
236
249
|
}
|
|
237
250
|
|
|
238
251
|
function computeManifest(
|
|
@@ -244,7 +257,12 @@ function computeManifest(
|
|
|
244
257
|
const adapter = resolvedAdapter ?? resolvePluginAdapter(controllerHome, pluginId);
|
|
245
258
|
if (!adapter || !adapterMatchesRepository(adapter, repository)) throw new Error(`PLUGIN_NOT_FOUND: ${pluginId}`);
|
|
246
259
|
const previous = readStoredManifest(controllerHome, repository.repoId, pluginId);
|
|
247
|
-
const built = adapter.buildManifest(previous?.revision ?? 0, previous?.updatedAt, repository.canonicalRoot
|
|
260
|
+
const built = adapter.buildManifest(previous?.revision ?? 0, previous?.updatedAt, repository.canonicalRoot, {
|
|
261
|
+
controllerHome,
|
|
262
|
+
repoId: repository.repoId,
|
|
263
|
+
repoRoot: repository.canonicalRoot,
|
|
264
|
+
controllerScoped: repository.repoId === CONTROLLER_SCOPE_REPO_ID,
|
|
265
|
+
});
|
|
248
266
|
const changed = !previous || fingerprintManifest(previous) !== fingerprintManifest(built);
|
|
249
267
|
return {
|
|
250
268
|
...built,
|
|
@@ -356,27 +374,63 @@ function enforceConfirmation(action: AssistantPluginActionDescriptor, request: A
|
|
|
356
374
|
}
|
|
357
375
|
}
|
|
358
376
|
|
|
377
|
+
export interface PluginActionAuthorizationEvidence {
|
|
378
|
+
source: 'none' | 'host_permission_model' | 'capability_grant' | 'strong_confirmation';
|
|
379
|
+
reusable: boolean;
|
|
380
|
+
capabilityId?: string;
|
|
381
|
+
target?: { kind: string; id: string };
|
|
382
|
+
grantId?: string;
|
|
383
|
+
established?: boolean;
|
|
384
|
+
lookupError?: string;
|
|
385
|
+
persistenceError?: string;
|
|
386
|
+
}
|
|
387
|
+
|
|
359
388
|
function actionForManifest(manifest: AssistantPluginManifest, actionId: string): AssistantPluginActionDescriptor {
|
|
360
389
|
const action = manifest.actions.find((entry) => entry.actionId === actionId);
|
|
361
390
|
if (!action) throw new Error(`PLUGIN_ACTION_NOT_FOUND: ${manifest.pluginId}/${actionId}`);
|
|
362
391
|
return action;
|
|
363
392
|
}
|
|
364
393
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
394
|
+
function reusableCapabilityId(manifest: AssistantPluginManifest, action: AssistantPluginActionDescriptor): string {
|
|
395
|
+
const matches = manifest.capabilities
|
|
396
|
+
.filter((capability) => capability.actions.includes(action.actionId))
|
|
397
|
+
.map((capability) => capability.capabilityId)
|
|
398
|
+
.filter(Boolean)
|
|
399
|
+
.sort();
|
|
400
|
+
// Overlapping capability groups are ambiguous privilege boundaries. Fall back
|
|
401
|
+
// to action-local reuse instead of silently choosing a broader capability.
|
|
402
|
+
return matches.length === 1 ? matches[0]! : `action:${action.actionId}`;
|
|
403
|
+
}
|
|
372
404
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
405
|
+
const INTERACTIVE_PLUGIN_AUTHORIZATION_SURFACES = new Set(['mcp', 'local-ui', 'chatgpt-action']);
|
|
406
|
+
|
|
407
|
+
function originMayEstablishCapabilityAuthorization(origin: AssistantPluginActionExecutionInput['origin']): boolean {
|
|
408
|
+
return INTERACTIVE_PLUGIN_AUTHORIZATION_SURFACES.has(origin.surface);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function authorizationTargetSummary(context: AssistantPluginAuthorizationContext): { kind: string; id: string } {
|
|
412
|
+
return { kind: context.target.kind, id: context.target.id };
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function authorizationError(error: unknown): string {
|
|
416
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
417
|
+
return message.slice(0, 500);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function initialAuthorizationEvidence(
|
|
421
|
+
manifest: AssistantPluginManifest,
|
|
422
|
+
action: AssistantPluginActionDescriptor,
|
|
423
|
+
): PluginActionAuthorizationEvidence {
|
|
424
|
+
if (action.confirmation === 'none') return { source: 'none', reusable: false };
|
|
425
|
+
const capabilityId = reusableCapabilityId(manifest, action);
|
|
426
|
+
if (action.confirmation === 'strong_confirmation') {
|
|
427
|
+
return { source: 'strong_confirmation', reusable: false, capabilityId };
|
|
378
428
|
}
|
|
379
|
-
|
|
429
|
+
return { source: 'host_permission_model', reusable: false, capabilityId };
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function denyAutomatedWrite(manifest: AssistantPluginManifest, action: AssistantPluginActionDescriptor, origin: AssistantPluginActionExecutionInput['origin']): void {
|
|
433
|
+
if (!['schedule', 'reconciliation', 'system'].includes(origin.surface)) return;
|
|
380
434
|
if (action.readOnly) return;
|
|
381
435
|
throw new Error(`EXTERNAL_EFFECT_AUTHORIZATION_REQUIRED: ${manifest.pluginId}/${action.actionId} cannot run from ${origin.surface}`);
|
|
382
436
|
}
|
|
@@ -406,7 +460,14 @@ export function listAssistantPluginManifests(
|
|
|
406
460
|
const preferStored = options.preferStored === true && options.forceRefresh !== true;
|
|
407
461
|
const cacheKey = listCacheKey(controllerHome, repository.repoId, preferStored);
|
|
408
462
|
if (options.forceRefresh !== true) {
|
|
409
|
-
|
|
463
|
+
// Stored manifests are persisted snapshots. Their freshness is governed by
|
|
464
|
+
// explicit registry/config mutation invalidation, not a wall-clock trust
|
|
465
|
+
// window. Live execution manifests retain the short identity-validation TTL.
|
|
466
|
+
const cached = readPluginManifestCache(
|
|
467
|
+
pluginManifestListCache,
|
|
468
|
+
cacheKey,
|
|
469
|
+
preferStored ? PLUGIN_MANIFEST_STORED_CACHE_TTL_MS : PLUGIN_MANIFEST_LIVE_CACHE_TTL_MS,
|
|
470
|
+
);
|
|
410
471
|
if (cached) return cached;
|
|
411
472
|
}
|
|
412
473
|
const manifests = listAssistantPluginIds(controllerHome, repository)
|
|
@@ -544,6 +605,7 @@ export interface PluginActionReceipt {
|
|
|
544
605
|
createdAt: string;
|
|
545
606
|
workId?: string;
|
|
546
607
|
origin?: { surface: string; actor?: string; correlationId?: string };
|
|
608
|
+
authorization?: PluginActionAuthorizationEvidence;
|
|
547
609
|
result?: Record<string, unknown>;
|
|
548
610
|
error?: { code: string; message: string };
|
|
549
611
|
}
|
|
@@ -692,12 +754,73 @@ function remoteEffectWorkForPluginAction(
|
|
|
692
754
|
throw new Error(`WORK_PLUGIN_RECEIPT_BINDING_CHECKS_PRESENT: ${workId} declares repository checks and cannot be completed by a plugin receipt alone`);
|
|
693
755
|
}
|
|
694
756
|
if (isTerminalWorkContractStatus(work.status)) {
|
|
695
|
-
|
|
757
|
+
const receiptAlreadyBound = Boolean(receiptId) && (
|
|
758
|
+
work.completionReceipt?.receiptId === receiptId
|
|
759
|
+
|| work.evidenceRefs.some((evidence) => evidence.evidenceId === receiptId)
|
|
760
|
+
);
|
|
761
|
+
if (work.status === 'completed' && receiptAlreadyBound) return work;
|
|
696
762
|
throw new Error(`WORK_PLUGIN_RECEIPT_BINDING_TERMINAL: ${workId} is ${work.status}`);
|
|
697
763
|
}
|
|
698
764
|
return work;
|
|
699
765
|
}
|
|
700
766
|
|
|
767
|
+
function attributedWorkForPluginAction(
|
|
768
|
+
controllerHome: string,
|
|
769
|
+
repository: RepositoryRecord,
|
|
770
|
+
action: AssistantPluginActionDescriptor,
|
|
771
|
+
request: AssistantPluginActionRequest,
|
|
772
|
+
): WorkContract | undefined {
|
|
773
|
+
const workId = request.workId?.trim();
|
|
774
|
+
if (!workId || action.risk === 'remote_write') return undefined;
|
|
775
|
+
const work = getWorkContract({ controllerHome, repoId: repository.repoId }, workId);
|
|
776
|
+
if (!work) throw new Error(`WORK_PLUGIN_ATTRIBUTION_NOT_FOUND: ${workId}`);
|
|
777
|
+
if (isTerminalWorkContractStatus(work.status)) {
|
|
778
|
+
throw new Error(`WORK_PLUGIN_ATTRIBUTION_TERMINAL: ${workId} is ${work.status}`);
|
|
779
|
+
}
|
|
780
|
+
return work;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
export function finalizeRemoteEffectWorkFromActionReceipt(
|
|
784
|
+
controllerHome: string,
|
|
785
|
+
repoId: string,
|
|
786
|
+
workId: string,
|
|
787
|
+
): WorkContract {
|
|
788
|
+
const work = getWorkContract({ controllerHome, repoId }, workId);
|
|
789
|
+
if (!work) throw new Error(`WORK_PLUGIN_RECEIPT_BINDING_NOT_FOUND: ${workId}`);
|
|
790
|
+
if (work.workKind !== 'remote_effect') {
|
|
791
|
+
throw new Error(`WORK_REMOTE_EFFECT_FINALIZE_KIND_MISMATCH: ${workId} is ${work.workKind}, expected remote_effect`);
|
|
792
|
+
}
|
|
793
|
+
if (work.status === 'completed' && work.completionReceipt?.source === 'remote_effect') return work;
|
|
794
|
+
if (isTerminalWorkContractStatus(work.status)) {
|
|
795
|
+
throw new Error(`WORK_REMOTE_EFFECT_FINALIZE_TERMINAL: ${workId} is ${work.status}`);
|
|
796
|
+
}
|
|
797
|
+
const receipt = work.evidenceRefs
|
|
798
|
+
.map((evidence) => evidence.evidenceId ? readPluginActionReceipt(controllerHome, repoId, evidence.evidenceId) : undefined)
|
|
799
|
+
.find((candidate) => candidate?.workId === workId && candidate.status === 'succeeded');
|
|
800
|
+
if (!receipt) {
|
|
801
|
+
throw new Error(`WORK_REMOTE_EFFECT_FINALIZE_RECEIPT_REQUIRED: ${workId} has no successful durable plugin action receipt`);
|
|
802
|
+
}
|
|
803
|
+
const remoteReceipt: RemoteEffectCompletionReceipt = {
|
|
804
|
+
schemaVersion: 1,
|
|
805
|
+
receiptId: receipt.receiptId,
|
|
806
|
+
source: 'remote_effect',
|
|
807
|
+
workId,
|
|
808
|
+
pluginId: receipt.pluginId,
|
|
809
|
+
actionId: receipt.actionId,
|
|
810
|
+
requestId: receipt.requestId,
|
|
811
|
+
semanticKey: receipt.semanticKey,
|
|
812
|
+
resultDigest: createHash('sha256').update(JSON.stringify(receipt.result ?? null)).digest('hex'),
|
|
813
|
+
recordedAt: new Date().toISOString(),
|
|
814
|
+
};
|
|
815
|
+
return recordWorkCompletionReceipt(
|
|
816
|
+
{ controllerHome, repoId },
|
|
817
|
+
workId,
|
|
818
|
+
remoteReceipt,
|
|
819
|
+
'completed_remote',
|
|
820
|
+
'remote_effect',
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
|
|
701
824
|
function bindRemoteEffectReceiptToWork(
|
|
702
825
|
controllerHome: string,
|
|
703
826
|
repository: RepositoryRecord,
|
|
@@ -709,15 +832,17 @@ function bindRemoteEffectReceiptToWork(
|
|
|
709
832
|
if (receipt.status !== 'succeeded') return remoteEffectWorkForPluginAction(controllerHome, repository, action, request);
|
|
710
833
|
const work = remoteEffectWorkForPluginAction(controllerHome, repository, action, request, receipt.receiptId);
|
|
711
834
|
if (!work) return undefined;
|
|
712
|
-
if (work.status === 'completed'
|
|
835
|
+
if (work.status === 'completed') return work;
|
|
836
|
+
let updated = work;
|
|
713
837
|
if (!work.evidenceRefs.some((evidence) => evidence.evidenceId === receipt.receiptId)) {
|
|
714
|
-
appendWorkEvidence({ controllerHome, repoId: repository.repoId }, work.workId, {
|
|
838
|
+
updated = appendWorkEvidence({ controllerHome, repoId: repository.repoId }, work.workId, {
|
|
715
839
|
evidenceId: receipt.receiptId,
|
|
716
840
|
title: 'typed remote plugin effect completed',
|
|
717
841
|
summary: `${receipt.pluginId}/${receipt.actionId} completed with durable receipt ${receipt.receiptId}.`,
|
|
718
842
|
detailLevel: 'summary',
|
|
719
843
|
});
|
|
720
844
|
}
|
|
845
|
+
if (action.remoteEffectWorkCompletion !== 'terminal') return updated;
|
|
721
846
|
const remoteReceipt: RemoteEffectCompletionReceipt = {
|
|
722
847
|
schemaVersion: 1,
|
|
723
848
|
receiptId: receipt.receiptId,
|
|
@@ -785,8 +910,11 @@ export async function submitAssistantPluginAction(
|
|
|
785
910
|
deduplicated: boolean;
|
|
786
911
|
result?: Record<string, unknown>;
|
|
787
912
|
receipt: PluginActionReceipt;
|
|
913
|
+
authorization?: PluginActionAuthorizationEvidence;
|
|
788
914
|
workId?: string;
|
|
789
915
|
}> {
|
|
916
|
+
const adapter = resolvePluginAdapter(controllerHome, request.pluginId);
|
|
917
|
+
if (!adapter) throw new Error(`PLUGIN_NOT_FOUND: ${request.pluginId}`);
|
|
790
918
|
const manifest = getAssistantPluginManifest(controllerHome, repository, request.pluginId);
|
|
791
919
|
const action = actionForManifest(manifest, request.actionId);
|
|
792
920
|
if (!manifest.enabled && action.actionId !== 'configure') {
|
|
@@ -812,7 +940,7 @@ export async function submitAssistantPluginAction(
|
|
|
812
940
|
if (request.workId && existing.workId !== request.workId) {
|
|
813
941
|
throw new Error(`WORK_PLUGIN_RECEIPT_BINDING_CONFLICT: ${request.requestId} already belongs to Work ${existing.workId ?? 'none'}`);
|
|
814
942
|
}
|
|
815
|
-
if (request.workId) bindRemoteEffectReceiptToWork(controllerHome, repository, action, request, existing);
|
|
943
|
+
if (request.workId && action.risk === 'remote_write') bindRemoteEffectReceiptToWork(controllerHome, repository, action, request, existing);
|
|
816
944
|
return {
|
|
817
945
|
manifest,
|
|
818
946
|
action,
|
|
@@ -820,19 +948,29 @@ export async function submitAssistantPluginAction(
|
|
|
820
948
|
deduplicated: true,
|
|
821
949
|
result: existing.result,
|
|
822
950
|
receipt: existing,
|
|
951
|
+
authorization: existing.authorization,
|
|
823
952
|
workId: existing.workId,
|
|
824
953
|
};
|
|
825
954
|
}
|
|
826
955
|
|
|
827
956
|
const createdAt = new Date().toISOString();
|
|
828
957
|
const receiptId = `PLG-${Date.now()}-${createHash('sha256').update(request.requestId).digest('hex').slice(0, 8)}`;
|
|
829
|
-
const
|
|
958
|
+
const capabilityId = reusableCapabilityId(manifest, action);
|
|
959
|
+
let authorization = initialAuthorizationEvidence(manifest, action);
|
|
960
|
+
let authorizationContext: AssistantPluginAuthorizationContext | undefined;
|
|
961
|
+
let activeAuthorizationGrant: PluginCapabilityAuthorizationGrant | undefined;
|
|
830
962
|
const requiresLocalEffectWork = localSystemActionRequiresWork(
|
|
831
963
|
repository,
|
|
832
964
|
request.pluginId,
|
|
833
965
|
request.actionId,
|
|
834
966
|
normalizedArgs,
|
|
835
967
|
);
|
|
968
|
+
const boundRemoteWork = action.risk === 'remote_write'
|
|
969
|
+
? remoteEffectWorkForPluginAction(controllerHome, repository, action, request)
|
|
970
|
+
: undefined;
|
|
971
|
+
const attributedWork = !requiresLocalEffectWork
|
|
972
|
+
? attributedWorkForPluginAction(controllerHome, repository, action, request)
|
|
973
|
+
: undefined;
|
|
836
974
|
const acceptedWork = requiresLocalEffectWork
|
|
837
975
|
? acceptSubmittedWorkContract(controllerHome, {
|
|
838
976
|
requestId: request.requestId,
|
|
@@ -885,10 +1023,63 @@ export async function submitAssistantPluginAction(
|
|
|
885
1023
|
receiptId,
|
|
886
1024
|
risk: action.risk,
|
|
887
1025
|
confirmation: action.confirmation,
|
|
1026
|
+
capabilityId,
|
|
1027
|
+
authorizationReuseSupported: action.confirmation === 'authorization' && Boolean(adapter.resolveAuthorizationContext),
|
|
888
1028
|
},
|
|
889
1029
|
});
|
|
890
1030
|
|
|
891
1031
|
try {
|
|
1032
|
+
if (action.confirmation === 'authorization'
|
|
1033
|
+
&& adapter.resolveAuthorizationContext
|
|
1034
|
+
&& originMayEstablishCapabilityAuthorization(request.origin)) {
|
|
1035
|
+
authorizationContext = await adapter.resolveAuthorizationContext({
|
|
1036
|
+
controllerHome,
|
|
1037
|
+
repoId: repository.repoId,
|
|
1038
|
+
repoRoot: repository.canonicalRoot,
|
|
1039
|
+
pluginId: request.pluginId,
|
|
1040
|
+
actionId: request.actionId,
|
|
1041
|
+
requestId: request.requestId,
|
|
1042
|
+
args: normalizedArgs,
|
|
1043
|
+
origin: request.origin,
|
|
1044
|
+
jobId: receiptId,
|
|
1045
|
+
timeoutMs: request.timeoutMs,
|
|
1046
|
+
signal: request.signal,
|
|
1047
|
+
});
|
|
1048
|
+
if (authorizationContext) {
|
|
1049
|
+
authorization = {
|
|
1050
|
+
source: 'host_permission_model',
|
|
1051
|
+
reusable: false,
|
|
1052
|
+
capabilityId,
|
|
1053
|
+
target: authorizationTargetSummary(authorizationContext),
|
|
1054
|
+
};
|
|
1055
|
+
try {
|
|
1056
|
+
activeAuthorizationGrant = findActivePluginCapabilityAuthorization(controllerHome, {
|
|
1057
|
+
ownerScope: pluginCapabilityAuthorizationOwnerScope(request.origin),
|
|
1058
|
+
repoId: repository.repoId,
|
|
1059
|
+
pluginId: request.pluginId,
|
|
1060
|
+
capabilityId,
|
|
1061
|
+
target: authorizationContext.target,
|
|
1062
|
+
scopes: action.scopes,
|
|
1063
|
+
risk: action.risk,
|
|
1064
|
+
});
|
|
1065
|
+
if (activeAuthorizationGrant) {
|
|
1066
|
+
authorization = {
|
|
1067
|
+
source: 'capability_grant',
|
|
1068
|
+
reusable: true,
|
|
1069
|
+
capabilityId,
|
|
1070
|
+
target: authorizationTargetSummary(authorizationContext),
|
|
1071
|
+
grantId: activeAuthorizationGrant.grantId,
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
} catch (error) {
|
|
1075
|
+
authorization = {
|
|
1076
|
+
...authorization,
|
|
1077
|
+
lookupError: authorizationError(error),
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
|
|
892
1083
|
const result = await executeAssistantPluginAction({
|
|
893
1084
|
controllerHome,
|
|
894
1085
|
repoId: repository.repoId,
|
|
@@ -905,15 +1096,49 @@ export async function submitAssistantPluginAction(
|
|
|
905
1096
|
? Date.now() + Math.max(1, Math.trunc(request.timeoutMs))
|
|
906
1097
|
: undefined,
|
|
907
1098
|
});
|
|
1099
|
+
if (action.confirmation === 'authorization'
|
|
1100
|
+
&& authorizationContext
|
|
1101
|
+
&& !activeAuthorizationGrant
|
|
1102
|
+
&& originMayEstablishCapabilityAuthorization(request.origin)) {
|
|
1103
|
+
try {
|
|
1104
|
+
const grant = recordPluginCapabilityAuthorization(controllerHome, {
|
|
1105
|
+
ownerScope: pluginCapabilityAuthorizationOwnerScope(request.origin),
|
|
1106
|
+
repoId: repository.repoId,
|
|
1107
|
+
pluginId: request.pluginId,
|
|
1108
|
+
capabilityId,
|
|
1109
|
+
target: authorizationContext.target,
|
|
1110
|
+
scopes: action.scopes,
|
|
1111
|
+
riskCeiling: action.risk,
|
|
1112
|
+
expiresInMinutes: authorizationContext.expiresInMinutes,
|
|
1113
|
+
});
|
|
1114
|
+
authorization = {
|
|
1115
|
+
source: 'host_permission_model',
|
|
1116
|
+
reusable: true,
|
|
1117
|
+
capabilityId,
|
|
1118
|
+
target: authorizationTargetSummary(authorizationContext),
|
|
1119
|
+
grantId: grant.grantId,
|
|
1120
|
+
established: true,
|
|
1121
|
+
...(authorization.lookupError ? { lookupError: authorization.lookupError } : {}),
|
|
1122
|
+
};
|
|
1123
|
+
} catch (error) {
|
|
1124
|
+
authorization = {
|
|
1125
|
+
...authorization,
|
|
1126
|
+
reusable: false,
|
|
1127
|
+
persistenceError: authorizationError(error),
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
908
1132
|
let resultWithLineage = result;
|
|
909
1133
|
if (boundRemoteWork) {
|
|
1134
|
+
const terminalRemoteEffect = action.remoteEffectWorkCompletion === 'terminal';
|
|
910
1135
|
resultWithLineage = {
|
|
911
1136
|
...result,
|
|
912
1137
|
work: {
|
|
913
1138
|
workId: boundRemoteWork.workId,
|
|
914
1139
|
workKind: 'remote_effect',
|
|
915
|
-
completionOutcome: 'completed_remote',
|
|
916
|
-
status: 'completed',
|
|
1140
|
+
...(terminalRemoteEffect ? { completionOutcome: 'completed_remote' as const } : {}),
|
|
1141
|
+
status: terminalRemoteEffect ? 'completed' : 'running',
|
|
917
1142
|
},
|
|
918
1143
|
};
|
|
919
1144
|
}
|
|
@@ -961,8 +1186,15 @@ export async function submitAssistantPluginAction(
|
|
|
961
1186
|
semanticKey: key,
|
|
962
1187
|
status: 'succeeded',
|
|
963
1188
|
createdAt,
|
|
964
|
-
...(acceptedWork
|
|
1189
|
+
...(acceptedWork
|
|
1190
|
+
? { workId: acceptedWork.workId }
|
|
1191
|
+
: boundRemoteWork
|
|
1192
|
+
? { workId: boundRemoteWork.workId }
|
|
1193
|
+
: attributedWork
|
|
1194
|
+
? { workId: attributedWork.workId }
|
|
1195
|
+
: {}),
|
|
965
1196
|
origin: request.origin,
|
|
1197
|
+
authorization,
|
|
966
1198
|
result: resultWithLineage,
|
|
967
1199
|
};
|
|
968
1200
|
writeJsonAtomic(pluginActionReceiptPath(controllerHome, repository.repoId, receiptId), receipt);
|
|
@@ -982,7 +1214,8 @@ export async function submitAssistantPluginAction(
|
|
|
982
1214
|
deduplicated: false,
|
|
983
1215
|
result: resultWithLineage,
|
|
984
1216
|
receipt,
|
|
985
|
-
|
|
1217
|
+
authorization,
|
|
1218
|
+
workId: acceptedWork?.workId ?? boundRemoteWork?.workId ?? attributedWork?.workId,
|
|
986
1219
|
};
|
|
987
1220
|
} catch (error) {
|
|
988
1221
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -1018,8 +1251,15 @@ export async function submitAssistantPluginAction(
|
|
|
1018
1251
|
semanticKey: key,
|
|
1019
1252
|
status: 'failed',
|
|
1020
1253
|
createdAt,
|
|
1021
|
-
...(acceptedWork
|
|
1254
|
+
...(acceptedWork
|
|
1255
|
+
? { workId: acceptedWork.workId }
|
|
1256
|
+
: boundRemoteWork
|
|
1257
|
+
? { workId: boundRemoteWork.workId }
|
|
1258
|
+
: attributedWork
|
|
1259
|
+
? { workId: attributedWork.workId }
|
|
1260
|
+
: {}),
|
|
1022
1261
|
origin: request.origin,
|
|
1262
|
+
authorization,
|
|
1023
1263
|
error: { code, message },
|
|
1024
1264
|
};
|
|
1025
1265
|
writeJsonAtomic(pluginActionReceiptPath(controllerHome, repository.repoId, receiptId), receipt);
|
|
@@ -4,8 +4,24 @@ export type AssistantPluginLifecycleState = 'enabled' | 'disabled' | 'degraded'
|
|
|
4
4
|
export type AssistantPluginHealthState = 'ready' | 'disabled' | 'degraded' | 'error';
|
|
5
5
|
export type AssistantPluginActionRisk = 'readonly' | 'workspace_write' | 'remote_write' | 'destructive';
|
|
6
6
|
export type AssistantPluginActionConfirmation = 'none' | 'authorization' | 'strong_confirmation';
|
|
7
|
+
export type AssistantPluginForegroundEffect = 'none' | 'possible' | 'required';
|
|
7
8
|
export type AssistantPluginResource = 'repo-state' | 'workspace' | 'remote' | 'git-refs' | 'provider-state';
|
|
8
9
|
|
|
10
|
+
export interface AssistantPluginAuthorizationTarget {
|
|
11
|
+
/** Stable provider resource class, for example ios-physical-device. */
|
|
12
|
+
kind: string;
|
|
13
|
+
/** Stable exact provider identity. Ephemeral request/session ids must never be used here. */
|
|
14
|
+
id: string;
|
|
15
|
+
/** Optional provider identity fence. A changed fingerprint invalidates reuse. */
|
|
16
|
+
identityFingerprint?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AssistantPluginAuthorizationContext {
|
|
20
|
+
target: AssistantPluginAuthorizationTarget;
|
|
21
|
+
/** Optional grant lifetime. The grant authority applies its own upper bound. */
|
|
22
|
+
expiresInMinutes?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
9
25
|
export interface AssistantPluginPermissionScope {
|
|
10
26
|
scope: string;
|
|
11
27
|
mode: 'read' | 'write';
|
|
@@ -38,6 +54,14 @@ export interface AssistantPluginActionDescriptor {
|
|
|
38
54
|
defaultTimeoutMs: number;
|
|
39
55
|
cancellable: boolean;
|
|
40
56
|
idempotent: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Successful remote-write actions normally append a durable Work receipt only.
|
|
59
|
+
* Set terminal only when this action itself is authoritative semantic completion
|
|
60
|
+
* for a bound remote_effect Work.
|
|
61
|
+
*/
|
|
62
|
+
remoteEffectWorkCompletion?: 'intermediate' | 'terminal';
|
|
63
|
+
executionMode?: 'runtime' | 'lightweight_process';
|
|
64
|
+
foregroundEffect?: AssistantPluginForegroundEffect;
|
|
41
65
|
scopes: string[];
|
|
42
66
|
resourceClaims: AssistantPluginActionResourceClaim[];
|
|
43
67
|
argumentsSchema: Record<string, unknown>;
|
|
@@ -128,12 +152,21 @@ export interface AssistantPluginActionExecutionInput {
|
|
|
128
152
|
providerIdentityPrevalidated?: boolean;
|
|
129
153
|
}
|
|
130
154
|
|
|
131
|
-
export type AssistantPluginScope = 'repository' | 'controller';
|
|
155
|
+
export type AssistantPluginScope = 'repository' | 'controller' | 'controller_with_repository_overlay';
|
|
156
|
+
|
|
157
|
+
export interface AssistantPluginBuildContext {
|
|
158
|
+
controllerHome: string;
|
|
159
|
+
repoId: string;
|
|
160
|
+
repoRoot: string;
|
|
161
|
+
controllerScoped: boolean;
|
|
162
|
+
}
|
|
132
163
|
|
|
133
164
|
export interface AssistantPluginAdapter {
|
|
134
165
|
pluginId: string;
|
|
135
166
|
scope?: AssistantPluginScope;
|
|
136
|
-
buildManifest(previousRevision?: number, previousUpdatedAt?: string, repoRoot?: string): AssistantPluginManifest;
|
|
167
|
+
buildManifest(previousRevision?: number, previousUpdatedAt?: string, repoRoot?: string, context?: AssistantPluginBuildContext): AssistantPluginManifest;
|
|
168
|
+
/** Resolve an exact stable resource identity for reusable authorization-class actions. */
|
|
169
|
+
resolveAuthorizationContext?(input: AssistantPluginActionExecutionInput): Promise<AssistantPluginAuthorizationContext | undefined>;
|
|
137
170
|
executeAction(input: AssistantPluginActionExecutionInput): Promise<Record<string, unknown>>;
|
|
138
171
|
/** Defaults to true. External providers can defer routine health refresh until the normal manifest cache expires. */
|
|
139
172
|
shouldRefreshManifestAfterAction?(actionId: string): boolean;
|