@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
|
@@ -68,7 +68,7 @@ function desktopOperatorActions(): AssistantPluginActionDescriptor[] {
|
|
|
68
68
|
{
|
|
69
69
|
actionId: 'desktop_session_open',
|
|
70
70
|
title: 'Open desktop session',
|
|
71
|
-
description: 'Launch or locate one application
|
|
71
|
+
description: 'Launch or locate one application and create a bounded interaction session; stays in the background by default, or explicitly activates the target when activate=true.',
|
|
72
72
|
readOnly: false,
|
|
73
73
|
risk: 'workspace_write',
|
|
74
74
|
confirmation: 'authorization',
|
|
@@ -83,6 +83,7 @@ function desktopOperatorActions(): AssistantPluginActionDescriptor[] {
|
|
|
83
83
|
bundle_id: { type: 'string' },
|
|
84
84
|
app_name: { type: 'string' },
|
|
85
85
|
launch: { type: 'boolean' },
|
|
86
|
+
activate: { type: 'boolean', description: 'Explicitly activate the target application after launch/lookup. Defaults to false.' },
|
|
86
87
|
},
|
|
87
88
|
anyOf: [{ required: ['bundle_id'] }, { required: ['app_name'] }],
|
|
88
89
|
additionalProperties: false,
|
|
@@ -132,6 +133,11 @@ function desktopOperatorActions(): AssistantPluginActionDescriptor[] {
|
|
|
132
133
|
properties: {
|
|
133
134
|
interaction_id: { type: 'string' },
|
|
134
135
|
selector: SELECTOR_SCHEMA,
|
|
136
|
+
semantic_action: {
|
|
137
|
+
type: 'string',
|
|
138
|
+
enum: ['press', 'show_menu', 'pick', 'open', 'confirm'],
|
|
139
|
+
description: 'Bounded Accessibility action supported by the trusted Desktop Operator provider; defaults to press when omitted.',
|
|
140
|
+
},
|
|
135
141
|
},
|
|
136
142
|
required: ['interaction_id', 'selector'],
|
|
137
143
|
additionalProperties: false,
|
|
@@ -404,7 +410,7 @@ export function createDesktopOperatorRegistrationInput(
|
|
|
404
410
|
{ capabilityId: 'desktop.permissions', title: 'Desktop permissions', description: 'Request the official macOS permissions required by Desktop Operator capabilities.', scopes: ['desktop.permissions'], actions: ['desktop_permissions_request'] },
|
|
405
411
|
{ capabilityId: 'desktop.session', title: 'Desktop sessions', description: 'Create and close application interaction sessions.', scopes: ['desktop.session'], actions: ['desktop_session_open', 'desktop_session_close'] },
|
|
406
412
|
{ capabilityId: 'desktop.observe', title: 'Desktop observation', description: 'Read bounded Accessibility and window state.', scopes: ['desktop.observe'], actions: ['desktop_observe'] },
|
|
407
|
-
{ capabilityId: 'desktop.interact', title: 'Desktop interaction', description: 'Press, type, send keys, and open URLs.', scopes: ['desktop.interact'], actions: ['desktop_press', 'desktop_type_text', 'desktop_key', 'desktop_open_url'] },
|
|
413
|
+
{ capabilityId: 'desktop.interact', title: 'Desktop interaction', description: 'Press controls, type text, send keys, and open URLs.', scopes: ['desktop.interact'], actions: ['desktop_press', 'desktop_type_text', 'desktop_key', 'desktop_open_url'] },
|
|
408
414
|
{ capabilityId: 'desktop.capture', title: 'Desktop capture', description: 'Capture authorized screenshots.', scopes: ['desktop.capture'], actions: ['desktop_screenshot'] },
|
|
409
415
|
{ capabilityId: 'desktop.clipboard', title: 'Desktop clipboard', description: 'Read or replace plain-text clipboard content and issue explicit copy/paste in a bound session.', scopes: ['desktop.clipboard'], actions: ['desktop_clipboard_read', 'desktop_clipboard_write', 'desktop_copy', 'desktop_paste'] },
|
|
410
416
|
{ capabilityId: 'desktop.batch', title: 'Desktop batch', description: 'Run bounded desktop action batches.', scopes: ['desktop.batch'], actions: ['desktop_batch'] },
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
1
2
|
import { AssistantPluginError } from './errors';
|
|
2
3
|
import { getExternalPluginRegistration, listExternalPluginRegistrations, type ExternalPluginRegistration } from './external-registration';
|
|
3
4
|
import { callExternalUnixSocket, probeExternalUnixSocketSync, type ExternalUnixSocketCallOptions } from './external-unix-socket';
|
|
4
5
|
import { executeManagedPluginProcess, executeManagedPluginProcessSync, type ManagedPluginProcessSpec } from './managed-process-adapter';
|
|
5
|
-
import { restartVerifiedUserLaunchAgent, startVerifiedUserLaunchAgent, stopVerifiedUserLaunchAgent } from './local-system-adapter';
|
|
6
|
-
import type { AssistantPluginActionDescriptor, AssistantPluginAdapter, AssistantPluginCapability, AssistantPluginHealth, AssistantPluginManifest, AssistantPluginPermissionScope } from './types';
|
|
6
|
+
import { activateAndVerifyFrontmostApplication, restartVerifiedUserLaunchAgent, startVerifiedUserLaunchAgent, stopVerifiedUserLaunchAgent } from './local-system-adapter';
|
|
7
|
+
import type { AssistantPluginActionDescriptor, AssistantPluginAdapter, AssistantPluginAuthorizationContext, AssistantPluginCapability, AssistantPluginHealth, AssistantPluginManifest, AssistantPluginPermissionScope } from './types';
|
|
7
8
|
|
|
8
9
|
interface ProviderManifest {
|
|
9
10
|
id: string;
|
|
@@ -31,6 +32,7 @@ export interface ExternalPluginAdapterDependencies {
|
|
|
31
32
|
startVerifiedUserLaunchAgent?: (label: unknown, expectedProgram: unknown) => Record<string, unknown>;
|
|
32
33
|
stopVerifiedUserLaunchAgent?: (label: unknown, expectedProgram: unknown) => Record<string, unknown>;
|
|
33
34
|
restartVerifiedUserLaunchAgent?: (label: unknown, expectedProgram: unknown) => Record<string, unknown>;
|
|
35
|
+
activateAndVerifyFrontmostApplication?: typeof activateAndVerifyFrontmostApplication;
|
|
34
36
|
now?: () => Date;
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -59,7 +61,10 @@ function parseProviderManifest(value: Record<string, unknown>, registration: Ext
|
|
|
59
61
|
if (manifest.protocolVersion !== registration.protocolVersion) throw providerError('EXTERNAL_PLUGIN_PROTOCOL_MISMATCH', `Expected provider protocol ${registration.protocolVersion}, received ${manifest.protocolVersion || 'unknown'}.`);
|
|
60
62
|
if (manifest.scope !== registration.scope) throw providerError('EXTERNAL_PLUGIN_SCOPE_MISMATCH', `Expected provider scope ${registration.scope}, received ${manifest.scope || 'unknown'}.`);
|
|
61
63
|
if (manifest.provider !== registration.provider) throw providerError('EXTERNAL_PLUGIN_PROVIDER_MISMATCH', `Expected provider ${registration.provider}, received ${manifest.provider || 'unknown'}.`);
|
|
62
|
-
const missingActions = registration.actions
|
|
64
|
+
const missingActions = registration.actions
|
|
65
|
+
.map((action) => action.actionId)
|
|
66
|
+
.filter((actionId) => !(registration.pluginId === 'desktop_operator' && ['desktop_pointer_click', 'desktop_foreground_pointer_click'].includes(actionId)))
|
|
67
|
+
.filter((actionId) => !manifest.actions.includes(actionId));
|
|
63
68
|
if (missingActions.length > 0) throw providerError('EXTERNAL_PLUGIN_ACTION_MISMATCH', `Provider is missing registered actions: ${missingActions.join(', ')}.`);
|
|
64
69
|
return manifest;
|
|
65
70
|
}
|
|
@@ -189,6 +194,225 @@ async function callProvider(
|
|
|
189
194
|
});
|
|
190
195
|
}
|
|
191
196
|
|
|
197
|
+
function externalProviderAuthorizationContext(registration: ExternalPluginRegistration): AssistantPluginAuthorizationContext {
|
|
198
|
+
return {
|
|
199
|
+
target: {
|
|
200
|
+
kind: 'external-provider',
|
|
201
|
+
id: registration.pluginId,
|
|
202
|
+
identityFingerprint: registration.registrationFingerprint,
|
|
203
|
+
},
|
|
204
|
+
expiresInMinutes: 30 * 24 * 60,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function desktopApplicationAuthorizationContext(
|
|
209
|
+
registration: ExternalPluginRegistration,
|
|
210
|
+
stableApplicationId: string,
|
|
211
|
+
): AssistantPluginAuthorizationContext {
|
|
212
|
+
const normalized = stableApplicationId.trim();
|
|
213
|
+
return {
|
|
214
|
+
target: {
|
|
215
|
+
kind: 'desktop-application',
|
|
216
|
+
id: normalized,
|
|
217
|
+
identityFingerprint: createHash('sha256')
|
|
218
|
+
.update(`${registration.registrationFingerprint}\0${normalized}`)
|
|
219
|
+
.digest('hex'),
|
|
220
|
+
},
|
|
221
|
+
expiresInMinutes: 30 * 24 * 60,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function recordArray(value: unknown): Record<string, unknown>[] {
|
|
226
|
+
return Array.isArray(value)
|
|
227
|
+
? value.filter((entry): entry is Record<string, unknown> => Boolean(entry) && typeof entry === 'object' && !Array.isArray(entry))
|
|
228
|
+
: [];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function firstString(record: Record<string, unknown>, ...keys: string[]): string {
|
|
232
|
+
for (const key of keys) {
|
|
233
|
+
const value = record[key];
|
|
234
|
+
if (typeof value === 'string' && value.trim()) return value.trim();
|
|
235
|
+
}
|
|
236
|
+
return '';
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function firstNumber(record: Record<string, unknown>, ...keys: string[]): number | undefined {
|
|
240
|
+
for (const key of keys) {
|
|
241
|
+
const value = record[key];
|
|
242
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
243
|
+
}
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function desktopSession(status: Record<string, unknown>, interactionId: string): Record<string, unknown> | undefined {
|
|
248
|
+
return recordArray(status.sessions).find((session) => firstString(session, 'interactionId', 'interaction_id') === interactionId);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function desktopApplicationIsActive(status: Record<string, unknown>, bundleId: string, appName: string): boolean {
|
|
252
|
+
return recordArray(status.applications).some((application) => {
|
|
253
|
+
if (application.active !== true || application.terminated === true) return false;
|
|
254
|
+
const candidateBundleId = firstString(application, 'bundle_id', 'bundleIdentifier');
|
|
255
|
+
const candidateName = firstString(application, 'name', 'appName');
|
|
256
|
+
return bundleId ? candidateBundleId === bundleId : Boolean(appName) && candidateName === appName;
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async function openVerifiedDesktopSession(
|
|
261
|
+
registration: ExternalPluginRegistration,
|
|
262
|
+
requestId: string,
|
|
263
|
+
args: Record<string, unknown>,
|
|
264
|
+
timeoutMs: number | undefined,
|
|
265
|
+
signal: AbortSignal | undefined,
|
|
266
|
+
dependencies: ExternalPluginAdapterDependencies,
|
|
267
|
+
): Promise<Record<string, unknown>> {
|
|
268
|
+
const bundleId = typeof args.bundle_id === 'string' ? args.bundle_id.trim() : '';
|
|
269
|
+
const appName = typeof args.app_name === 'string' ? args.app_name.trim() : '';
|
|
270
|
+
if (!bundleId && !appName) {
|
|
271
|
+
throw providerError('DESKTOP_ACTIVATION_TARGET_UNAVAILABLE', 'Activated desktop sessions require an exact bundle id or application name.');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
let result: Record<string, unknown>;
|
|
275
|
+
let fallbackVerified = false;
|
|
276
|
+
try {
|
|
277
|
+
result = await callProvider(
|
|
278
|
+
registration,
|
|
279
|
+
requestId,
|
|
280
|
+
'desktop_session_open',
|
|
281
|
+
args,
|
|
282
|
+
timeoutMs,
|
|
283
|
+
signal,
|
|
284
|
+
dependencies,
|
|
285
|
+
);
|
|
286
|
+
} catch (error) {
|
|
287
|
+
if (!(error instanceof AssistantPluginError) || error.code !== 'APP_ACTIVATION_FAILED') throw error;
|
|
288
|
+
|
|
289
|
+
result = await callProvider(
|
|
290
|
+
registration,
|
|
291
|
+
`${requestId}:fallback-session`,
|
|
292
|
+
'desktop_session_open',
|
|
293
|
+
{ ...(bundleId ? { bundle_id: bundleId } : { app_name: appName }), launch: false, activate: false },
|
|
294
|
+
timeoutMs,
|
|
295
|
+
signal,
|
|
296
|
+
dependencies,
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
const activateFallback = dependencies.activateAndVerifyFrontmostApplication ?? activateAndVerifyFrontmostApplication;
|
|
300
|
+
try {
|
|
301
|
+
const fallbackProof = await activateFallback({ bundleId: bundleId || undefined, appName: appName || undefined });
|
|
302
|
+
const proofBundleId = typeof fallbackProof.bundleId === 'string' ? fallbackProof.bundleId.trim() : '';
|
|
303
|
+
const proofAppName = typeof fallbackProof.appName === 'string' ? fallbackProof.appName.trim() : '';
|
|
304
|
+
const proofMatches = bundleId ? proofBundleId === bundleId : proofAppName === appName;
|
|
305
|
+
if (fallbackProof.activated !== true || fallbackProof.verified !== true || !proofMatches) {
|
|
306
|
+
throw new AssistantPluginError(
|
|
307
|
+
'DESKTOP_ACTIVATION_FALLBACK_IDENTITY_MISMATCH',
|
|
308
|
+
`Forge fallback did not prove the exact requested application ${bundleId || appName} as frontmost.`,
|
|
309
|
+
{ retryable: true, details: { target: { bundleId, appName }, observed: { bundleId: proofBundleId, appName: proofAppName } } },
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
fallbackVerified = true;
|
|
313
|
+
} catch (fallbackError) {
|
|
314
|
+
if (fallbackError instanceof AssistantPluginError) {
|
|
315
|
+
throw new AssistantPluginError(
|
|
316
|
+
'DESKTOP_ACTIVATION_FALLBACK_FAILED',
|
|
317
|
+
`Desktop Operator activation failed and Forge could not independently verify ${bundleId || appName} as frontmost.`,
|
|
318
|
+
{
|
|
319
|
+
retryable: fallbackError.retryable,
|
|
320
|
+
details: {
|
|
321
|
+
providerErrorCode: error.code,
|
|
322
|
+
fallbackErrorCode: fallbackError.code,
|
|
323
|
+
fallbackErrorMessage: fallbackError.message,
|
|
324
|
+
target: bundleId || appName,
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
throw new AssistantPluginError(
|
|
330
|
+
'DESKTOP_ACTIVATION_FALLBACK_FAILED',
|
|
331
|
+
`Desktop Operator activation failed and Forge fallback failed for ${bundleId || appName}.`,
|
|
332
|
+
{ retryable: true, details: { providerErrorCode: error.code, fallbackErrorMessage: String(fallbackError), target: bundleId || appName } },
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (!fallbackVerified) {
|
|
338
|
+
const activeStatus = await callProvider(
|
|
339
|
+
registration,
|
|
340
|
+
`${requestId}:active-status`,
|
|
341
|
+
'desktop_status',
|
|
342
|
+
{ limit: 500 },
|
|
343
|
+
timeoutMs,
|
|
344
|
+
signal,
|
|
345
|
+
dependencies,
|
|
346
|
+
);
|
|
347
|
+
if (!desktopApplicationIsActive(activeStatus, bundleId, appName)) {
|
|
348
|
+
throw providerError('DESKTOP_ACTIVATION_NOT_CONFIRMED', `Desktop Operator did not confirm ${bundleId || appName} as the frontmost application after activation.`, true);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return result;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async function resolveExternalAuthorizationContext(
|
|
355
|
+
registration: ExternalPluginRegistration,
|
|
356
|
+
input: Parameters<NonNullable<AssistantPluginAdapter['resolveAuthorizationContext']>>[0],
|
|
357
|
+
dependencies: ExternalPluginAdapterDependencies,
|
|
358
|
+
): Promise<AssistantPluginAuthorizationContext | undefined> {
|
|
359
|
+
if (EXTERNAL_PROVIDER_LIFECYCLE_ACTIONS.has(input.actionId)) {
|
|
360
|
+
return externalProviderAuthorizationContext(registration);
|
|
361
|
+
}
|
|
362
|
+
if (registration.pluginId !== 'desktop_operator') return undefined;
|
|
363
|
+
if (input.actionId === 'desktop_permissions_request') {
|
|
364
|
+
return externalProviderAuthorizationContext(registration);
|
|
365
|
+
}
|
|
366
|
+
if (input.actionId === 'desktop_session_open') {
|
|
367
|
+
const bundleId = typeof input.args.bundle_id === 'string' ? input.args.bundle_id.trim() : '';
|
|
368
|
+
return bundleId ? desktopApplicationAuthorizationContext(registration, bundleId) : undefined;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const interactionId = typeof input.args.interaction_id === 'string' ? input.args.interaction_id.trim() : '';
|
|
372
|
+
if (!interactionId) return undefined;
|
|
373
|
+
|
|
374
|
+
const providerManifest = await callProvider(
|
|
375
|
+
registration,
|
|
376
|
+
`${input.requestId}:authorization-target:manifest`,
|
|
377
|
+
'manifest',
|
|
378
|
+
{},
|
|
379
|
+
undefined,
|
|
380
|
+
input.signal,
|
|
381
|
+
dependencies,
|
|
382
|
+
);
|
|
383
|
+
parseProviderManifest(providerManifest, registration);
|
|
384
|
+
const status = await callProvider(
|
|
385
|
+
registration,
|
|
386
|
+
`${input.requestId}:authorization-target:desktop-status`,
|
|
387
|
+
'desktop_status',
|
|
388
|
+
{ limit: 500 },
|
|
389
|
+
input.timeoutMs,
|
|
390
|
+
input.signal,
|
|
391
|
+
dependencies,
|
|
392
|
+
);
|
|
393
|
+
const sessions = Array.isArray(status.sessions) ? status.sessions : [];
|
|
394
|
+
const session = sessions.find((entry) => {
|
|
395
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return false;
|
|
396
|
+
const record = entry as Record<string, unknown>;
|
|
397
|
+
const id = typeof record.interactionId === 'string' ? record.interactionId : typeof record.interaction_id === 'string' ? record.interaction_id : '';
|
|
398
|
+
return id === interactionId;
|
|
399
|
+
}) as Record<string, unknown> | undefined;
|
|
400
|
+
if (!session) {
|
|
401
|
+
throw providerError('EXTERNAL_PLUGIN_AUTHORIZATION_TARGET_UNAVAILABLE', `Desktop session ${interactionId} was not found while resolving its stable authorization target.`, false);
|
|
402
|
+
}
|
|
403
|
+
const bundleId = typeof session.bundleIdentifier === 'string' ? session.bundleIdentifier.trim()
|
|
404
|
+
: typeof session.bundle_identifier === 'string' ? session.bundle_identifier.trim()
|
|
405
|
+
: '';
|
|
406
|
+
const appName = typeof session.appName === 'string' ? session.appName.trim()
|
|
407
|
+
: typeof session.app_name === 'string' ? session.app_name.trim()
|
|
408
|
+
: '';
|
|
409
|
+
const stableApplicationId = bundleId || (appName ? `name:${appName.toLowerCase()}` : '');
|
|
410
|
+
if (!stableApplicationId) {
|
|
411
|
+
throw providerError('EXTERNAL_PLUGIN_AUTHORIZATION_TARGET_UNAVAILABLE', `Desktop session ${interactionId} has no stable application identity.`, false);
|
|
412
|
+
}
|
|
413
|
+
return desktopApplicationAuthorizationContext(registration, stableApplicationId);
|
|
414
|
+
}
|
|
415
|
+
|
|
192
416
|
export function getExternalPluginAdapter(controllerHome: string, pluginId: string): AssistantPluginAdapter | undefined {
|
|
193
417
|
const registration = getExternalPluginRegistration(controllerHome, pluginId);
|
|
194
418
|
return registration ? createExternalPluginAdapter(registration) : undefined;
|
|
@@ -211,6 +435,7 @@ export function createExternalPluginAdapter(
|
|
|
211
435
|
return {
|
|
212
436
|
pluginId: registration.pluginId,
|
|
213
437
|
scope: registration.scope,
|
|
438
|
+
resolveAuthorizationContext: (input) => resolveExternalAuthorizationContext(registration, input, dependencies),
|
|
214
439
|
buildManifest(previousRevision = 0, previousUpdatedAt?: string): AssistantPluginManifest {
|
|
215
440
|
const checkedAt = now().toISOString();
|
|
216
441
|
if (!registration.enabled) {
|
|
@@ -305,6 +530,102 @@ export function createExternalPluginAdapter(
|
|
|
305
530
|
);
|
|
306
531
|
parseProviderManifest(providerManifest, registration);
|
|
307
532
|
}
|
|
533
|
+
if (registration.pluginId === 'desktop_operator' && input.actionId === 'desktop_foreground_pointer_click') {
|
|
534
|
+
const sourceInteractionId = typeof input.args.interaction_id === 'string' ? input.args.interaction_id.trim() : '';
|
|
535
|
+
const requestedWindowId = typeof input.args.window_id === 'number' && Number.isInteger(input.args.window_id) ? input.args.window_id : undefined;
|
|
536
|
+
const x = typeof input.args.x === 'number' && Number.isFinite(input.args.x) ? input.args.x : undefined;
|
|
537
|
+
const y = typeof input.args.y === 'number' && Number.isFinite(input.args.y) ? input.args.y : undefined;
|
|
538
|
+
if (!sourceInteractionId || !requestedWindowId || x === undefined || y === undefined) {
|
|
539
|
+
throw providerError('DESKTOP_FOREGROUND_POINTER_ARGUMENT_INVALID', 'desktop_foreground_pointer_click requires interaction_id, window_id, x, and y.');
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const sourceStatus = await callProvider(
|
|
543
|
+
registration,
|
|
544
|
+
`${input.requestId}:source-status`,
|
|
545
|
+
'desktop_status',
|
|
546
|
+
{ limit: 500 },
|
|
547
|
+
input.timeoutMs,
|
|
548
|
+
input.signal,
|
|
549
|
+
dependencies,
|
|
550
|
+
);
|
|
551
|
+
const sourceSession = desktopSession(sourceStatus, sourceInteractionId);
|
|
552
|
+
if (!sourceSession) {
|
|
553
|
+
throw providerError('DESKTOP_FOREGROUND_POINTER_SESSION_NOT_FOUND', `Desktop session ${sourceInteractionId} is no longer available.`, true);
|
|
554
|
+
}
|
|
555
|
+
const bundleId = firstString(sourceSession, 'bundleIdentifier', 'bundle_id');
|
|
556
|
+
const appName = firstString(sourceSession, 'appName', 'app_name');
|
|
557
|
+
if (!bundleId && !appName) {
|
|
558
|
+
throw providerError('DESKTOP_FOREGROUND_POINTER_TARGET_UNAVAILABLE', `Desktop session ${sourceInteractionId} has no stable application identity.`);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const activation = await openVerifiedDesktopSession(
|
|
562
|
+
registration,
|
|
563
|
+
`${input.requestId}:activate`,
|
|
564
|
+
{ ...(bundleId ? { bundle_id: bundleId } : { app_name: appName }), launch: false, activate: true },
|
|
565
|
+
input.timeoutMs,
|
|
566
|
+
input.signal,
|
|
567
|
+
dependencies,
|
|
568
|
+
);
|
|
569
|
+
const activationInteractionId = firstString(activation, 'interactionId', 'interaction_id');
|
|
570
|
+
if (!activationInteractionId) {
|
|
571
|
+
throw providerError('DESKTOP_ACTIVATION_SESSION_MISSING', 'Desktop Operator activated the application without returning a bound interaction session.', true);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const screenshot = await callProvider(
|
|
575
|
+
registration,
|
|
576
|
+
`${input.requestId}:screenshot`,
|
|
577
|
+
'desktop_screenshot',
|
|
578
|
+
{
|
|
579
|
+
interaction_id: activationInteractionId,
|
|
580
|
+
scope: 'window',
|
|
581
|
+
window_id: requestedWindowId,
|
|
582
|
+
...(typeof input.args.label === 'string' && input.args.label.trim() ? { label: input.args.label.trim() } : {}),
|
|
583
|
+
},
|
|
584
|
+
input.timeoutMs,
|
|
585
|
+
input.signal,
|
|
586
|
+
dependencies,
|
|
587
|
+
);
|
|
588
|
+
const visualRevision = firstNumber(screenshot, 'visual_revision', 'visualRevision');
|
|
589
|
+
const capturedWindowId = firstNumber(screenshot, 'windowId', 'window_id') ?? requestedWindowId;
|
|
590
|
+
if (!visualRevision || !capturedWindowId) {
|
|
591
|
+
throw providerError('DESKTOP_FOREGROUND_CAPTURE_INVALID', 'Desktop Operator did not return a fresh visual revision for the foreground window.', true);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const click = await callProvider(
|
|
595
|
+
registration,
|
|
596
|
+
`${input.requestId}:click`,
|
|
597
|
+
'desktop_pointer_click',
|
|
598
|
+
{
|
|
599
|
+
interaction_id: activationInteractionId,
|
|
600
|
+
window_id: capturedWindowId,
|
|
601
|
+
visual_revision: visualRevision,
|
|
602
|
+
x,
|
|
603
|
+
y,
|
|
604
|
+
},
|
|
605
|
+
input.timeoutMs,
|
|
606
|
+
input.signal,
|
|
607
|
+
dependencies,
|
|
608
|
+
);
|
|
609
|
+
return {
|
|
610
|
+
interactionId: activationInteractionId,
|
|
611
|
+
activationVerified: true,
|
|
612
|
+
windowId: capturedWindowId,
|
|
613
|
+
visualRevision,
|
|
614
|
+
screenshot,
|
|
615
|
+
click,
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (registration.pluginId === 'desktop_operator' && input.actionId === 'desktop_session_open' && input.args.activate === true) {
|
|
620
|
+
return await openVerifiedDesktopSession(
|
|
621
|
+
registration,
|
|
622
|
+
input.requestId,
|
|
623
|
+
input.args,
|
|
624
|
+
input.timeoutMs,
|
|
625
|
+
input.signal,
|
|
626
|
+
dependencies,
|
|
627
|
+
);
|
|
628
|
+
}
|
|
308
629
|
return await callProvider(
|
|
309
630
|
registration,
|
|
310
631
|
input.requestId,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawnSync } from 'child_process';
|
|
2
2
|
import { existsSync } from 'fs';
|
|
3
3
|
import { createConnection, type Socket } from 'net';
|
|
4
|
-
import { dirname, isAbsolute, join } from 'path';
|
|
4
|
+
import { dirname, isAbsolute, join, resolve } from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { resolveBunExecutable } from '../shared/process-environment';
|
|
7
7
|
import { AssistantPluginError } from './errors';
|
|
@@ -178,7 +178,13 @@ export async function callExternalUnixSocket(
|
|
|
178
178
|
export function resolveExternalPluginProbeSidecarPath(
|
|
179
179
|
execPath: string = process.execPath,
|
|
180
180
|
moduleUrl: string = import.meta.url,
|
|
181
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
181
182
|
): string {
|
|
183
|
+
const configuredReleaseRoot = env.FORGE_RELEASE_PATH?.trim();
|
|
184
|
+
if (configuredReleaseRoot) {
|
|
185
|
+
const releaseSidecar = join(resolve(configuredReleaseRoot), 'external-unix-socket-probe.cjs');
|
|
186
|
+
if (existsSync(releaseSidecar)) return releaseSidecar;
|
|
187
|
+
}
|
|
182
188
|
const releaseSibling = join(dirname(execPath), 'external-unix-socket-probe.cjs');
|
|
183
189
|
if (existsSync(releaseSibling)) return releaseSibling;
|
|
184
190
|
const moduleSibling = fileURLToPath(new URL('./external-unix-socket-probe.cjs', moduleUrl));
|
|
@@ -8,6 +8,7 @@ import { iosPluginAdapter } from './ios-adapter';
|
|
|
8
8
|
import { localSystemPluginAdapter } from './local-system-adapter';
|
|
9
9
|
import { pluginManagementAdapter } from './plugin-management-adapter';
|
|
10
10
|
import { resendPluginAdapter } from './resend-adapter';
|
|
11
|
+
import { xiaohongshuPluginAdapter } from './xiaohongshu-publish';
|
|
11
12
|
import type { AssistantPluginAdapter } from './types';
|
|
12
13
|
|
|
13
14
|
const FIRST_PARTY_PLUGIN_ADAPTERS: readonly AssistantPluginAdapter[] = [
|
|
@@ -19,6 +20,7 @@ const FIRST_PARTY_PLUGIN_ADAPTERS: readonly AssistantPluginAdapter[] = [
|
|
|
19
20
|
googleCalendarPluginAdapter,
|
|
20
21
|
googleTasksPluginAdapter,
|
|
21
22
|
resendPluginAdapter,
|
|
23
|
+
xiaohongshuPluginAdapter,
|
|
22
24
|
localSystemPluginAdapter,
|
|
23
25
|
pluginManagementAdapter,
|
|
24
26
|
];
|
|
@@ -7,6 +7,11 @@ import {
|
|
|
7
7
|
refreshIssueWithGitHubPlugin,
|
|
8
8
|
saveGitHubPluginConfig,
|
|
9
9
|
} from '../../cli/github/plugin';
|
|
10
|
+
import {
|
|
11
|
+
dispatchGitHubWorkflow,
|
|
12
|
+
listGitHubWorkflowRuns,
|
|
13
|
+
listGitHubWorkflows,
|
|
14
|
+
} from '../../cli/github/github';
|
|
10
15
|
import type {
|
|
11
16
|
AssistantPluginActionDescriptor,
|
|
12
17
|
AssistantPluginActionExecutionInput,
|
|
@@ -37,6 +42,20 @@ function githubPermissions(ready: boolean, projectConfigured: boolean): Assistan
|
|
|
37
42
|
granted: ready && projectConfigured,
|
|
38
43
|
required: projectConfigured,
|
|
39
44
|
},
|
|
45
|
+
{
|
|
46
|
+
scope: 'github:actions:read',
|
|
47
|
+
mode: 'read',
|
|
48
|
+
description: 'List GitHub Actions workflows and recent workflow runs.',
|
|
49
|
+
granted: ready,
|
|
50
|
+
required: false,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
scope: 'github:actions:write',
|
|
54
|
+
mode: 'write',
|
|
55
|
+
description: 'Dispatch an explicitly named workflow_dispatch workflow.',
|
|
56
|
+
granted: ready,
|
|
57
|
+
required: false,
|
|
58
|
+
},
|
|
40
59
|
{
|
|
41
60
|
scope: 'controller:issues:write',
|
|
42
61
|
mode: 'write',
|
|
@@ -63,6 +82,13 @@ function githubCapabilities(): AssistantPluginCapability[] {
|
|
|
63
82
|
scopes: ['github:projects:write'],
|
|
64
83
|
actions: ['configure', 'publish_issue'],
|
|
65
84
|
},
|
|
85
|
+
{
|
|
86
|
+
capabilityId: 'actions-ci',
|
|
87
|
+
title: 'GitHub Actions CI',
|
|
88
|
+
description: 'List workflow definitions and runs, and dispatch an explicitly named workflow_dispatch workflow.',
|
|
89
|
+
scopes: ['github:actions:read', 'github:actions:write'],
|
|
90
|
+
actions: ['list_workflows', 'list_workflow_runs', 'dispatch_workflow'],
|
|
91
|
+
},
|
|
66
92
|
];
|
|
67
93
|
}
|
|
68
94
|
|
|
@@ -144,6 +170,74 @@ function githubActions(): AssistantPluginActionDescriptor[] {
|
|
|
144
170
|
additionalProperties: false,
|
|
145
171
|
},
|
|
146
172
|
},
|
|
173
|
+
{
|
|
174
|
+
actionId: 'list_workflows',
|
|
175
|
+
title: 'List GitHub Actions workflows',
|
|
176
|
+
description: 'List workflow definitions for the configured GitHub repository.',
|
|
177
|
+
readOnly: true,
|
|
178
|
+
risk: 'readonly',
|
|
179
|
+
confirmation: 'none',
|
|
180
|
+
defaultTimeoutMs: 30_000,
|
|
181
|
+
cancellable: true,
|
|
182
|
+
idempotent: true,
|
|
183
|
+
scopes: ['github:actions:read'],
|
|
184
|
+
resourceClaims: [{ resource: 'remote', mode: 'read' }],
|
|
185
|
+
argumentsSchema: {
|
|
186
|
+
type: 'object',
|
|
187
|
+
properties: {
|
|
188
|
+
limit: { type: 'number', minimum: 1, maximum: 100 },
|
|
189
|
+
include_disabled: { type: 'boolean' },
|
|
190
|
+
},
|
|
191
|
+
additionalProperties: false,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
actionId: 'list_workflow_runs',
|
|
196
|
+
title: 'List GitHub Actions runs',
|
|
197
|
+
description: 'List recent GitHub Actions workflow runs with optional workflow, branch, and status filters.',
|
|
198
|
+
readOnly: true,
|
|
199
|
+
risk: 'readonly',
|
|
200
|
+
confirmation: 'none',
|
|
201
|
+
defaultTimeoutMs: 30_000,
|
|
202
|
+
cancellable: true,
|
|
203
|
+
idempotent: true,
|
|
204
|
+
scopes: ['github:actions:read'],
|
|
205
|
+
resourceClaims: [{ resource: 'remote', mode: 'read' }],
|
|
206
|
+
argumentsSchema: {
|
|
207
|
+
type: 'object',
|
|
208
|
+
properties: {
|
|
209
|
+
workflow: { type: 'string' },
|
|
210
|
+
branch: { type: 'string' },
|
|
211
|
+
status: { type: 'string' },
|
|
212
|
+
limit: { type: 'number', minimum: 1, maximum: 100 },
|
|
213
|
+
include_disabled: { type: 'boolean' },
|
|
214
|
+
},
|
|
215
|
+
additionalProperties: false,
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
actionId: 'dispatch_workflow',
|
|
220
|
+
title: 'Dispatch GitHub Actions workflow',
|
|
221
|
+
description: 'Create a workflow_dispatch event for one explicitly named workflow.',
|
|
222
|
+
readOnly: false,
|
|
223
|
+
risk: 'remote_write',
|
|
224
|
+
confirmation: 'authorization',
|
|
225
|
+
defaultTimeoutMs: 60_000,
|
|
226
|
+
cancellable: true,
|
|
227
|
+
idempotent: false,
|
|
228
|
+
scopes: ['github:actions:write'],
|
|
229
|
+
resourceClaims: [{ resource: 'remote', mode: 'exclusive' }],
|
|
230
|
+
argumentsSchema: {
|
|
231
|
+
type: 'object',
|
|
232
|
+
properties: {
|
|
233
|
+
workflow: { type: 'string' },
|
|
234
|
+
ref: { type: 'string' },
|
|
235
|
+
inputs: { type: 'object', additionalProperties: { type: ['string', 'number', 'boolean'] } },
|
|
236
|
+
},
|
|
237
|
+
required: ['workflow'],
|
|
238
|
+
additionalProperties: false,
|
|
239
|
+
},
|
|
240
|
+
},
|
|
147
241
|
{
|
|
148
242
|
actionId: 'close_issue',
|
|
149
243
|
title: 'Close linked GitHub issue',
|
|
@@ -252,6 +346,37 @@ export async function executeGitHubPluginAction(input: AssistantPluginActionExec
|
|
|
252
346
|
return { issue: publishIssueWithGitHubPlugin(input.repoRoot, String(input.args.issue_id ?? '').trim()) };
|
|
253
347
|
case 'refresh_issue':
|
|
254
348
|
return refreshIssueWithGitHubPlugin(input.repoRoot, String(input.args.issue_id ?? '').trim()) as Record<string, unknown>;
|
|
349
|
+
case 'list_workflows': {
|
|
350
|
+
const config = loadGitHubPluginConfig(input.repoRoot);
|
|
351
|
+
return {
|
|
352
|
+
workflows: listGitHubWorkflows(input.repoRoot, config.repository, {
|
|
353
|
+
limit: typeof input.args.limit === 'number' ? input.args.limit : undefined,
|
|
354
|
+
includeDisabled: input.args.include_disabled === true,
|
|
355
|
+
}),
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
case 'list_workflow_runs': {
|
|
359
|
+
const config = loadGitHubPluginConfig(input.repoRoot);
|
|
360
|
+
return {
|
|
361
|
+
runs: listGitHubWorkflowRuns(input.repoRoot, config.repository, {
|
|
362
|
+
workflow: typeof input.args.workflow === 'string' ? input.args.workflow : undefined,
|
|
363
|
+
branch: typeof input.args.branch === 'string' ? input.args.branch : undefined,
|
|
364
|
+
status: typeof input.args.status === 'string' ? input.args.status : undefined,
|
|
365
|
+
limit: typeof input.args.limit === 'number' ? input.args.limit : undefined,
|
|
366
|
+
includeDisabled: input.args.include_disabled === true,
|
|
367
|
+
}),
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
case 'dispatch_workflow': {
|
|
371
|
+
const config = loadGitHubPluginConfig(input.repoRoot);
|
|
372
|
+
return dispatchGitHubWorkflow(input.repoRoot, config.repository, {
|
|
373
|
+
workflow: String(input.args.workflow ?? ''),
|
|
374
|
+
ref: typeof input.args.ref === 'string' ? input.args.ref : undefined,
|
|
375
|
+
inputs: input.args.inputs && typeof input.args.inputs === 'object' && !Array.isArray(input.args.inputs)
|
|
376
|
+
? input.args.inputs as Record<string, string | number | boolean>
|
|
377
|
+
: undefined,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
255
380
|
case 'close_issue':
|
|
256
381
|
return { issue: closeIssueWithGitHubPlugin(input.repoRoot, String(input.args.issue_id ?? '').trim()) };
|
|
257
382
|
default:
|