@moretea-labs/forge 1.5.1 → 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 +46 -0
- package/CLAUDE.md +2 -0
- package/DESIGN.md +7 -2
- package/README.md +4 -4
- package/README.zh-CN.md +2 -2
- 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/pre-edit-guard.sh +8 -39
- package/assets/hooks/prompt-guard.sh +7 -83
- 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 +54 -3
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/harness-overview.md +1 -1
- package/assets/reference-configs/hook-operations.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 +13 -38
- 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/sprint-backlog.sh +6 -6
- 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 +38 -22
- package/docs/operations/controller-performance-and-502.md +124 -0
- package/docs/operations/controller-reliability-runbook.md +1 -1
- package/docs/operations/features.md +3 -3
- 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/tutorials/01-install-and-start.md +1 -1
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/wiki/Architecture.md +6 -6
- package/docs/wiki/Implementation.md +2 -2
- package/docs/wiki/Installation.md +1 -1
- package/docs/wiki/Integrations.md +2 -2
- package/docs/wiki/Quick-Start.md +1 -1
- 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-public-docs.sh +14 -1
- 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-chatgpt-automation-schedules.ts +64 -0
- 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/sprint-backlog.sh +1 -1
- 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/chatgpt.ts +31 -2
- package/src/cli/commands/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +37 -10
- 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 +898 -430
- 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/hook/prompt-guard-decision.ts +17 -18
- package/src/cli/hook/prompt-intents.ts +1 -1
- package/src/cli/installer/managed-entries.ts +15 -1
- package/src/cli/local-bridge/console-automations.ts +225 -67
- package/src/cli/local-bridge/console-view-models.ts +3 -35
- package/src/cli/local-bridge/facade-api.ts +2 -217
- package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +153 -3
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +183 -3
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/lib/api.ts +18 -11
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/styles.css +27 -11
- package/src/cli/local-bridge/frontend/src/types.ts +8 -7
- package/src/cli/local-bridge/job-store.ts +1 -490
- package/src/cli/local-bridge/server.ts +29 -532
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +5101 -4967
- 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/paths.ts +8 -2
- package/src/cli/mcp/repository-tools.ts +356 -101
- package/src/cli/mcp/server.ts +625 -54
- 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 +125 -15
- package/src/cli/mcp/transports/session-registry.ts +67 -5
- package/src/cli/mcp/types.ts +3 -3
- package/src/cli/repositories/command-classifier.ts +209 -14
- 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/safe-patch.ts +6 -4
- package/src/cli/repositories/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +110 -10
- package/src/cli/repository/inspector.ts +565 -62
- 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 +196 -2
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
- package/src/runtime/control-plane/execution/session-store.ts +18 -0
- package/src/runtime/control-plane/execution/validation.ts +15 -2
- 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 +175 -8
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -21
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +87 -9
- 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 +144 -14
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +9 -2
- package/src/runtime/control-plane/facade/goal-workloop.ts +885 -105
- package/src/runtime/control-plane/facade/index.ts +1 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +211 -26
- package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
- 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 +55 -11
- package/src/runtime/control-plane/facade/work-contract-store.ts +204 -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 +642 -51
- 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/requirement-store.ts +15 -11
- 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 +19 -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 +52 -14
- package/src/runtime/execution/process-runtime/check-result.ts +63 -2
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +346 -40
- package/src/runtime/execution/process-runtime/gc.ts +98 -12
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +57 -6
- package/src/runtime/execution/process-runtime/resource-claims.ts +97 -8
- package/src/runtime/execution/process-runtime/runtime.ts +59 -4
- package/src/runtime/execution/process-runtime/store.ts +7 -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 +1219 -126
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +185 -83
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2555 -1616
- package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
- package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
- package/src/runtime/plugins/browser-adapter.ts +2925 -318
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff-host.ts +6 -31
- package/src/runtime/plugins/browser-handoff.ts +92 -5
- package/src/runtime/plugins/browser-macos-bridge.ts +586 -45
- 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 +15 -12
- package/src/runtime/plugins/external-adapter.ts +324 -3
- package/src/runtime/plugins/external-registration.ts +84 -5
- package/src/runtime/plugins/external-unix-socket.ts +7 -1
- package/src/runtime/plugins/first-party-registry.ts +4 -2
- package/src/runtime/plugins/github-adapter.ts +125 -0
- package/src/runtime/plugins/gmail-adapter.ts +28 -2
- 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 +125 -8
- 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 +181 -0
- package/src/runtime/plugins/resend-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +366 -24
- package/src/runtime/plugins/types.ts +39 -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/actions.ts +0 -10
- package/src/runtime/recovery/classifier.ts +0 -9
- package/src/runtime/recovery/maintenance-executor.ts +415 -18
- package/src/runtime/recovery/probe.ts +0 -1
- package/src/runtime/recovery/types.ts +0 -1
- 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 +162 -19
- package/src/runtime/root/release-store.ts +48 -11
- package/src/runtime/root/runtime.ts +23 -5
- package/src/runtime/root/service.ts +100 -27
- package/src/runtime/root/types.ts +2 -0
- package/src/runtime/safe-tooling/index.ts +0 -1
- package/src/runtime/safe-tooling/ios-development.ts +321 -63
- package/src/runtime/safe-tooling/types.ts +0 -30
- 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 +702 -94
- 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 +258 -0
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
- package/src/runtime/workflow/schedules/engine.ts +509 -80
- 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 +6 -3
- package/src/runtime/workflow/schedules/work-continuation.ts +120 -34
- 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/bin/forge-desktop-helper.mjs +0 -204
- 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 -453
- package/docs/architecture/current/codegraph-context-provider.md +0 -226
- 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 -354
- package/docs/architecture/current/entity-model.md +0 -592
- 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 -144
- 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 -311
- 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 -83
- package/docs/operations/controller-desktop-plugin.md +0 -112
- 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/plugins/desktop-adapter.ts +0 -374
- package/src/runtime/safe-tooling/browser-safe.ts +0 -133
- 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
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
2
|
import { existsSync, mkdirSync, realpathSync } from 'fs';
|
|
3
|
-
import { isAbsolute, join } from 'path';
|
|
3
|
+
import { delimiter, dirname, isAbsolute, join } from 'path';
|
|
4
4
|
import { spawnSync } from 'child_process';
|
|
5
5
|
import { performance } from 'perf_hooks';
|
|
6
6
|
import { repositoryControllerRoot } from '../../cli/repositories/controller-home';
|
|
7
7
|
import { runBoundedProcess } from '../execution/thin-harness/async-process';
|
|
8
8
|
import { readJsonFile, writeJsonAtomic } from '../shared/json-files';
|
|
9
|
+
import { resolveTrustedNodeExecutable } from '../shared/trusted-node-executable';
|
|
9
10
|
import { AssistantPluginError, toAssistantPluginError } from './errors';
|
|
10
11
|
import {
|
|
11
12
|
interactionAutomationEngine,
|
|
@@ -169,16 +170,35 @@ export function resetIosAgentDeviceRuntimeHooksForTest(): void {
|
|
|
169
170
|
interactionCommandTails.clear();
|
|
170
171
|
}
|
|
171
172
|
|
|
172
|
-
function
|
|
173
|
-
return process.env.FORGE_AGENT_DEVICE_EXECUTABLE?.trim() ||
|
|
173
|
+
function configuredExecutable(): string | undefined {
|
|
174
|
+
return process.env.FORGE_AGENT_DEVICE_EXECUTABLE?.trim() || undefined;
|
|
174
175
|
}
|
|
175
176
|
|
|
176
|
-
function
|
|
177
|
-
|
|
177
|
+
function repoLocalExecutable(repoRoot?: string): string | undefined {
|
|
178
|
+
if (!repoRoot) return undefined;
|
|
179
|
+
const candidates = [
|
|
180
|
+
join(repoRoot, 'node_modules', '.bin', 'agent-device'),
|
|
181
|
+
join(repoRoot, 'node_modules', 'agent-device', 'bin', 'agent-device.mjs'),
|
|
182
|
+
];
|
|
183
|
+
for (const candidate of candidates) {
|
|
184
|
+
if (!existsSync(candidate)) continue;
|
|
185
|
+
try { return realpathSync(candidate); } catch { return candidate; }
|
|
186
|
+
}
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function executable(repoRoot?: string): string {
|
|
191
|
+
const configured = configuredExecutable();
|
|
192
|
+
if (configured) return configured;
|
|
193
|
+
return repoLocalExecutable(repoRoot) ?? 'agent-device';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function resolvedExecutable(repoRoot?: string): string {
|
|
197
|
+
const configured = executable(repoRoot);
|
|
178
198
|
if (isAbsolute(configured)) {
|
|
179
199
|
try { return realpathSync(configured); } catch { return configured; }
|
|
180
200
|
}
|
|
181
|
-
for (const directory of (process.env.PATH ?? '').split(
|
|
201
|
+
for (const directory of (process.env.PATH ?? '').split(delimiter).filter(Boolean)) {
|
|
182
202
|
const candidate = join(directory, configured);
|
|
183
203
|
if (!existsSync(candidate)) continue;
|
|
184
204
|
try { return realpathSync(candidate); } catch { return candidate; }
|
|
@@ -186,6 +206,13 @@ function resolvedExecutable(): string {
|
|
|
186
206
|
return configured;
|
|
187
207
|
}
|
|
188
208
|
|
|
209
|
+
function withTrustedNodePath(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
|
|
210
|
+
const node = resolveTrustedNodeExecutable(env).executable;
|
|
211
|
+
if (!node) return env;
|
|
212
|
+
const path = [dirname(node), env.PATH].filter((value): value is string => Boolean(value)).join(delimiter);
|
|
213
|
+
return { ...env, PATH: path };
|
|
214
|
+
}
|
|
215
|
+
|
|
189
216
|
function timestamp(): string {
|
|
190
217
|
return hooks.now().toISOString();
|
|
191
218
|
}
|
|
@@ -194,28 +221,29 @@ function sanitize(value: string): string {
|
|
|
194
221
|
return value.replace(/[^a-zA-Z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'ios-agent-device';
|
|
195
222
|
}
|
|
196
223
|
|
|
197
|
-
function statusProbeCacheKey(): string {
|
|
224
|
+
function statusProbeCacheKey(repoRoot?: string): string {
|
|
198
225
|
return [
|
|
199
226
|
hooks.platform(),
|
|
200
|
-
|
|
201
|
-
|
|
227
|
+
repoRoot ?? '',
|
|
228
|
+
executable(repoRoot),
|
|
229
|
+
resolvedExecutable(repoRoot),
|
|
202
230
|
configuredAgentDeviceBackendMode(),
|
|
203
231
|
process.versions.node,
|
|
204
232
|
process.env.PATH ?? '',
|
|
205
233
|
].join('|');
|
|
206
234
|
}
|
|
207
235
|
|
|
208
|
-
function probeStatus() {
|
|
236
|
+
function probeStatus(repoRoot?: string) {
|
|
209
237
|
const backendMode = configuredAgentDeviceBackendMode();
|
|
210
|
-
const typedClient = typedAgentDeviceIdentity();
|
|
238
|
+
const typedClient = typedAgentDeviceIdentity({ repoRoot });
|
|
211
239
|
if (hooks.platform() !== 'darwin') {
|
|
212
240
|
return {
|
|
213
241
|
available: false,
|
|
214
242
|
expectedVersion: IOS_AGENT_DEVICE_VERSION,
|
|
215
243
|
supportedVersionPolicy: '>=0.19.3 <0.21.0 with reviewed command contract',
|
|
216
244
|
detectedVersion: undefined,
|
|
217
|
-
executable: executable(),
|
|
218
|
-
resolvedExecutable: resolvedExecutable(),
|
|
245
|
+
executable: executable(repoRoot),
|
|
246
|
+
resolvedExecutable: resolvedExecutable(repoRoot),
|
|
219
247
|
platform: hooks.platform(),
|
|
220
248
|
capabilityProfile: detectAgentDeviceCapabilities('', {}),
|
|
221
249
|
backendMode,
|
|
@@ -223,14 +251,15 @@ function probeStatus() {
|
|
|
223
251
|
reason: 'agent-device iOS support requires macOS.',
|
|
224
252
|
};
|
|
225
253
|
}
|
|
226
|
-
const
|
|
254
|
+
const runtimeEnv = withTrustedNodePath({ ...process.env });
|
|
255
|
+
const result = hooks.runCommand(executable(repoRoot), ['--version'], { cwd: repoRoot, env: runtimeEnv, timeoutMs: 3_000 });
|
|
227
256
|
const detectedVersion = result.ok ? result.stdout.trim() : undefined;
|
|
228
257
|
const help: AgentDeviceHelpContract = {};
|
|
229
258
|
if (result.ok && detectedVersion) {
|
|
230
|
-
const rootHelp = hooks.runCommand(executable(), ['help'], { timeoutMs: 3_000 });
|
|
259
|
+
const rootHelp = hooks.runCommand(executable(repoRoot), ['help'], { cwd: repoRoot, env: runtimeEnv, timeoutMs: 3_000 });
|
|
231
260
|
if (rootHelp.ok) help.root = rootHelp.stdout || rootHelp.stderr;
|
|
232
261
|
for (const topic of ['snapshot', 'press', 'fill', 'batch', 'keyboard'] as const) {
|
|
233
|
-
const topicResult = hooks.runCommand(executable(), ['help', topic], { timeoutMs: 3_000 });
|
|
262
|
+
const topicResult = hooks.runCommand(executable(repoRoot), ['help', topic], { cwd: repoRoot, env: runtimeEnv, timeoutMs: 3_000 });
|
|
234
263
|
if (topicResult.ok) help[topic] = topicResult.stdout || topicResult.stderr;
|
|
235
264
|
}
|
|
236
265
|
}
|
|
@@ -251,8 +280,8 @@ function probeStatus() {
|
|
|
251
280
|
expectedVersion: IOS_AGENT_DEVICE_VERSION,
|
|
252
281
|
supportedVersionPolicy: '>=0.19.3 <0.21.0 with reviewed command contract',
|
|
253
282
|
detectedVersion,
|
|
254
|
-
executable: executable(),
|
|
255
|
-
resolvedExecutable: resolvedExecutable(),
|
|
283
|
+
executable: executable(repoRoot),
|
|
284
|
+
resolvedExecutable: resolvedExecutable(repoRoot),
|
|
256
285
|
platform: hooks.platform(),
|
|
257
286
|
capabilityProfile,
|
|
258
287
|
backendMode,
|
|
@@ -267,20 +296,105 @@ function probeStatus() {
|
|
|
267
296
|
};
|
|
268
297
|
}
|
|
269
298
|
|
|
270
|
-
|
|
299
|
+
function unprobedAgentDeviceStatus(repoRoot?: string): ReturnType<typeof probeStatus> {
|
|
300
|
+
const backendMode = configuredAgentDeviceBackendMode();
|
|
301
|
+
const typedClient = typedAgentDeviceIdentity({ repoRoot });
|
|
302
|
+
return {
|
|
303
|
+
available: false,
|
|
304
|
+
expectedVersion: IOS_AGENT_DEVICE_VERSION,
|
|
305
|
+
supportedVersionPolicy: '>=0.19.3 <0.21.0 with reviewed command contract',
|
|
306
|
+
detectedVersion: undefined,
|
|
307
|
+
executable: executable(repoRoot),
|
|
308
|
+
resolvedExecutable: resolvedExecutable(repoRoot),
|
|
309
|
+
platform: hooks.platform(),
|
|
310
|
+
capabilityProfile: detectAgentDeviceCapabilities('', {}),
|
|
311
|
+
backendMode,
|
|
312
|
+
typedClient: { ...typedClient, cliVersion: undefined, cliVersionCompatible: false },
|
|
313
|
+
reason: 'agent-device readiness has not been probed by an explicit asynchronous action in this runtime yet.',
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export function iosAgentDeviceStatus(options: { forceRefresh?: boolean; repoRoot?: string } = {}) {
|
|
271
318
|
const nowMs = hooks.now().getTime();
|
|
272
|
-
const cacheKey = statusProbeCacheKey();
|
|
319
|
+
const cacheKey = statusProbeCacheKey(options.repoRoot);
|
|
273
320
|
if (!options.forceRefresh
|
|
274
321
|
&& statusCache
|
|
275
322
|
&& statusCache.cacheKey === cacheKey
|
|
276
323
|
&& statusCache.expiresAt > nowMs) return statusCache.value;
|
|
277
|
-
|
|
324
|
+
if (hooks.platform() !== 'darwin') return probeStatus(options.repoRoot);
|
|
325
|
+
return unprobedAgentDeviceStatus(options.repoRoot);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async function probeStatusAsync(input: Pick<AssistantPluginActionExecutionInput, 'repoRoot' | 'signal'>): Promise<ReturnType<typeof probeStatus>> {
|
|
329
|
+
const repoRoot = input.repoRoot;
|
|
330
|
+
const backendMode = configuredAgentDeviceBackendMode();
|
|
331
|
+
const typedClient = typedAgentDeviceIdentity({ repoRoot });
|
|
332
|
+
if (hooks.platform() !== 'darwin') return probeStatus(repoRoot);
|
|
333
|
+
const runtimeEnv = withTrustedNodePath({ ...process.env });
|
|
334
|
+
const result = await hooks.runCommandAsync(executable(repoRoot), ['--version'], {
|
|
335
|
+
cwd: repoRoot,
|
|
336
|
+
env: runtimeEnv,
|
|
337
|
+
timeoutMs: 3_000,
|
|
338
|
+
signal: input.signal,
|
|
339
|
+
});
|
|
340
|
+
const detectedVersion = result.ok ? result.stdout.trim() : undefined;
|
|
341
|
+
const help: AgentDeviceHelpContract = {};
|
|
342
|
+
if (result.ok && detectedVersion) {
|
|
343
|
+
const rootHelp = await hooks.runCommandAsync(executable(repoRoot), ['help'], {
|
|
344
|
+
cwd: repoRoot, env: runtimeEnv, timeoutMs: 3_000, signal: input.signal,
|
|
345
|
+
});
|
|
346
|
+
if (rootHelp.ok) help.root = rootHelp.stdout || rootHelp.stderr;
|
|
347
|
+
for (const topic of ['snapshot', 'press', 'fill', 'batch', 'keyboard'] as const) {
|
|
348
|
+
const topicResult = await hooks.runCommandAsync(executable(repoRoot), ['help', topic], {
|
|
349
|
+
cwd: repoRoot, env: runtimeEnv, timeoutMs: 3_000, signal: input.signal,
|
|
350
|
+
});
|
|
351
|
+
if (topicResult.ok) help[topic] = topicResult.stdout || topicResult.stderr;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const capabilityProfile = detectAgentDeviceCapabilities(detectedVersion ?? '', help);
|
|
355
|
+
const typedClientWithCompatibility = {
|
|
356
|
+
...typedClient,
|
|
357
|
+
cliVersion: detectedVersion,
|
|
358
|
+
cliVersionCompatible: agentDeviceProviderVersionsMatch(typedClient.version, detectedVersion),
|
|
359
|
+
};
|
|
360
|
+
const available = result.ok
|
|
361
|
+
&& capabilityProfile.versionSupported
|
|
362
|
+
&& Boolean(capabilityProfile.snapshot.interactiveFlag)
|
|
363
|
+
&& capabilityProfile.press.supported
|
|
364
|
+
&& capabilityProfile.fill.supported
|
|
365
|
+
&& capabilityProfile.batch.supported;
|
|
366
|
+
return {
|
|
367
|
+
available,
|
|
368
|
+
expectedVersion: IOS_AGENT_DEVICE_VERSION,
|
|
369
|
+
supportedVersionPolicy: '>=0.19.3 <0.21.0 with reviewed command contract',
|
|
370
|
+
detectedVersion,
|
|
371
|
+
executable: executable(repoRoot),
|
|
372
|
+
resolvedExecutable: resolvedExecutable(repoRoot),
|
|
373
|
+
platform: hooks.platform(),
|
|
374
|
+
capabilityProfile,
|
|
375
|
+
backendMode,
|
|
376
|
+
typedClient: typedClientWithCompatibility,
|
|
377
|
+
reason: !result.ok
|
|
378
|
+
? (result.stderr || result.stdout || 'agent-device is not installed.')
|
|
379
|
+
: !capabilityProfile.versionSupported
|
|
380
|
+
? `Unsupported agent-device version ${detectedVersion || 'unknown'}; expected the reviewed >=0.19.3 <0.21.0 contract.`
|
|
381
|
+
: !available
|
|
382
|
+
? 'The installed agent-device command contract is missing required snapshot, press, fill, or batch capabilities.'
|
|
383
|
+
: undefined,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
async function iosAgentDeviceActionStatus(input: AssistantPluginActionExecutionInput): Promise<ReturnType<typeof probeStatus>> {
|
|
388
|
+
const nowMs = hooks.now().getTime();
|
|
389
|
+
const cacheKey = statusProbeCacheKey(input.repoRoot);
|
|
390
|
+
if (statusCache && statusCache.cacheKey === cacheKey && statusCache.expiresAt > nowMs) return statusCache.value;
|
|
391
|
+
const value = await probeStatusAsync(input);
|
|
278
392
|
statusCache = { cacheKey, expiresAt: nowMs + STATUS_TTL_MS, value };
|
|
279
393
|
return value;
|
|
280
394
|
}
|
|
281
395
|
|
|
282
|
-
function requireDependency(): ReturnType<typeof probeStatus> {
|
|
283
|
-
const status = iosAgentDeviceStatus();
|
|
396
|
+
function requireDependency(repoRoot?: string): ReturnType<typeof probeStatus> {
|
|
397
|
+
const status = iosAgentDeviceStatus({ repoRoot });
|
|
284
398
|
if (!status.available) {
|
|
285
399
|
throw new AssistantPluginError('PLUGIN_DEPENDENCY_MISSING', status.reason ?? 'A compatible agent-device provider is unavailable.', {
|
|
286
400
|
retryable: false,
|
|
@@ -290,8 +404,19 @@ function requireDependency(): ReturnType<typeof probeStatus> {
|
|
|
290
404
|
return status;
|
|
291
405
|
}
|
|
292
406
|
|
|
293
|
-
function
|
|
294
|
-
|
|
407
|
+
async function requireDependencyAsync(input: AssistantPluginActionExecutionInput): Promise<ReturnType<typeof probeStatus>> {
|
|
408
|
+
const status = await iosAgentDeviceActionStatus(input);
|
|
409
|
+
if (!status.available) {
|
|
410
|
+
throw new AssistantPluginError('PLUGIN_DEPENDENCY_MISSING', status.reason ?? 'A compatible agent-device provider is unavailable.', {
|
|
411
|
+
retryable: false,
|
|
412
|
+
details: status,
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
return status;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function capabilityProfile(repoRoot?: string): AgentDeviceCapabilityProfile {
|
|
419
|
+
return requireDependency(repoRoot).capabilityProfile;
|
|
295
420
|
}
|
|
296
421
|
|
|
297
422
|
function controllerRoot(input: AssistantPluginActionExecutionInput): string {
|
|
@@ -308,6 +433,37 @@ function stateDir(input: AssistantPluginActionExecutionInput, interactionId: str
|
|
|
308
433
|
return path;
|
|
309
434
|
}
|
|
310
435
|
|
|
436
|
+
function physicalDeviceRuntimeRoot(input: AssistantPluginActionExecutionInput, targetId: string): string {
|
|
437
|
+
const path = join(
|
|
438
|
+
controllerRoot(input),
|
|
439
|
+
'interactions',
|
|
440
|
+
'ios-agent-device',
|
|
441
|
+
'device-runtime',
|
|
442
|
+
sanitize(targetId),
|
|
443
|
+
);
|
|
444
|
+
mkdirSync(path, { recursive: true });
|
|
445
|
+
return path;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function physicalDeviceRuntimeStateDir(input: AssistantPluginActionExecutionInput, targetId: string): string {
|
|
449
|
+
const path = join(physicalDeviceRuntimeRoot(input, targetId), 'state');
|
|
450
|
+
mkdirSync(path, { recursive: true });
|
|
451
|
+
return path;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function runtimeStateDir(input: AssistantPluginActionExecutionInput, record: InteractionSessionRecord): string {
|
|
455
|
+
// A real iPhone must not get a fresh daemon/Runner cache for every logical
|
|
456
|
+
// interaction. One stable per-device runtime owns provider metadata and any
|
|
457
|
+
// explicitly prepared semantic Runner. Simulator sessions remain isolated.
|
|
458
|
+
return record.provider === DEVICE_PROVIDER
|
|
459
|
+
? physicalDeviceRuntimeStateDir(input, record.targetId)
|
|
460
|
+
: stateDir(input, record.interactionId);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function targetRuntimeStateDir(input: AssistantPluginActionExecutionInput, target: AgentDeviceEntry): string | undefined {
|
|
464
|
+
return target.kind === 'device' ? physicalDeviceRuntimeStateDir(input, target.id) : undefined;
|
|
465
|
+
}
|
|
466
|
+
|
|
311
467
|
function signingConfigPath(input: AssistantPluginActionExecutionInput, interactionId: string): string {
|
|
312
468
|
return join(interactionRoot(input, interactionId), 'signing.json');
|
|
313
469
|
}
|
|
@@ -344,27 +500,31 @@ function artifactDir(input: AssistantPluginActionExecutionInput, interactionId:
|
|
|
344
500
|
|
|
345
501
|
function sessionEnv(input: AssistantPluginActionExecutionInput, record: InteractionSessionRecord): NodeJS.ProcessEnv {
|
|
346
502
|
const config = readSigningConfig(input, record.interactionId);
|
|
347
|
-
return {
|
|
503
|
+
return withTrustedNodePath({
|
|
348
504
|
...process.env,
|
|
349
505
|
...signingEnv(config),
|
|
350
|
-
AGENT_DEVICE_STATE_DIR:
|
|
506
|
+
AGENT_DEVICE_STATE_DIR: runtimeStateDir(input, record),
|
|
351
507
|
AGENT_DEVICE_SESSION: record.sessionId,
|
|
352
508
|
AGENT_DEVICE_PLATFORM: 'ios',
|
|
353
509
|
AGENT_DEVICE_SESSION_LOCK: 'reject',
|
|
354
|
-
// Keep the
|
|
355
|
-
//
|
|
356
|
-
//
|
|
510
|
+
// Keep the daemon and an explicitly prepared Runner warm. Physical devices
|
|
511
|
+
// share one stable runtime state directory across logical interactions;
|
|
512
|
+
// Simulator interactions remain isolated.
|
|
357
513
|
AGENT_DEVICE_DAEMON_IDLE_TIMEOUT_MS:
|
|
358
514
|
process.env.FORGE_AGENT_DEVICE_DAEMON_IDLE_TIMEOUT_MS?.trim() || DEFAULT_AGENT_DEVICE_IDLE_MS,
|
|
359
515
|
AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS:
|
|
360
516
|
process.env.FORGE_AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS?.trim() || DEFAULT_AGENT_DEVICE_IDLE_MS,
|
|
361
|
-
};
|
|
517
|
+
});
|
|
362
518
|
}
|
|
363
519
|
|
|
364
|
-
function probeEnv(
|
|
365
|
-
|
|
520
|
+
function probeEnv(
|
|
521
|
+
input: AssistantPluginActionExecutionInput,
|
|
522
|
+
config?: AgentDeviceSigningConfig,
|
|
523
|
+
requestedStateDir?: string,
|
|
524
|
+
): NodeJS.ProcessEnv {
|
|
525
|
+
const path = requestedStateDir ?? join(controllerRoot(input), 'interactions', 'ios-agent-device', 'probe-state');
|
|
366
526
|
mkdirSync(path, { recursive: true });
|
|
367
|
-
return {
|
|
527
|
+
return withTrustedNodePath({
|
|
368
528
|
...process.env,
|
|
369
529
|
...signingEnv(config),
|
|
370
530
|
AGENT_DEVICE_STATE_DIR: path,
|
|
@@ -373,7 +533,7 @@ function probeEnv(input: AssistantPluginActionExecutionInput, config?: AgentDevi
|
|
|
373
533
|
process.env.FORGE_AGENT_DEVICE_DAEMON_IDLE_TIMEOUT_MS?.trim() || DEFAULT_AGENT_DEVICE_IDLE_MS,
|
|
374
534
|
AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS:
|
|
375
535
|
process.env.FORGE_AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS?.trim() || DEFAULT_AGENT_DEVICE_IDLE_MS,
|
|
376
|
-
};
|
|
536
|
+
});
|
|
377
537
|
}
|
|
378
538
|
|
|
379
539
|
function bounded(value: unknown): unknown {
|
|
@@ -488,14 +648,15 @@ function runJson(
|
|
|
488
648
|
options: {
|
|
489
649
|
record?: InteractionSessionRecord;
|
|
490
650
|
signing?: AgentDeviceSigningConfig;
|
|
651
|
+
stateDir?: string;
|
|
491
652
|
timeoutMs?: number;
|
|
492
653
|
failureCode: string;
|
|
493
654
|
},
|
|
494
655
|
): Record<string, unknown> {
|
|
495
|
-
const result = hooks.runCommand(executable(), args, {
|
|
656
|
+
const result = hooks.runCommand(executable(input.repoRoot), args, {
|
|
496
657
|
cwd: input.repoRoot,
|
|
497
658
|
timeoutMs: effectiveCommandTimeout(input, options.timeoutMs),
|
|
498
|
-
env: options.record ? sessionEnv(input, options.record) : probeEnv(input, options.signing),
|
|
659
|
+
env: options.record ? sessionEnv(input, options.record) : probeEnv(input, options.signing, options.stateDir),
|
|
499
660
|
signal: input.signal,
|
|
500
661
|
});
|
|
501
662
|
return parseJsonResult(result, options.failureCode);
|
|
@@ -507,14 +668,15 @@ async function runJsonAsync(
|
|
|
507
668
|
options: {
|
|
508
669
|
record?: InteractionSessionRecord;
|
|
509
670
|
signing?: AgentDeviceSigningConfig;
|
|
671
|
+
stateDir?: string;
|
|
510
672
|
timeoutMs?: number;
|
|
511
673
|
failureCode: string;
|
|
512
674
|
},
|
|
513
675
|
): Promise<Record<string, unknown>> {
|
|
514
|
-
const result = await hooks.runCommandAsync(executable(), args, {
|
|
676
|
+
const result = await hooks.runCommandAsync(executable(input.repoRoot), args, {
|
|
515
677
|
cwd: input.repoRoot,
|
|
516
678
|
timeoutMs: effectiveCommandTimeout(input, options.timeoutMs),
|
|
517
|
-
env: options.record ? sessionEnv(input, options.record) : probeEnv(input, options.signing),
|
|
679
|
+
env: options.record ? sessionEnv(input, options.record) : probeEnv(input, options.signing, options.stateDir),
|
|
518
680
|
signal: input.signal,
|
|
519
681
|
});
|
|
520
682
|
return parseJsonResult(result, options.failureCode);
|
|
@@ -696,7 +858,7 @@ function providerSessionAlreadyAbsent(result: CommandResult): boolean {
|
|
|
696
858
|
}
|
|
697
859
|
|
|
698
860
|
function bestEffortClose(input: AssistantPluginActionExecutionInput, record: InteractionSessionRecord): boolean {
|
|
699
|
-
const result = hooks.runCommand(executable(), ['close', '--session', record.sessionId, '--platform', 'ios', '--json'], {
|
|
861
|
+
const result = hooks.runCommand(executable(input.repoRoot), ['close', '--session', record.sessionId, '--platform', 'ios', '--json'], {
|
|
700
862
|
cwd: input.repoRoot,
|
|
701
863
|
timeoutMs: 30_000,
|
|
702
864
|
env: sessionEnv(input, record),
|
|
@@ -716,7 +878,7 @@ async function closeProviderSession(
|
|
|
716
878
|
record: InteractionSessionRecord,
|
|
717
879
|
args: string[],
|
|
718
880
|
): Promise<{ result: Record<string, unknown>; providerAlreadyAbsent: boolean }> {
|
|
719
|
-
const commandResult = await hooks.runCommandAsync(executable(), [
|
|
881
|
+
const commandResult = await hooks.runCommandAsync(executable(input.repoRoot), [
|
|
720
882
|
...args,
|
|
721
883
|
'--session', record.sessionId,
|
|
722
884
|
'--platform', 'ios',
|
|
@@ -985,8 +1147,8 @@ async function executeSessionSnapshotBackend(
|
|
|
985
1147
|
let fallbackTypedVersion: string | undefined;
|
|
986
1148
|
let fallbackCliVersion: string | undefined;
|
|
987
1149
|
if (mode !== 'cli') {
|
|
988
|
-
const dependency = requireDependency();
|
|
989
|
-
const typed = new TypedAgentDeviceReadProvider();
|
|
1150
|
+
const dependency = requireDependency(input.repoRoot);
|
|
1151
|
+
const typed = new TypedAgentDeviceReadProvider(typedAgentDeviceIdentity({ repoRoot: input.repoRoot }));
|
|
990
1152
|
const versionsMatch = agentDeviceProviderVersionsMatch(
|
|
991
1153
|
typed.identity.version,
|
|
992
1154
|
dependency.detectedVersion,
|
|
@@ -1013,9 +1175,8 @@ async function executeSessionSnapshotBackend(
|
|
|
1013
1175
|
} else if (typed.identity.available || mode === 'typed') {
|
|
1014
1176
|
try {
|
|
1015
1177
|
return await typed.snapshot({
|
|
1016
|
-
stateDir:
|
|
1178
|
+
stateDir: runtimeStateDir(input, record),
|
|
1017
1179
|
session: record.sessionId,
|
|
1018
|
-
device: record.targetId,
|
|
1019
1180
|
platform: 'ios',
|
|
1020
1181
|
requestId: input.requestId,
|
|
1021
1182
|
cwd: input.repoRoot,
|
|
@@ -1052,7 +1213,7 @@ async function executeSessionSnapshotBackend(
|
|
|
1052
1213
|
}
|
|
1053
1214
|
}
|
|
1054
1215
|
|
|
1055
|
-
const args = compileSnapshotCommand(capabilityProfile(), request);
|
|
1216
|
+
const args = compileSnapshotCommand(capabilityProfile(input.repoRoot), request);
|
|
1056
1217
|
const result = await runJsonAsync(
|
|
1057
1218
|
input,
|
|
1058
1219
|
[...args, '--session', record.sessionId, '--platform', 'ios', '--json'],
|
|
@@ -1378,7 +1539,7 @@ async function runSessionBatch(
|
|
|
1378
1539
|
let result: unknown = await runSessionCommand(
|
|
1379
1540
|
input,
|
|
1380
1541
|
record,
|
|
1381
|
-
compileBatchCommand(capabilityProfile(), prepared.nativeSteps, MAX_BATCH_STEPS, { includeCost: true }),
|
|
1542
|
+
compileBatchCommand(capabilityProfile(input.repoRoot), prepared.nativeSteps, MAX_BATCH_STEPS, { includeCost: true }),
|
|
1382
1543
|
'AGENT_DEVICE_BATCH_FAILED',
|
|
1383
1544
|
timeoutMs,
|
|
1384
1545
|
);
|
|
@@ -1395,7 +1556,7 @@ async function runSessionBatchAttempt(
|
|
|
1395
1556
|
let result: unknown = await runSessionCommandAttempt(
|
|
1396
1557
|
input,
|
|
1397
1558
|
record,
|
|
1398
|
-
compileBatchCommand(capabilityProfile(), prepared.nativeSteps, MAX_BATCH_STEPS, { includeCost: true }),
|
|
1559
|
+
compileBatchCommand(capabilityProfile(input.repoRoot), prepared.nativeSteps, MAX_BATCH_STEPS, { includeCost: true }),
|
|
1399
1560
|
'AGENT_DEVICE_BATCH_FAILED',
|
|
1400
1561
|
timeoutMs,
|
|
1401
1562
|
);
|
|
@@ -1817,7 +1978,7 @@ async function executeJdSearch(input: AssistantPluginActionExecutionInput): Prom
|
|
|
1817
1978
|
// The current batch schema supports only status/dismiss, so Return stays
|
|
1818
1979
|
// a separate provider command, but only when the negotiated contract
|
|
1819
1980
|
// explicitly advertises it.
|
|
1820
|
-
if (!capabilityProfile().keyboard.returnSupported) {
|
|
1981
|
+
if (!capabilityProfile(input.repoRoot).keyboard.returnSupported) {
|
|
1821
1982
|
return failWorkflowSession(input, record, new AssistantPluginError(
|
|
1822
1983
|
'PLUGIN_ACTION_NOT_SUPPORTED',
|
|
1823
1984
|
'The detected agent-device contract does not support keyboard Return.',
|
|
@@ -1921,7 +2082,7 @@ export function iosAgentDeviceCapabilities(): AssistantPluginCapability[] {
|
|
|
1921
2082
|
{
|
|
1922
2083
|
capabilityId: 'ios-agent-device-physical',
|
|
1923
2084
|
title: 'agent-device physical iPhone',
|
|
1924
|
-
description: '
|
|
2085
|
+
description: 'Opt-in XCTest accessibility fallback for one exact physical iPhone. CoreDevice/RemoteXPC is the default physical-device path. Do not use agent-device for ordinary profile/form editing, Unicode text entry, screenshots, or known-coordinate interaction; use the physical-device provider and its batch fast path instead. Prepare XCTest only when semantic AX inspection is genuinely required.',
|
|
1925
2086
|
scopes: ['ios.discover', 'ios.device'],
|
|
1926
2087
|
actions,
|
|
1927
2088
|
},
|
|
@@ -1935,7 +2096,7 @@ export function iosAgentDeviceActions(): AssistantPluginActionDescriptor[] {
|
|
|
1935
2096
|
{ resource: 'repo-state' as const, mode: 'write' as const },
|
|
1936
2097
|
];
|
|
1937
2098
|
const interactionProperty = { interaction_id: { type: 'string' } };
|
|
1938
|
-
|
|
2099
|
+
const actions: AssistantPluginActionDescriptor[] = [
|
|
1939
2100
|
{
|
|
1940
2101
|
actionId: 'agent_device_status', title: 'agent-device status',
|
|
1941
2102
|
description: 'Resolve the exact executable and verify a reviewed agent-device command contract.',
|
|
@@ -1950,8 +2111,8 @@ export function iosAgentDeviceActions(): AssistantPluginActionDescriptor[] {
|
|
|
1950
2111
|
argumentsSchema: { type: 'object', properties: { app: { type: 'string' }, device: { type: 'string' }, team_id: { type: 'string' }, runner_bundle_id: { type: 'string' }, developer_dir: { type: 'string' } }, additionalProperties: false },
|
|
1951
2112
|
},
|
|
1952
2113
|
{
|
|
1953
|
-
actionId: 'agent_device_prepare', title: 'Prepare
|
|
1954
|
-
description: '
|
|
2114
|
+
actionId: 'agent_device_prepare', title: 'Prepare semantic XCTest fallback',
|
|
2115
|
+
description: 'Explicitly build, sign, install and health-check the agent-device XCTest Runner. This is a heavy semantic fallback, not the normal physical-iPhone form-edit path. Physical-device preparation uses one stable per-device runtime so repeated semantic interactions can reuse it.',
|
|
1955
2116
|
readOnly: false, risk: 'workspace_write', confirmation: 'authorization', defaultTimeoutMs: 10 * 60_000, cancellable: true, idempotent: false,
|
|
1956
2117
|
scopes: ['ios.discover', 'ios.simulator', 'ios.device'], resourceClaims: write,
|
|
1957
2118
|
argumentsSchema: {
|
|
@@ -1961,7 +2122,7 @@ export function iosAgentDeviceActions(): AssistantPluginActionDescriptor[] {
|
|
|
1961
2122
|
},
|
|
1962
2123
|
{
|
|
1963
2124
|
actionId: 'agent_device_open', title: 'Open agent-device iOS session',
|
|
1964
|
-
description: 'Open an
|
|
2125
|
+
description: 'Open an agent-device semantic session on one exact physical iPhone or booted Simulator. On physical iPhone this may start/reconnect an XCTest Runner; prefer physical_device_open plus physical_device_batch for ordinary app navigation and profile/form edits.',
|
|
1965
2126
|
readOnly: false, risk: 'workspace_write', confirmation: 'authorization', defaultTimeoutMs: 4 * 60_000, cancellable: true, idempotent: false,
|
|
1966
2127
|
scopes: ['ios.simulator', 'ios.device'], resourceClaims: write,
|
|
1967
2128
|
argumentsSchema: {
|
|
@@ -1971,7 +2132,7 @@ export function iosAgentDeviceActions(): AssistantPluginActionDescriptor[] {
|
|
|
1971
2132
|
},
|
|
1972
2133
|
{
|
|
1973
2134
|
actionId: 'agent_device_batch', title: 'Run fast typed iOS action batch',
|
|
1974
|
-
description: `Run up to ${MAX_BATCH_STEPS}
|
|
2135
|
+
description: `Run up to ${MAX_BATCH_STEPS} semantic AX steps in one agent-device process and one daemon request. Mutating steps settle before the next step. On a physical iPhone, use this only when accessibility semantics are required; known-coordinate/form workflows should use physical_device_batch to avoid XCTest lifecycle cost.`,
|
|
1975
2136
|
readOnly: false, risk: 'workspace_write', confirmation: 'authorization', defaultTimeoutMs: 2 * 60_000, cancellable: true, idempotent: false,
|
|
1976
2137
|
scopes: ['ios.simulator', 'ios.device'], resourceClaims: write,
|
|
1977
2138
|
argumentsSchema: {
|
|
@@ -2023,7 +2184,7 @@ export function iosAgentDeviceActions(): AssistantPluginActionDescriptor[] {
|
|
|
2023
2184
|
},
|
|
2024
2185
|
{
|
|
2025
2186
|
actionId: 'agent_device_press', title: 'Press agent-device target',
|
|
2026
|
-
description: 'Press one ref, selector, or explicit coordinate pair
|
|
2187
|
+
description: 'Press one ref, selector, or explicit coordinate pair. Semantic targets return a settled bounded diff; explicit coordinates bypass accessibility settle for heavy-screen recovery.',
|
|
2027
2188
|
readOnly: false, risk: 'workspace_write', confirmation: 'authorization', defaultTimeoutMs: 60_000, cancellable: true, idempotent: false,
|
|
2028
2189
|
scopes: ['ios.simulator', 'ios.device'], resourceClaims: write,
|
|
2029
2190
|
argumentsSchema: { type: 'object', properties: { ...interactionProperty, target: { type: 'string' }, x: { type: 'number' }, y: { type: 'number' } }, required: ['interaction_id'], additionalProperties: false },
|
|
@@ -2064,13 +2225,16 @@ export function iosAgentDeviceActions(): AssistantPluginActionDescriptor[] {
|
|
|
2064
2225
|
argumentsSchema: { type: 'object', properties: { ...interactionProperty, shutdown_simulator: { type: 'boolean' } }, required: ['interaction_id'], additionalProperties: false },
|
|
2065
2226
|
},
|
|
2066
2227
|
];
|
|
2228
|
+
return actions.map((action) => action.readOnly
|
|
2229
|
+
? action
|
|
2230
|
+
: { ...action, executionMode: 'lightweight_process' });
|
|
2067
2231
|
}
|
|
2068
2232
|
|
|
2069
2233
|
export async function executeIosAgentDeviceAction(input: AssistantPluginActionExecutionInput): Promise<Record<string, unknown>> {
|
|
2070
2234
|
if (input.deadlineAtMs === undefined && typeof input.timeoutMs === 'number' && Number.isFinite(input.timeoutMs)) {
|
|
2071
2235
|
input = { ...input, deadlineAtMs: Date.now() + Math.max(1, Math.trunc(input.timeoutMs)) };
|
|
2072
2236
|
}
|
|
2073
|
-
if (input.actionId === 'agent_device_status') return { provider: 'agent-device', ...
|
|
2237
|
+
if (input.actionId === 'agent_device_status') return { provider: 'agent-device', ...await iosAgentDeviceActionStatus(input) };
|
|
2074
2238
|
if (input.actionId === 'agent_device_close') {
|
|
2075
2239
|
const interactionId = requireString(input.args.interaction_id, 'interaction_id');
|
|
2076
2240
|
const existing = readAgentDeviceInteraction(input.repoRoot, interactionId);
|
|
@@ -2078,7 +2242,7 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
|
|
|
2078
2242
|
return { provider: 'agent-device', interaction: existing, alreadyClosed: true };
|
|
2079
2243
|
}
|
|
2080
2244
|
}
|
|
2081
|
-
const dependency =
|
|
2245
|
+
const dependency = await requireDependencyAsync(input);
|
|
2082
2246
|
|
|
2083
2247
|
if (input.actionId === 'agent_device_jd_search') return executeJdSearch(input);
|
|
2084
2248
|
|
|
@@ -2096,6 +2260,7 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
|
|
|
2096
2260
|
physicalDeviceSupported: selected.kind === 'device',
|
|
2097
2261
|
result: bounded(await runJsonAsync(input, args, {
|
|
2098
2262
|
signing: signingFromArgs(input.args),
|
|
2263
|
+
stateDir: targetRuntimeStateDir(input, selected),
|
|
2099
2264
|
failureCode: 'AGENT_DEVICE_DOCTOR_FAILED',
|
|
2100
2265
|
timeoutMs: 4 * 60_000,
|
|
2101
2266
|
})),
|
|
@@ -2115,6 +2280,7 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
|
|
|
2115
2280
|
'prepare', 'ios-runner', '--platform', 'ios', '--device', selected.name, '--timeout', '600000', '--json',
|
|
2116
2281
|
], {
|
|
2117
2282
|
signing,
|
|
2283
|
+
stateDir: targetRuntimeStateDir(input, selected),
|
|
2118
2284
|
failureCode: 'AGENT_DEVICE_PREPARE_FAILED',
|
|
2119
2285
|
timeoutMs: 10 * 60_000,
|
|
2120
2286
|
})),
|
|
@@ -2223,11 +2389,15 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
|
|
|
2223
2389
|
if (record.provider === DEVICE_PROVIDER && target && SENSITIVE_SEMANTICS.test(target)) {
|
|
2224
2390
|
throw new AssistantPluginError('IOS_DEVICE_SENSITIVE_ACTION_BLOCKED', 'Press targets involving credentials, verification, biometrics, checkout, purchase or payment require human interaction.', { retryable: false });
|
|
2225
2391
|
}
|
|
2226
|
-
const
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2392
|
+
const baseArgs = ['press', ...(target ? [target] : [String(input.args.x), String(input.args.y)])];
|
|
2393
|
+
// Explicit coordinate presses are the bounded fallback for screens whose
|
|
2394
|
+
// accessibility tree is too heavy or animated to snapshot reliably.
|
|
2395
|
+
// Settling forces an AX snapshot after the mutation, defeating that
|
|
2396
|
+
// fallback and can recycle/wedge the XCTest runner. Keep semantic target
|
|
2397
|
+
// presses settled, but let explicit points complete without AX capture.
|
|
2398
|
+
const args = target
|
|
2399
|
+
? appendSettleFlag(capabilityProfile(input.repoRoot), baseArgs, 'press')
|
|
2400
|
+
: baseArgs;
|
|
2231
2401
|
return { provider: 'agent-device', interaction: record, result: bounded(await runSessionCommand(input, record, args, 'AGENT_DEVICE_PRESS_FAILED')) };
|
|
2232
2402
|
}
|
|
2233
2403
|
case 'agent_device_fill': {
|
|
@@ -2237,7 +2407,7 @@ export async function executeIosAgentDeviceAction(input: AssistantPluginActionEx
|
|
|
2237
2407
|
if (record.provider === DEVICE_PROVIDER && (SENSITIVE_SEMANTICS.test(target) || SENSITIVE_SEMANTICS.test(text))) {
|
|
2238
2408
|
throw new AssistantPluginError('IOS_DEVICE_SENSITIVE_ACTION_BLOCKED', 'Sensitive text and credential, verification, checkout, purchase or payment targets require human interaction.', { retryable: false });
|
|
2239
2409
|
}
|
|
2240
|
-
const profile = capabilityProfile();
|
|
2410
|
+
const profile = capabilityProfile(input.repoRoot);
|
|
2241
2411
|
const args = appendSettleFlag(profile, ['fill', target, text]);
|
|
2242
2412
|
if (typeof input.args.delay_ms === 'number') {
|
|
2243
2413
|
if (!profile.fill.delayFlag) {
|