@moretea-labs/forge 1.6.0 → 1.7.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 +4 -0
- package/CHANGELOG.md +39 -0
- package/CLAUDE.md +4 -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/02-operating-mode.partial.md +2 -0
- package/assets/partials-agents/03-orchestration.partial.md +1 -1
- package/assets/plugin-registry.v1.json +3 -3
- 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-architecture-sync.sh +17 -0
- 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/inspect-project-state.ts +8 -6
- package/assets/templates/helpers/migrate-project-template.sh +22 -45
- package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
- 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/helpers/workflow-contract.ts +5 -1
- 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 +178 -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-plugin-management.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 +143 -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 +33 -11
- package/scripts/activate-source-baseline.ts +17 -13
- package/scripts/architecture-event.ts +2 -820
- package/scripts/architecture-queue.sh +2 -645
- package/scripts/archive-architecture-request.sh +2 -242
- package/scripts/archive-workflow.sh +1 -291
- 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/capability-config.ts +2 -392
- package/scripts/capability-resolver.ts +2 -503
- package/scripts/capture-plan.sh +1 -332
- package/scripts/check-agent-tooling.sh +2 -1558
- package/scripts/check-architecture-sync.sh +2 -371
- package/scripts/check-brain-manifest.sh +2 -253
- package/scripts/check-context-files.sh +2 -47
- package/scripts/check-deploy-sql-order.sh +2 -115
- package/scripts/check-mcp-compatibility.ts +14 -0
- package/scripts/check-runtime-architecture.mjs +349 -79
- package/scripts/check-skill-version.ts +3 -191
- package/scripts/check-source-duplication.mjs +61 -0
- package/scripts/check-stable-baseline.ts +92 -0
- package/scripts/check-task-sync.sh +2 -63
- package/scripts/check-task-workflow.sh +2 -1000
- package/scripts/codex-handoff-resume.sh +2 -267
- package/scripts/context-contract-sync.sh +2 -514
- package/scripts/contract-run.ts +2 -463
- package/scripts/contract-worktree.sh +1 -722
- package/scripts/ensure-task-workflow.sh +1 -1225
- package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
- package/scripts/inspect-project-state.ts +4 -279
- package/scripts/install-standalone-recovery.ts +24 -0
- package/scripts/lib/project-init-lib.sh +22 -46
- package/scripts/lib/run-forge-helper.sh +19 -0
- package/scripts/lib/run-forge-helper.ts +26 -0
- package/scripts/migrate-project-template.sh +1 -1189
- package/scripts/migrate-workflow-docs.ts +4 -412
- package/scripts/new-plan.sh +1 -180
- package/scripts/new-spec.sh +1 -47
- package/scripts/new-sprint.sh +1 -46
- package/scripts/plan-to-todo.sh +1 -796
- package/scripts/prepare-codex-handoff.sh +2 -201
- package/scripts/prepare-handoff.sh +1 -78
- package/scripts/refresh-current-status.sh +2 -467
- package/scripts/run-governed-gate.ts +5 -1
- package/scripts/select-agent-context-blocks.sh +2 -64
- package/scripts/ship-worktrees.sh +1 -558
- package/scripts/smoke-ios-physical-device.ts +4 -2
- package/scripts/smoke-runtime-recovery.ts +1 -35
- package/scripts/smoke-schedule-engine.ts +1 -20
- package/scripts/sprint-backlog.sh +1 -834
- package/scripts/stage-runtime-release.ts +2 -1
- package/scripts/summarize-failures.sh +2 -123
- package/scripts/switch-plan.sh +1 -150
- package/scripts/sync-brain-docs.sh +2 -379
- package/scripts/sync-generated-authority.mjs +175 -0
- package/scripts/verify-contract.sh +2 -703
- package/scripts/verify-forge-runtime.sh +0 -1
- package/scripts/verify-sprint.sh +1 -677
- package/scripts/workflow-contract.ts +4 -205
- package/scripts/workstream-sync.sh +2 -261
- package/src/cli/agent-jobs/executor-health.ts +1 -1
- package/src/cli/commands/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +12 -3
- 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 +113 -5
- 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 +828 -487
- 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/contracts.ts +16 -0
- package/src/cli/github/github.ts +135 -16
- package/src/cli/github/session.ts +2 -1
- 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 +37 -264
- 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 +2 -515
- 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 +10 -222
- package/src/cli/mcp/multi-repository.ts +16 -5
- package/src/cli/mcp/oauth.ts +175 -26
- package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
- package/src/cli/mcp/repository-tools.ts +282 -146
- package/src/cli/mcp/server.ts +586 -116
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/tool-contract.ts +14 -0
- package/src/cli/mcp/toolset-selection.ts +1 -1
- package/src/cli/mcp/toolset.ts +44 -7
- package/src/cli/mcp/transports/http.ts +124 -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 +103 -21
- package/src/cli/repositories/command-executor.ts +78 -526
- 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 +124 -0
- package/src/cli/repositories/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +118 -6
- package/src/cli/repository/inspector.ts +563 -65
- 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-contract.ts +61 -0
- package/src/runtime/context/semantic-navigation.ts +223 -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 +48 -16
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
- package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
- 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-completion-authority.ts +58 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
- package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
- package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
- package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
- 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-operation-service.ts +468 -0
- package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
- package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
- package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +22 -18
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +156 -11
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
- package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
- package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +90 -9
- package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
- package/src/runtime/control-plane/facade/controller-round-relay.ts +1118 -0
- package/src/runtime/control-plane/facade/controller-session-store.ts +302 -12
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +17 -1
- package/src/runtime/control-plane/facade/goal-workloop.ts +928 -190
- package/src/runtime/control-plane/facade/index.ts +3 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +275 -42
- package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
- package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
- 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 +90 -10
- package/src/runtime/control-plane/facade/work-contract-store.ts +157 -261
- package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
- 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 +152 -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 +278 -543
- 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 +63 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +365 -117
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +89 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +244 -11
- package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
- 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/repo-actor/registry.ts +4 -2
- package/src/runtime/control-plane/routing/route-policy.ts +24 -21
- package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
- 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/evidence/process-check-execution.ts +18 -0
- package/src/runtime/execution/jobs/child-reference.ts +6 -2
- 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 +88 -0
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +367 -40
- package/src/runtime/execution/process-runtime/gc.ts +38 -6
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1201 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +51 -5
- package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
- package/src/runtime/execution/process-runtime/runtime.ts +53 -3
- package/src/runtime/execution/process-runtime/store.ts +1 -0
- package/src/runtime/execution/process-runtime/types.ts +4 -12
- 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/work-activity.ts +21 -0
- package/src/runtime/execution/workers/executor.ts +18 -61
- package/src/runtime/gateway/mcp/execution-tools.ts +35 -1852
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +186 -84
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +565 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2378 -1947
- package/src/runtime/plugins/app-store-connect-adapter.ts +216 -47
- package/src/runtime/plugins/browser-adapter.ts +2662 -829
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff-host.ts +2 -25
- package/src/runtime/plugins/browser-handoff.ts +110 -5
- package/src/runtime/plugins/browser-macos-bridge.ts +701 -63
- package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
- package/src/runtime/plugins/browser-native-session-service.ts +222 -0
- 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 +154 -0
- package/src/runtime/plugins/browser-runtime.ts +193 -0
- package/src/runtime/plugins/browser-session-authority.ts +332 -0
- package/src/runtime/plugins/browser-session-store.ts +121 -0
- package/src/runtime/plugins/browser-session-types.ts +98 -0
- package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +10 -4
- package/src/runtime/plugins/external-adapter.ts +358 -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 +47 -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 +330 -33
- package/src/runtime/plugins/types.ts +38 -3
- 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 +426 -25
- package/src/runtime/root/mcp-transport.ts +180 -10
- package/src/runtime/root/package-connector-service.ts +230 -10
- package/src/runtime/root/package-runtime-release.ts +143 -17
- package/src/runtime/root/package-runtime-service.ts +461 -22
- package/src/runtime/root/release-manifest.ts +144 -18
- package/src/runtime/root/release-materialize.ts +125 -32
- 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 +12 -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 +1079 -240
- package/src/runtime/standalone-recovery/entry.ts +100 -24
- package/src/runtime/standalone-recovery/installer.ts +20 -4
- 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 +364 -202
- package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
- package/src/runtime/workflow/schedules/settlement.ts +64 -17
- package/src/runtime/workflow/schedules/store.ts +209 -19
- 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)
|
|
@@ -537,6 +598,8 @@ export interface PluginActionReceipt {
|
|
|
537
598
|
receiptId: string;
|
|
538
599
|
requestId: string;
|
|
539
600
|
repoId: string;
|
|
601
|
+
/** Work authority repository when it differs from controller/provider receipt scope. */
|
|
602
|
+
workRepoId?: string;
|
|
540
603
|
pluginId: string;
|
|
541
604
|
actionId: string;
|
|
542
605
|
semanticKey: string;
|
|
@@ -544,6 +607,7 @@ export interface PluginActionReceipt {
|
|
|
544
607
|
createdAt: string;
|
|
545
608
|
workId?: string;
|
|
546
609
|
origin?: { surface: string; actor?: string; correlationId?: string };
|
|
610
|
+
authorization?: PluginActionAuthorizationEvidence;
|
|
547
611
|
result?: Record<string, unknown>;
|
|
548
612
|
error?: { code: string; message: string };
|
|
549
613
|
}
|
|
@@ -551,6 +615,7 @@ export interface PluginActionReceipt {
|
|
|
551
615
|
interface PluginActionRequestIndex {
|
|
552
616
|
requestId: string;
|
|
553
617
|
repoId: string;
|
|
618
|
+
workRepoId?: string;
|
|
554
619
|
receiptId: string;
|
|
555
620
|
semanticKey: string;
|
|
556
621
|
createdAt: string;
|
|
@@ -671,6 +736,15 @@ function localEffectTarget(
|
|
|
671
736
|
};
|
|
672
737
|
}
|
|
673
738
|
|
|
739
|
+
function workAttributionRepoId(repository: RepositoryRecord, request: AssistantPluginActionRequest): string {
|
|
740
|
+
const explicit = request.workRepoId?.trim();
|
|
741
|
+
if (!request.workId?.trim()) {
|
|
742
|
+
if (explicit) throw new Error(`WORK_PLUGIN_ATTRIBUTION_REPO_WITHOUT_WORK: ${explicit}`);
|
|
743
|
+
return repository.repoId;
|
|
744
|
+
}
|
|
745
|
+
return explicit || repository.repoId;
|
|
746
|
+
}
|
|
747
|
+
|
|
674
748
|
function remoteEffectWorkForPluginAction(
|
|
675
749
|
controllerHome: string,
|
|
676
750
|
repository: RepositoryRecord,
|
|
@@ -683,7 +757,8 @@ function remoteEffectWorkForPluginAction(
|
|
|
683
757
|
if (action.risk !== 'remote_write') {
|
|
684
758
|
throw new Error(`WORK_PLUGIN_RECEIPT_BINDING_REQUIRES_REMOTE_WRITE: ${action.actionId}`);
|
|
685
759
|
}
|
|
686
|
-
const
|
|
760
|
+
const workRepoId = workAttributionRepoId(repository, request);
|
|
761
|
+
const work = getWorkContract({ controllerHome, repoId: workRepoId }, workId);
|
|
687
762
|
if (!work) throw new Error(`WORK_PLUGIN_RECEIPT_BINDING_NOT_FOUND: ${workId}`);
|
|
688
763
|
if (work.workKind !== 'remote_effect') {
|
|
689
764
|
throw new Error(`WORK_PLUGIN_RECEIPT_BINDING_KIND_MISMATCH: ${workId} is ${work.workKind}, expected remote_effect`);
|
|
@@ -692,12 +767,101 @@ function remoteEffectWorkForPluginAction(
|
|
|
692
767
|
throw new Error(`WORK_PLUGIN_RECEIPT_BINDING_CHECKS_PRESENT: ${workId} declares repository checks and cannot be completed by a plugin receipt alone`);
|
|
693
768
|
}
|
|
694
769
|
if (isTerminalWorkContractStatus(work.status)) {
|
|
695
|
-
|
|
770
|
+
const receiptAlreadyBound = Boolean(receiptId) && (
|
|
771
|
+
work.completionReceipt?.receiptId === receiptId
|
|
772
|
+
|| work.evidenceRefs.some((evidence) => evidence.evidenceId === receiptId)
|
|
773
|
+
);
|
|
774
|
+
if (work.status === 'completed' && receiptAlreadyBound) return work;
|
|
696
775
|
throw new Error(`WORK_PLUGIN_RECEIPT_BINDING_TERMINAL: ${workId} is ${work.status}`);
|
|
697
776
|
}
|
|
698
777
|
return work;
|
|
699
778
|
}
|
|
700
779
|
|
|
780
|
+
function attributedWorkForPluginAction(
|
|
781
|
+
controllerHome: string,
|
|
782
|
+
repository: RepositoryRecord,
|
|
783
|
+
action: AssistantPluginActionDescriptor,
|
|
784
|
+
request: AssistantPluginActionRequest,
|
|
785
|
+
): WorkContract | undefined {
|
|
786
|
+
const workId = request.workId?.trim();
|
|
787
|
+
if (!workId || action.risk === 'remote_write') return undefined;
|
|
788
|
+
const workRepoId = workAttributionRepoId(repository, request);
|
|
789
|
+
const work = getWorkContract({ controllerHome, repoId: workRepoId }, workId);
|
|
790
|
+
if (!work) throw new Error(`WORK_PLUGIN_ATTRIBUTION_NOT_FOUND: ${workRepoId}:${workId}`);
|
|
791
|
+
if (isTerminalWorkContractStatus(work.status)) {
|
|
792
|
+
throw new Error(`WORK_PLUGIN_ATTRIBUTION_TERMINAL: ${workId} is ${work.status}`);
|
|
793
|
+
}
|
|
794
|
+
return work;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
function bindLocalEffectReceiptToAttributedWork(
|
|
798
|
+
controllerHome: string,
|
|
799
|
+
repository: RepositoryRecord,
|
|
800
|
+
action: AssistantPluginActionDescriptor,
|
|
801
|
+
request: AssistantPluginActionRequest,
|
|
802
|
+
receipt: PluginActionReceipt,
|
|
803
|
+
work?: WorkContract,
|
|
804
|
+
): WorkContract | undefined {
|
|
805
|
+
if (!request.workId || receipt.status !== 'succeeded') return work;
|
|
806
|
+
const workRepoId = workAttributionRepoId(repository, request);
|
|
807
|
+
const attributed = work ?? getWorkContract({ controllerHome, repoId: workRepoId }, request.workId.trim());
|
|
808
|
+
if (!attributed) throw new Error(`WORK_PLUGIN_ATTRIBUTION_NOT_FOUND: ${workRepoId}:${request.workId.trim()}`);
|
|
809
|
+
if (attributed.workKind !== 'local_effect' || action.readOnly || action.risk === 'readonly') return attributed;
|
|
810
|
+
if (attributed.evidenceRefs.some((evidence) => evidence.evidenceId === receipt.receiptId)) return attributed;
|
|
811
|
+
if (isTerminalWorkContractStatus(attributed.status)) return attributed;
|
|
812
|
+
return appendWorkEvidence({ controllerHome, repoId: workRepoId }, attributed.workId, {
|
|
813
|
+
evidenceId: receipt.receiptId,
|
|
814
|
+
title: 'typed local plugin effect completed',
|
|
815
|
+
summary: `${receipt.pluginId}/${receipt.actionId} completed with durable receipt ${receipt.receiptId}.`,
|
|
816
|
+
detailLevel: 'summary',
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
export function finalizeRemoteEffectWorkFromActionReceipt(
|
|
821
|
+
controllerHome: string,
|
|
822
|
+
repoId: string,
|
|
823
|
+
workId: string,
|
|
824
|
+
): WorkContract {
|
|
825
|
+
const work = getWorkContract({ controllerHome, repoId }, workId);
|
|
826
|
+
if (!work) throw new Error(`WORK_PLUGIN_RECEIPT_BINDING_NOT_FOUND: ${workId}`);
|
|
827
|
+
if (work.workKind !== 'remote_effect') {
|
|
828
|
+
throw new Error(`WORK_REMOTE_EFFECT_FINALIZE_KIND_MISMATCH: ${workId} is ${work.workKind}, expected remote_effect`);
|
|
829
|
+
}
|
|
830
|
+
if (work.status === 'completed' && work.completionReceipt?.source === 'remote_effect') return work;
|
|
831
|
+
if (isTerminalWorkContractStatus(work.status)) {
|
|
832
|
+
throw new Error(`WORK_REMOTE_EFFECT_FINALIZE_TERMINAL: ${workId} is ${work.status}`);
|
|
833
|
+
}
|
|
834
|
+
const receipt = work.evidenceRefs
|
|
835
|
+
.map((evidence) => {
|
|
836
|
+
if (!evidence.evidenceId) return undefined;
|
|
837
|
+
return readPluginActionReceipt(controllerHome, repoId, evidence.evidenceId)
|
|
838
|
+
?? readPluginActionReceipt(controllerHome, CONTROLLER_SCOPE_REPO_ID, evidence.evidenceId);
|
|
839
|
+
})
|
|
840
|
+
.find((candidate) => candidate?.workId === workId && candidate.status === 'succeeded');
|
|
841
|
+
if (!receipt) {
|
|
842
|
+
throw new Error(`WORK_REMOTE_EFFECT_FINALIZE_RECEIPT_REQUIRED: ${workId} has no successful durable plugin action receipt`);
|
|
843
|
+
}
|
|
844
|
+
const remoteReceipt: RemoteEffectCompletionReceipt = {
|
|
845
|
+
schemaVersion: 1,
|
|
846
|
+
receiptId: receipt.receiptId,
|
|
847
|
+
source: 'remote_effect',
|
|
848
|
+
workId,
|
|
849
|
+
pluginId: receipt.pluginId,
|
|
850
|
+
actionId: receipt.actionId,
|
|
851
|
+
requestId: receipt.requestId,
|
|
852
|
+
semanticKey: receipt.semanticKey,
|
|
853
|
+
resultDigest: createHash('sha256').update(JSON.stringify(receipt.result ?? null)).digest('hex'),
|
|
854
|
+
recordedAt: new Date().toISOString(),
|
|
855
|
+
};
|
|
856
|
+
return recordWorkCompletionReceipt(
|
|
857
|
+
{ controllerHome, repoId },
|
|
858
|
+
workId,
|
|
859
|
+
remoteReceipt,
|
|
860
|
+
'completed_remote',
|
|
861
|
+
'remote_effect',
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
|
|
701
865
|
function bindRemoteEffectReceiptToWork(
|
|
702
866
|
controllerHome: string,
|
|
703
867
|
repository: RepositoryRecord,
|
|
@@ -709,15 +873,18 @@ function bindRemoteEffectReceiptToWork(
|
|
|
709
873
|
if (receipt.status !== 'succeeded') return remoteEffectWorkForPluginAction(controllerHome, repository, action, request);
|
|
710
874
|
const work = remoteEffectWorkForPluginAction(controllerHome, repository, action, request, receipt.receiptId);
|
|
711
875
|
if (!work) return undefined;
|
|
712
|
-
if (work.status === 'completed'
|
|
876
|
+
if (work.status === 'completed') return work;
|
|
877
|
+
const workRepoId = workAttributionRepoId(repository, request);
|
|
878
|
+
let updated = work;
|
|
713
879
|
if (!work.evidenceRefs.some((evidence) => evidence.evidenceId === receipt.receiptId)) {
|
|
714
|
-
appendWorkEvidence({ controllerHome, repoId:
|
|
880
|
+
updated = appendWorkEvidence({ controllerHome, repoId: workRepoId }, work.workId, {
|
|
715
881
|
evidenceId: receipt.receiptId,
|
|
716
882
|
title: 'typed remote plugin effect completed',
|
|
717
883
|
summary: `${receipt.pluginId}/${receipt.actionId} completed with durable receipt ${receipt.receiptId}.`,
|
|
718
884
|
detailLevel: 'summary',
|
|
719
885
|
});
|
|
720
886
|
}
|
|
887
|
+
if (action.remoteEffectWorkCompletion !== 'terminal') return updated;
|
|
721
888
|
const remoteReceipt: RemoteEffectCompletionReceipt = {
|
|
722
889
|
schemaVersion: 1,
|
|
723
890
|
receiptId: receipt.receiptId,
|
|
@@ -731,7 +898,7 @@ function bindRemoteEffectReceiptToWork(
|
|
|
731
898
|
recordedAt: new Date().toISOString(),
|
|
732
899
|
};
|
|
733
900
|
return recordWorkCompletionReceipt(
|
|
734
|
-
{ controllerHome, repoId:
|
|
901
|
+
{ controllerHome, repoId: workRepoId },
|
|
735
902
|
work.workId,
|
|
736
903
|
remoteReceipt,
|
|
737
904
|
'completed_remote',
|
|
@@ -785,8 +952,11 @@ export async function submitAssistantPluginAction(
|
|
|
785
952
|
deduplicated: boolean;
|
|
786
953
|
result?: Record<string, unknown>;
|
|
787
954
|
receipt: PluginActionReceipt;
|
|
955
|
+
authorization?: PluginActionAuthorizationEvidence;
|
|
788
956
|
workId?: string;
|
|
789
957
|
}> {
|
|
958
|
+
const adapter = resolvePluginAdapter(controllerHome, request.pluginId);
|
|
959
|
+
if (!adapter) throw new Error(`PLUGIN_NOT_FOUND: ${request.pluginId}`);
|
|
790
960
|
const manifest = getAssistantPluginManifest(controllerHome, repository, request.pluginId);
|
|
791
961
|
const action = actionForManifest(manifest, request.actionId);
|
|
792
962
|
if (!manifest.enabled && action.actionId !== 'configure') {
|
|
@@ -812,7 +982,15 @@ export async function submitAssistantPluginAction(
|
|
|
812
982
|
if (request.workId && existing.workId !== request.workId) {
|
|
813
983
|
throw new Error(`WORK_PLUGIN_RECEIPT_BINDING_CONFLICT: ${request.requestId} already belongs to Work ${existing.workId ?? 'none'}`);
|
|
814
984
|
}
|
|
815
|
-
|
|
985
|
+
const requestedWorkRepoId = request.workId ? workAttributionRepoId(repository, request) : undefined;
|
|
986
|
+
if (requestedWorkRepoId && (index.workRepoId ?? index.repoId) !== requestedWorkRepoId) {
|
|
987
|
+
throw new Error(`WORK_PLUGIN_ATTRIBUTION_REPO_CONFLICT: ${request.requestId} already belongs to Work repository ${index.workRepoId ?? index.repoId}`);
|
|
988
|
+
}
|
|
989
|
+
if (request.workId && action.risk === 'remote_write') {
|
|
990
|
+
bindRemoteEffectReceiptToWork(controllerHome, repository, action, request, existing);
|
|
991
|
+
} else if (request.workId) {
|
|
992
|
+
bindLocalEffectReceiptToAttributedWork(controllerHome, repository, action, request, existing);
|
|
993
|
+
}
|
|
816
994
|
return {
|
|
817
995
|
manifest,
|
|
818
996
|
action,
|
|
@@ -820,19 +998,29 @@ export async function submitAssistantPluginAction(
|
|
|
820
998
|
deduplicated: true,
|
|
821
999
|
result: existing.result,
|
|
822
1000
|
receipt: existing,
|
|
1001
|
+
authorization: existing.authorization,
|
|
823
1002
|
workId: existing.workId,
|
|
824
1003
|
};
|
|
825
1004
|
}
|
|
826
1005
|
|
|
827
1006
|
const createdAt = new Date().toISOString();
|
|
828
1007
|
const receiptId = `PLG-${Date.now()}-${createHash('sha256').update(request.requestId).digest('hex').slice(0, 8)}`;
|
|
829
|
-
const
|
|
1008
|
+
const capabilityId = reusableCapabilityId(manifest, action);
|
|
1009
|
+
let authorization = initialAuthorizationEvidence(manifest, action);
|
|
1010
|
+
let authorizationContext: AssistantPluginAuthorizationContext | undefined;
|
|
1011
|
+
let activeAuthorizationGrant: PluginCapabilityAuthorizationGrant | undefined;
|
|
830
1012
|
const requiresLocalEffectWork = localSystemActionRequiresWork(
|
|
831
1013
|
repository,
|
|
832
1014
|
request.pluginId,
|
|
833
1015
|
request.actionId,
|
|
834
1016
|
normalizedArgs,
|
|
835
1017
|
);
|
|
1018
|
+
const boundRemoteWork = action.risk === 'remote_write'
|
|
1019
|
+
? remoteEffectWorkForPluginAction(controllerHome, repository, action, request)
|
|
1020
|
+
: undefined;
|
|
1021
|
+
const attributedWork = !requiresLocalEffectWork
|
|
1022
|
+
? attributedWorkForPluginAction(controllerHome, repository, action, request)
|
|
1023
|
+
: undefined;
|
|
836
1024
|
const acceptedWork = requiresLocalEffectWork
|
|
837
1025
|
? acceptSubmittedWorkContract(controllerHome, {
|
|
838
1026
|
requestId: request.requestId,
|
|
@@ -885,10 +1073,63 @@ export async function submitAssistantPluginAction(
|
|
|
885
1073
|
receiptId,
|
|
886
1074
|
risk: action.risk,
|
|
887
1075
|
confirmation: action.confirmation,
|
|
1076
|
+
capabilityId,
|
|
1077
|
+
authorizationReuseSupported: action.confirmation === 'authorization' && Boolean(adapter.resolveAuthorizationContext),
|
|
888
1078
|
},
|
|
889
1079
|
});
|
|
890
1080
|
|
|
891
1081
|
try {
|
|
1082
|
+
if (action.confirmation === 'authorization'
|
|
1083
|
+
&& adapter.resolveAuthorizationContext
|
|
1084
|
+
&& originMayEstablishCapabilityAuthorization(request.origin)) {
|
|
1085
|
+
authorizationContext = await adapter.resolveAuthorizationContext({
|
|
1086
|
+
controllerHome,
|
|
1087
|
+
repoId: repository.repoId,
|
|
1088
|
+
repoRoot: repository.canonicalRoot,
|
|
1089
|
+
pluginId: request.pluginId,
|
|
1090
|
+
actionId: request.actionId,
|
|
1091
|
+
requestId: request.requestId,
|
|
1092
|
+
args: normalizedArgs,
|
|
1093
|
+
origin: request.origin,
|
|
1094
|
+
jobId: receiptId,
|
|
1095
|
+
timeoutMs: request.timeoutMs,
|
|
1096
|
+
signal: request.signal,
|
|
1097
|
+
});
|
|
1098
|
+
if (authorizationContext) {
|
|
1099
|
+
authorization = {
|
|
1100
|
+
source: 'host_permission_model',
|
|
1101
|
+
reusable: false,
|
|
1102
|
+
capabilityId,
|
|
1103
|
+
target: authorizationTargetSummary(authorizationContext),
|
|
1104
|
+
};
|
|
1105
|
+
try {
|
|
1106
|
+
activeAuthorizationGrant = findActivePluginCapabilityAuthorization(controllerHome, {
|
|
1107
|
+
ownerScope: pluginCapabilityAuthorizationOwnerScope(request.origin),
|
|
1108
|
+
repoId: repository.repoId,
|
|
1109
|
+
pluginId: request.pluginId,
|
|
1110
|
+
capabilityId,
|
|
1111
|
+
target: authorizationContext.target,
|
|
1112
|
+
scopes: action.scopes,
|
|
1113
|
+
risk: action.risk,
|
|
1114
|
+
});
|
|
1115
|
+
if (activeAuthorizationGrant) {
|
|
1116
|
+
authorization = {
|
|
1117
|
+
source: 'capability_grant',
|
|
1118
|
+
reusable: true,
|
|
1119
|
+
capabilityId,
|
|
1120
|
+
target: authorizationTargetSummary(authorizationContext),
|
|
1121
|
+
grantId: activeAuthorizationGrant.grantId,
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
} catch (error) {
|
|
1125
|
+
authorization = {
|
|
1126
|
+
...authorization,
|
|
1127
|
+
lookupError: authorizationError(error),
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
|
|
892
1133
|
const result = await executeAssistantPluginAction({
|
|
893
1134
|
controllerHome,
|
|
894
1135
|
repoId: repository.repoId,
|
|
@@ -905,15 +1146,49 @@ export async function submitAssistantPluginAction(
|
|
|
905
1146
|
? Date.now() + Math.max(1, Math.trunc(request.timeoutMs))
|
|
906
1147
|
: undefined,
|
|
907
1148
|
});
|
|
1149
|
+
if (action.confirmation === 'authorization'
|
|
1150
|
+
&& authorizationContext
|
|
1151
|
+
&& !activeAuthorizationGrant
|
|
1152
|
+
&& originMayEstablishCapabilityAuthorization(request.origin)) {
|
|
1153
|
+
try {
|
|
1154
|
+
const grant = recordPluginCapabilityAuthorization(controllerHome, {
|
|
1155
|
+
ownerScope: pluginCapabilityAuthorizationOwnerScope(request.origin),
|
|
1156
|
+
repoId: repository.repoId,
|
|
1157
|
+
pluginId: request.pluginId,
|
|
1158
|
+
capabilityId,
|
|
1159
|
+
target: authorizationContext.target,
|
|
1160
|
+
scopes: action.scopes,
|
|
1161
|
+
riskCeiling: action.risk,
|
|
1162
|
+
expiresInMinutes: authorizationContext.expiresInMinutes,
|
|
1163
|
+
});
|
|
1164
|
+
authorization = {
|
|
1165
|
+
source: 'host_permission_model',
|
|
1166
|
+
reusable: true,
|
|
1167
|
+
capabilityId,
|
|
1168
|
+
target: authorizationTargetSummary(authorizationContext),
|
|
1169
|
+
grantId: grant.grantId,
|
|
1170
|
+
established: true,
|
|
1171
|
+
...(authorization.lookupError ? { lookupError: authorization.lookupError } : {}),
|
|
1172
|
+
};
|
|
1173
|
+
} catch (error) {
|
|
1174
|
+
authorization = {
|
|
1175
|
+
...authorization,
|
|
1176
|
+
reusable: false,
|
|
1177
|
+
persistenceError: authorizationError(error),
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
908
1182
|
let resultWithLineage = result;
|
|
909
1183
|
if (boundRemoteWork) {
|
|
1184
|
+
const terminalRemoteEffect = action.remoteEffectWorkCompletion === 'terminal';
|
|
910
1185
|
resultWithLineage = {
|
|
911
1186
|
...result,
|
|
912
1187
|
work: {
|
|
913
1188
|
workId: boundRemoteWork.workId,
|
|
914
1189
|
workKind: 'remote_effect',
|
|
915
|
-
completionOutcome: 'completed_remote',
|
|
916
|
-
status: 'completed',
|
|
1190
|
+
...(terminalRemoteEffect ? { completionOutcome: 'completed_remote' as const } : {}),
|
|
1191
|
+
status: terminalRemoteEffect ? 'completed' : 'running',
|
|
917
1192
|
},
|
|
918
1193
|
};
|
|
919
1194
|
}
|
|
@@ -956,24 +1231,37 @@ export async function submitAssistantPluginAction(
|
|
|
956
1231
|
receiptId,
|
|
957
1232
|
requestId: request.requestId,
|
|
958
1233
|
repoId: repository.repoId,
|
|
1234
|
+
...(request.workId ? { workRepoId: workAttributionRepoId(repository, request) } : {}),
|
|
959
1235
|
pluginId: request.pluginId,
|
|
960
1236
|
actionId: request.actionId,
|
|
961
1237
|
semanticKey: key,
|
|
962
1238
|
status: 'succeeded',
|
|
963
1239
|
createdAt,
|
|
964
|
-
...(acceptedWork
|
|
1240
|
+
...(acceptedWork
|
|
1241
|
+
? { workId: acceptedWork.workId }
|
|
1242
|
+
: boundRemoteWork
|
|
1243
|
+
? { workId: boundRemoteWork.workId }
|
|
1244
|
+
: attributedWork
|
|
1245
|
+
? { workId: attributedWork.workId }
|
|
1246
|
+
: {}),
|
|
965
1247
|
origin: request.origin,
|
|
1248
|
+
authorization,
|
|
966
1249
|
result: resultWithLineage,
|
|
967
1250
|
};
|
|
968
1251
|
writeJsonAtomic(pluginActionReceiptPath(controllerHome, repository.repoId, receiptId), receipt);
|
|
969
1252
|
writeJsonAtomic(requestPath, {
|
|
970
1253
|
requestId: request.requestId,
|
|
971
1254
|
repoId: repository.repoId,
|
|
1255
|
+
...(request.workId ? { workRepoId: workAttributionRepoId(repository, request) } : {}),
|
|
972
1256
|
receiptId,
|
|
973
1257
|
semanticKey: key,
|
|
974
1258
|
createdAt,
|
|
975
1259
|
} satisfies PluginActionRequestIndex);
|
|
976
|
-
if (boundRemoteWork)
|
|
1260
|
+
if (boundRemoteWork) {
|
|
1261
|
+
bindRemoteEffectReceiptToWork(controllerHome, repository, action, request, receipt);
|
|
1262
|
+
} else if (attributedWork) {
|
|
1263
|
+
bindLocalEffectReceiptToAttributedWork(controllerHome, repository, action, request, receipt, attributedWork);
|
|
1264
|
+
}
|
|
977
1265
|
const nextManifest = getAssistantPluginManifest(controllerHome, repository, request.pluginId);
|
|
978
1266
|
return {
|
|
979
1267
|
manifest: nextManifest,
|
|
@@ -982,13 +1270,14 @@ export async function submitAssistantPluginAction(
|
|
|
982
1270
|
deduplicated: false,
|
|
983
1271
|
result: resultWithLineage,
|
|
984
1272
|
receipt,
|
|
985
|
-
|
|
1273
|
+
authorization,
|
|
1274
|
+
workId: acceptedWork?.workId ?? boundRemoteWork?.workId ?? attributedWork?.workId,
|
|
986
1275
|
};
|
|
987
1276
|
} catch (error) {
|
|
988
1277
|
const message = error instanceof Error ? error.message : String(error);
|
|
989
1278
|
const code = /^([A-Z][A-Z0-9_]+)/.exec(message)?.[1] ?? 'PLUGIN_ACTION_FAILED';
|
|
990
1279
|
if (boundRemoteWork) {
|
|
991
|
-
appendWorkEvidence({ controllerHome, repoId: repository
|
|
1280
|
+
appendWorkEvidence({ controllerHome, repoId: workAttributionRepoId(repository, request) }, boundRemoteWork.workId, {
|
|
992
1281
|
title: 'typed remote plugin effect failed',
|
|
993
1282
|
summary: `${request.pluginId}/${request.actionId}: ${message}`.slice(0, 1_000),
|
|
994
1283
|
detailLevel: 'summary',
|
|
@@ -1013,13 +1302,21 @@ export async function submitAssistantPluginAction(
|
|
|
1013
1302
|
receiptId,
|
|
1014
1303
|
requestId: request.requestId,
|
|
1015
1304
|
repoId: repository.repoId,
|
|
1305
|
+
...(request.workId ? { workRepoId: workAttributionRepoId(repository, request) } : {}),
|
|
1016
1306
|
pluginId: request.pluginId,
|
|
1017
1307
|
actionId: request.actionId,
|
|
1018
1308
|
semanticKey: key,
|
|
1019
1309
|
status: 'failed',
|
|
1020
1310
|
createdAt,
|
|
1021
|
-
...(acceptedWork
|
|
1311
|
+
...(acceptedWork
|
|
1312
|
+
? { workId: acceptedWork.workId }
|
|
1313
|
+
: boundRemoteWork
|
|
1314
|
+
? { workId: boundRemoteWork.workId }
|
|
1315
|
+
: attributedWork
|
|
1316
|
+
? { workId: attributedWork.workId }
|
|
1317
|
+
: {}),
|
|
1022
1318
|
origin: request.origin,
|
|
1319
|
+
authorization,
|
|
1023
1320
|
error: { code, message },
|
|
1024
1321
|
};
|
|
1025
1322
|
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>;
|
|
@@ -100,8 +124,10 @@ export interface AssistantPluginActionRequest {
|
|
|
100
124
|
pluginId: string;
|
|
101
125
|
actionId: string;
|
|
102
126
|
requestId: string;
|
|
103
|
-
/** Optional existing
|
|
127
|
+
/** Optional existing Work that owns this typed action receipt. */
|
|
104
128
|
workId?: string;
|
|
129
|
+
/** Durable repository authority for workId. May differ from provider scope for controller-scoped plugins. */
|
|
130
|
+
workRepoId?: string;
|
|
105
131
|
args: Record<string, unknown>;
|
|
106
132
|
timeoutMs?: number;
|
|
107
133
|
signal?: AbortSignal;
|
|
@@ -128,12 +154,21 @@ export interface AssistantPluginActionExecutionInput {
|
|
|
128
154
|
providerIdentityPrevalidated?: boolean;
|
|
129
155
|
}
|
|
130
156
|
|
|
131
|
-
export type AssistantPluginScope = 'repository' | 'controller';
|
|
157
|
+
export type AssistantPluginScope = 'repository' | 'controller' | 'controller_with_repository_overlay';
|
|
158
|
+
|
|
159
|
+
export interface AssistantPluginBuildContext {
|
|
160
|
+
controllerHome: string;
|
|
161
|
+
repoId: string;
|
|
162
|
+
repoRoot: string;
|
|
163
|
+
controllerScoped: boolean;
|
|
164
|
+
}
|
|
132
165
|
|
|
133
166
|
export interface AssistantPluginAdapter {
|
|
134
167
|
pluginId: string;
|
|
135
168
|
scope?: AssistantPluginScope;
|
|
136
|
-
buildManifest(previousRevision?: number, previousUpdatedAt?: string, repoRoot?: string): AssistantPluginManifest;
|
|
169
|
+
buildManifest(previousRevision?: number, previousUpdatedAt?: string, repoRoot?: string, context?: AssistantPluginBuildContext): AssistantPluginManifest;
|
|
170
|
+
/** Resolve an exact stable resource identity for reusable authorization-class actions. */
|
|
171
|
+
resolveAuthorizationContext?(input: AssistantPluginActionExecutionInput): Promise<AssistantPluginAuthorizationContext | undefined>;
|
|
137
172
|
executeAction(input: AssistantPluginActionExecutionInput): Promise<Record<string, unknown>>;
|
|
138
173
|
/** Defaults to true. External providers can defer routine health refresh until the normal manifest cache expires. */
|
|
139
174
|
shouldRefreshManifestAfterAction?(actionId: string): boolean;
|