@moretea-labs/forge 1.8.0 → 1.8.2
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 +73 -7
- package/CHANGELOG.md +34 -0
- package/CLAUDE.md +17 -2
- package/CONTRIBUTING.md +3 -2
- package/README.en.md +24 -3
- package/README.md +10 -6
- package/README.zh-CN.md +5 -3
- package/THIRD_PARTY_NOTICES.md +1 -2
- package/adapters/chatgpt/browser-delivery-host.ts +7 -1
- package/adapters/chatgpt/browser-delivery-runtime.ts +531 -56
- package/adapters/chatgpt/controller-binding-store.ts +101 -22
- package/adapters/chatgpt/controller-round-host.ts +15 -25
- package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
- package/adapters/chatgpt/provider-delivery.ts +229 -2
- package/adapters/chatgpt/work-conversation-binding-store.ts +99 -54
- package/adapters/computer/chatgpt-extension-target.ts +708 -0
- package/adapters/computer/chrome-extension/background.js +541 -0
- package/adapters/computer/chrome-extension/content.js +402 -0
- package/adapters/computer/chrome-extension/core.js +24 -0
- package/adapters/computer/chrome-extension/manifest.json +32 -0
- package/adapters/computer/desktop-operator-discovery.ts +11 -31
- package/adapters/computer/desktop-operator-provider.ts +18 -6
- package/adapters/computer/interaction-target-authority.ts +178 -24
- package/adapters/mcp/access-mode.ts +18 -39
- package/adapters/mcp/auth.ts +2 -7
- package/adapters/mcp/instructions.ts +6 -5
- package/adapters/mcp/multi-repository.ts +10 -47
- package/adapters/mcp/oauth.ts +73 -0
- package/adapters/mcp/paths.ts +4 -1
- package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
- package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
- package/adapters/mcp/runtime-gateway/context-adapter.ts +490 -113
- package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +83 -0
- package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
- package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
- package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
- package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
- package/adapters/mcp/runtime-gateway/execution-tools.ts +14 -54
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
- package/adapters/mcp/runtime-gateway/plugin-adapter.ts +132 -47
- package/adapters/mcp/runtime-gateway/process-tools.ts +173 -23
- package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
- package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
- package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
- package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
- package/adapters/mcp/runtime-gateway/router.ts +19 -507
- package/adapters/mcp/runtime-gateway/routing-policy.ts +506 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +15 -66
- package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +123 -178
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +11 -5
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +37 -1
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +416 -270
- package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +140 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +262 -3123
- package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
- package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
- package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +229 -0
- package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
- package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
- package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
- package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
- package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
- package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +320 -0
- package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
- package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +180 -0
- package/adapters/mcp/server.ts +91 -26
- package/adapters/mcp/setup.ts +5 -13
- package/adapters/mcp/tool-mapping/access-tools.ts +0 -6
- package/adapters/mcp/tool-mapping/legacy-tool-service.ts +703 -3092
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +5 -10
- package/adapters/mcp/tool-mapping/repository-tools.ts +170 -213
- package/adapters/mcp/toolset-names.ts +11 -37
- package/adapters/mcp/toolset.ts +19 -92
- package/{src/cli → adapters}/mcp/transports/AGENTS.md +5 -5
- package/{src/cli → adapters}/mcp/transports/CLAUDE.md +5 -5
- package/adapters/mcp/transports/http-observation.ts +377 -0
- package/adapters/mcp/transports/http-post-lifecycle.ts +19 -0
- package/adapters/mcp/transports/http.ts +200 -683
- package/adapters/mcp/transports/oauth-http.ts +322 -0
- package/adapters/mcp/transports/session-registry.ts +6 -0
- package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
- package/adapters/mcp/types.ts +0 -6
- package/assets/hooks/lib/session-state.sh +0 -38
- package/assets/hooks/post-bash.sh +1 -1
- package/assets/hooks/post-tool-observer.sh +0 -5
- package/assets/hooks/prompt-guard.sh +0 -55
- package/assets/partials/04-project-structure.partial.md +1 -1
- package/assets/partials/07-footer.partial.md +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +1 -1
- package/assets/partials-agents/08-deep-docs.partial.md +1 -1
- package/assets/plugin-registry.v1.json +6 -4
- package/assets/reference-configs/agentic-development-flow.md +26 -1
- package/assets/reference-configs/external-tooling.md +0 -76
- package/assets/reference-configs/global-working-rules.md +19 -0
- package/assets/reference-configs/release-deploy.md +1 -1
- package/assets/templates/helpers/architecture-queue.sh +1 -1
- package/assets/templates/helpers/check-agent-tooling.sh +1 -327
- package/assets/templates/helpers/check-task-workflow.sh +1 -1
- package/assets/templates/helpers/ensure-task-workflow.sh +0 -14
- package/assets/templates/helpers/migrate-project-template.sh +2 -2
- package/assets/workflow-contract.v1.json +0 -2
- package/docs/README.md +5 -2
- package/docs/architecture/CURRENT.md +205 -51
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
- package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +42 -0
- package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
- package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
- package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
- package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
- package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +234 -0
- package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
- package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +74 -0
- package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +342 -0
- package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
- package/docs/architecture/decisions/20261009-exact-code-context-discovery.md +19 -0
- package/docs/architecture/decisions/20261009-generated-xcode-cache-retention.md +37 -0
- package/docs/architecture/decisions/20261011-autonomous-continuation-convergence.md +597 -0
- package/docs/architecture/decisions/20261017-edit-session-finalization-reconciliation.md +17 -0
- package/docs/architecture/decisions/20261019-retire-host-skills.md +16 -0
- package/docs/architecture/diagrams/agentic-dev-plugin-architecture.html +1 -1
- package/docs/architecture/domains/public-surface.md +3 -5
- package/docs/architecture/domains/verification.md +6 -5
- package/docs/architecture/domains/workflow-engine.md +6 -0
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +3 -3
- package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +4 -4
- package/docs/architecture/reviews/20261015-code-search-runtime-acceptance.md +75 -0
- package/docs/forge-plugin-management.md +16 -4
- package/docs/operations/controller-browser-plugin.md +23 -0
- package/docs/operations/controller-performance-and-502.md +17 -0
- package/docs/operations/controller-reliability-runbook.md +2 -2
- package/docs/operations/features.md +6 -7
- package/docs/operations/features.zh-CN.md +1 -1
- package/docs/operations/github-repository.md +4 -4
- package/docs/operations/github-semantic-release-projection.md +20 -0
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +13 -52
- package/docs/operations/releasing.md +2 -0
- package/docs/operations/runtime-performance-diagnostics.md +8 -0
- package/docs/operations/standalone-disaster-recovery.md +15 -7
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/tutorials/03-first-repository-task.md +2 -0
- package/docs/wiki/Computer-and-Plugins.md +78 -0
- package/docs/wiki/Computer-and-Plugins.zh-CN.md +88 -0
- package/docs/wiki/Home.md +16 -2
- package/docs/wiki/Implementation.md +25 -13
- package/docs/wiki/Installation.md +28 -32
- package/docs/wiki/Integrations.md +4 -0
- package/docs/wiki/Quick-Start.md +35 -22
- package/docs/wiki/Releases-and-Upgrades.md +15 -25
- package/docs/wiki/_Sidebar.md +5 -1
- package/package.json +25 -25
- package/packages/kernel/cognition/api/index.ts +6 -0
- package/packages/kernel/cognition/application/activation-service.ts +451 -0
- package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
- package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
- package/packages/kernel/cognition/application/memory-service.ts +64 -0
- package/packages/kernel/cognition/domain/learning.ts +106 -0
- package/packages/kernel/cognition/domain/memory.ts +254 -0
- package/packages/kernel/controller/api/index.ts +1 -0
- package/packages/kernel/controller/application/continuation-service.ts +281 -0
- package/packages/kernel/controller/application/controller-round-service.ts +12 -0
- package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
- package/packages/kernel/controller/domain/controller-round.ts +4 -1
- package/packages/kernel/controller/domain/execution-quality.ts +3 -1
- package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
- package/packages/kernel/controller/infrastructure/controller-session-store.ts +348 -97
- package/packages/kernel/controller/ports/controller-host.ts +2 -0
- package/packages/kernel/identity/api/index.ts +10 -0
- package/packages/kernel/identity/domain/activity-projection.ts +43 -0
- package/packages/kernel/identity/domain/capability-broker.ts +60 -0
- package/packages/kernel/identity/domain/grant.ts +72 -0
- package/packages/kernel/identity/domain/owned-resource.ts +116 -0
- package/packages/kernel/identity/domain/user-request.ts +93 -0
- package/packages/kernel/identity/infrastructure/activity-projection-store.ts +87 -0
- package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
- package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
- package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
- package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
- package/packages/kernel/scheduler/api/index.ts +0 -2
- package/packages/kernel/scheduler/application/eligibility.ts +4 -1
- package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
- package/packages/kernel/scheduler/application/settlement.ts +0 -15
- package/packages/kernel/scheduler/domain/schedule.ts +87 -0
- package/packages/kernel/scheduler/infrastructure/schedule-store.ts +166 -143
- package/packages/kernel/work/api/index.ts +3 -2
- package/packages/kernel/work/application/work-service.ts +18 -42
- package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
- package/packages/kernel/work/domain/engineering-design.ts +10 -5
- package/packages/kernel/work/domain/engineering-profile.ts +8 -12
- package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
- package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
- package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
- package/packages/kernel/work/domain/implementation-review.ts +14 -331
- package/packages/kernel/work/domain/objective-graph.ts +119 -0
- package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
- package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
- package/packages/kernel/work/domain/state-machine.ts +34 -65
- package/packages/kernel/work/domain/types.ts +57 -51
- package/packages/kernel/work/infrastructure/work-contract-store.ts +847 -729
- package/packages/kernel/work/ports/work-contract-store.ts +5 -2
- package/packages/plugin-runtime/browser/provider-registry.ts +12 -36
- package/packages/plugin-runtime/browser/session-authority.ts +2 -1
- package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
- package/packages/plugin-runtime/computer/conversation-target.ts +153 -0
- package/packages/plugin-runtime/computer/index.ts +2 -0
- package/packages/plugin-runtime/computer/target-authority.ts +26 -1
- package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
- package/packages/protocols/computer/contract.ts +27 -1
- package/scripts/activate-source-baseline.ts +7 -9
- package/scripts/assemble-template.ts +11 -72
- package/scripts/canary-controller-semantic-wait.ts +12 -24
- package/scripts/check-mcp-compatibility.ts +94 -201
- package/scripts/check-package-identity.mjs +0 -5
- package/scripts/check-runtime-architecture.mjs +921 -239
- package/scripts/forge-local-recovery-helper.mjs +93 -15
- package/scripts/init-project.sh +0 -46
- package/scripts/install-ios-hid-toolchain.sh +60 -0
- package/scripts/install-standalone-recovery.ts +1 -1
- package/scripts/lib/project-init-lib.sh +6 -3
- package/scripts/migrate-windows-wsl-controller-home.ts +2 -0
- package/scripts/open-source-audit-allowlist.txt +1 -3
- package/scripts/run-bounded-command.mjs +5 -0
- package/scripts/run-governed-gate.ts +2 -1
- package/scripts/run-mobile-monitor-bridge.ts +0 -1
- package/scripts/smoke-control-plane-failure-domain.ts +94 -0
- package/scripts/smoke-ios-physical-device.ts +38 -10
- package/scripts/smoke-mcp-http-runtime.ts +12 -8
- package/scripts/smoke-mcp-tool-surface.ts +27 -41
- package/scripts/smoke-runtime-recovery.ts +12 -43
- package/scripts/smoke-schedule-engine.ts +23 -15
- package/scripts/smoke-unattended-transport-recovery.ts +223 -0
- package/scripts/smoke-user-request-continuation-restart.ts +232 -0
- package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +95 -0
- package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
- package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
- package/scripts/smoke-workflow-supervisor.ts +103 -0
- package/scripts/sync-generated-authority.mjs +0 -1
- package/scripts/verify-forge-runtime.sh +2 -1
- package/src/cli/agent-jobs/executor-health.ts +12 -35
- package/src/cli/agent-jobs/integration.ts +20 -51
- package/src/cli/agent-jobs/job-manager.ts +7 -3
- package/src/cli/chatgpt-browser/file-policy.ts +2 -2
- package/src/cli/commands/brain-assistant.ts +27 -13
- package/src/cli/commands/brain.ts +13 -15
- package/src/cli/commands/chatgpt.ts +1 -163
- package/src/cli/commands/doctor.ts +1 -143
- package/src/cli/commands/global-runtime.ts +3 -196
- package/src/cli/commands/init-hook.ts +6 -23
- package/src/cli/commands/init.ts +3 -252
- package/src/cli/commands/mcp.ts +0 -5
- package/src/cli/commands/prompt-guard-decision.ts +0 -2
- package/src/cli/commands/recovery.ts +137 -135
- package/src/cli/commands/repository.ts +17 -1
- package/src/cli/commands/runtime.ts +3 -3
- package/src/cli/commands/setup-execution.ts +41 -0
- package/src/cli/commands/setup-profile.ts +8 -0
- package/src/cli/controller/check-runner.ts +13 -2
- package/src/cli/controller/completion-backlog.ts +3 -3
- package/src/cli/controller/completion-orchestrator.ts +5 -44
- package/src/cli/controller/completion-target.ts +3 -72
- package/src/cli/controller/composite-operations.ts +1 -1
- package/src/cli/controller/context/instruction-context.ts +1 -1
- package/src/cli/controller/context/known-paths.ts +2 -2
- package/src/cli/controller/context/query-planning.ts +11 -4
- package/src/cli/controller/context/rule-resolution.ts +2 -2
- package/src/cli/controller/context/source-materializer.ts +83 -102
- package/src/cli/controller/context/structural-provider.ts +84 -0
- package/src/cli/controller/context/structural.ts +6 -6
- package/src/cli/controller/context/types.ts +8 -9
- package/src/cli/controller/context-pack.ts +107 -84
- package/src/cli/controller/execution-completion.ts +4 -7
- package/src/cli/controller/execution-policy.ts +36 -153
- package/src/cli/controller/governance.ts +2 -3
- package/src/cli/controller/issue-store.ts +4 -99
- package/src/cli/controller/launch-agents.ts +59 -18
- package/src/cli/controller/operational-plan.ts +25 -52
- package/src/cli/controller/runtime-config.ts +5 -1
- package/src/cli/controller/stuck-state-migration.ts +2 -3
- package/src/cli/controller/systemd-user.ts +42 -10
- package/src/cli/editing/edit-session.ts +18 -12
- package/src/cli/github/github.ts +4 -4
- package/src/cli/github/semantic-projection.ts +174 -0
- package/src/cli/hook/prompt-intents.ts +0 -9
- package/src/cli/index.ts +1 -43
- package/src/cli/local-bridge/connector-freshness.ts +1 -12
- package/src/cli/local-bridge/console-automations.ts +19 -14
- package/src/cli/local-bridge/console-view-models.ts +4 -13
- package/src/cli/local-bridge/facade-api.ts +64 -193
- package/src/cli/local-bridge/server.ts +24 -147
- package/src/cli/local-bridge/types.ts +0 -1
- package/src/cli/mcp/oauth-client-retirement.ts +74 -0
- package/src/cli/repositories/command-classifier.ts +0 -9
- package/src/cli/repositories/command-executor.ts +29 -23
- package/src/cli/repositories/command-scope.ts +37 -18
- package/src/cli/repositories/controller-home.ts +48 -0
- package/src/cli/repositories/ephemeral-workspace.ts +20 -30
- package/src/cli/repositories/git-command-executor.ts +2 -2
- package/src/cli/repositories/locks.ts +20 -0
- package/src/cli/repositories/registry.ts +79 -12
- package/src/cli/repositories/safe-patch.ts +2 -12
- package/src/cli/repositories/structured-git.ts +101 -5
- package/src/cli/repository/inspector.ts +185 -343
- package/src/cli/repository/session-cache.ts +92 -6
- package/src/effects/process-runner.ts +17 -1
- package/src/runtime/context/assistant-context.ts +20 -7
- package/src/runtime/context/assistant-work-context.ts +89 -27
- package/src/runtime/context/automatic-learning.ts +565 -0
- package/src/runtime/context/cognitive-attention.ts +173 -0
- package/src/runtime/context/cognitive-skill-canary.ts +158 -0
- package/src/runtime/context/context-closure.ts +46 -9
- package/src/runtime/context/context-pack-process.ts +103 -0
- package/src/runtime/context/context-plane.ts +1 -9
- package/src/runtime/context/direct-controller-learning.ts +298 -0
- package/src/runtime/context/generic-lsp-provider.ts +1 -1
- package/src/runtime/context/semantic-navigation-contract.ts +16 -0
- package/src/runtime/context/semantic-navigation.ts +7 -35
- package/src/runtime/context/typescript-navigation-process.ts +145 -0
- package/src/runtime/context/typescript-navigation.ts +89 -3
- package/src/runtime/control-plane/cleanup-artifact-retention.ts +215 -12
- package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
- package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
- package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
- package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
- package/src/runtime/control-plane/execution/session-store.ts +31 -1
- package/src/runtime/control-plane/execution/validation.ts +6 -8
- package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
- package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
- package/src/runtime/control-plane/execution/work-delivery-service.ts +616 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
- package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
- package/src/runtime/control-plane/execution/work-handle-authority.ts +197 -110
- package/src/runtime/control-plane/execution/work-handle-store.ts +72 -44
- package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
- package/src/runtime/control-plane/execution/work-operation-service.ts +60 -34
- package/src/runtime/control-plane/execution/work-preparation-service.ts +231 -267
- package/src/runtime/control-plane/execution/work-process-evidence.ts +2 -2
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
- package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +201 -199
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +33 -85
- package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +6 -2
- package/src/runtime/control-plane/facade/capability-registry.ts +364 -37
- package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
- package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
- package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
- package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
- package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
- package/src/runtime/control-plane/facade/index.ts +0 -1
- package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
- package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
- package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
- package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
- package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
- package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
- package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
- package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
- package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
- package/src/runtime/control-plane/facade/types.ts +49 -108
- package/src/runtime/control-plane/facade/work-continuation.ts +9 -9
- package/src/runtime/control-plane/generated-cache-retention.ts +206 -59
- package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +256 -117
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -12
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
- package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
- package/src/runtime/control-plane/governance/access-policy.ts +19 -2
- package/src/runtime/control-plane/governance/authorization.ts +20 -3
- package/src/runtime/control-plane/governance/external-effects.ts +1 -1
- package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +29 -300
- package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
- package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
- package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
- package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
- package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
- package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
- package/src/runtime/control-plane/release-retention.ts +135 -47
- package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
- package/src/runtime/control-plane/runtime-cleanup.ts +295 -107
- package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
- package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
- package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
- package/src/runtime/diagnostics/incident-repair.ts +313 -146
- package/src/runtime/diagnostics/mcp-timing.ts +114 -0
- package/src/runtime/evidence/artifact-store.ts +158 -40
- package/src/runtime/evidence/evidence-store.ts +112 -8
- package/src/runtime/evidence/output-handle-index.ts +225 -0
- package/src/runtime/evidence/result-store.ts +158 -44
- package/src/runtime/evidence/sensitive-output.ts +22 -2
- package/src/runtime/execution/jobs/child-reference.ts +11 -0
- package/src/runtime/execution/jobs/receipt-recovery.ts +1 -11
- package/src/runtime/execution/jobs/store.ts +3 -4
- package/src/runtime/execution/managed-workspace.ts +57 -0
- package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
- package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
- package/src/runtime/execution/process-runtime/check-result.ts +105 -1
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
- package/src/runtime/execution/process-runtime/command-facade.ts +82 -30
- package/src/runtime/execution/process-runtime/gc.ts +15 -2
- package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
- package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
- package/src/runtime/execution/process-runtime/index.ts +3 -0
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
- package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
- package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
- package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
- package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
- package/src/runtime/execution/process-runtime/runtime.ts +55 -18
- package/src/runtime/execution/process-runtime/store.ts +30 -2
- package/src/runtime/execution/process-runtime/types.ts +6 -1
- package/src/runtime/execution/thin-harness/execution-router.ts +16 -16
- package/src/runtime/execution/thin-harness/fast-executor.ts +2 -2
- package/src/runtime/execution/thin-harness/search-worker.ts +2 -2
- package/src/runtime/execution/workers/executor.ts +3 -8
- package/src/runtime/maintenance/cleanup.ts +41 -5
- package/src/runtime/platform/service-inventory.ts +130 -0
- package/src/runtime/platform/service-manager.ts +8 -0
- package/src/runtime/plugins/action-application.ts +97 -29
- package/src/runtime/plugins/app-store-connect-adapter.ts +290 -18
- package/src/runtime/plugins/browser-adapter.ts +1124 -333
- package/src/runtime/plugins/browser-automation-service.ts +23 -3
- package/src/runtime/plugins/browser-macos-bridge.ts +431 -137
- package/src/runtime/plugins/browser-manifest-surface.ts +47 -12
- package/src/runtime/plugins/browser-native-session-service.ts +63 -13
- package/src/runtime/plugins/browser-registration.ts +18 -0
- package/src/runtime/plugins/browser-runtime.ts +40 -36
- package/src/runtime/plugins/browser-session-authority.ts +2 -2
- package/src/runtime/plugins/browser-session-store.ts +46 -76
- package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
- package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +228 -0
- package/src/runtime/plugins/computer-registration.ts +298 -20
- package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
- package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
- package/src/runtime/plugins/external-adapter.ts +42 -6
- package/src/runtime/plugins/external-registration.ts +21 -1
- package/src/runtime/plugins/github-adapter.ts +30 -3
- package/src/runtime/plugins/gmail-adapter.ts +189 -3
- package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
- package/src/runtime/plugins/google-shared.ts +24 -12
- package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
- package/src/runtime/plugins/ios/remote-xpc-hid.ts +70 -30
- package/src/runtime/plugins/ios-adapter.ts +46 -41
- package/src/runtime/plugins/ios-agent-device.ts +54 -4
- package/src/runtime/plugins/ios-device-ownership.ts +103 -0
- package/src/runtime/plugins/ios-physical-device.ts +497 -79
- package/src/runtime/plugins/lightweight-action.ts +208 -2
- package/src/runtime/plugins/local-system-adapter.ts +12 -100
- package/src/runtime/plugins/managed-process-adapter.ts +12 -5
- package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
- package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +682 -435
- package/src/runtime/plugins/types.ts +24 -0
- package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
- package/src/runtime/projections/git-status-sampler.ts +2 -19
- package/src/runtime/projections/invalidation.ts +7 -3
- package/src/runtime/projections/materialized-view.ts +80 -36
- package/src/runtime/recovery/actions.ts +4 -4
- package/src/runtime/recovery/capability-action-application.ts +46 -45
- package/src/runtime/recovery/lifecycle-inventory.ts +30 -40
- package/src/runtime/recovery/maintenance-executor.ts +374 -123
- package/src/runtime/recovery/probe.ts +2 -2
- package/src/runtime/recovery/store.ts +29 -11
- package/src/runtime/release/release-coordinator.ts +312 -0
- package/src/runtime/release/release-session.ts +716 -0
- package/src/runtime/release/release-state-migration.ts +25 -0
- package/src/runtime/resources/leases/store.ts +56 -25
- package/src/runtime/root/computer-composition.ts +191 -6
- package/src/runtime/root/controller-progression-composition.ts +254 -0
- package/src/runtime/root/controller-round-composition.ts +20 -1
- package/src/runtime/root/deployment-topology.ts +106 -0
- package/src/runtime/root/entry.ts +4 -3
- package/src/runtime/root/known-good-recovery.ts +184 -0
- package/src/runtime/root/local-bridge.ts +0 -1
- package/src/runtime/root/mcp-transport.ts +111 -18
- package/src/runtime/root/ownership.ts +261 -9
- package/src/runtime/root/package-connector-service.ts +227 -29
- package/src/runtime/root/package-runtime-release.ts +117 -30
- package/src/runtime/root/package-runtime-service.ts +24 -24
- package/src/runtime/root/release-execution-canary.ts +57 -12
- package/src/runtime/root/release-loader.ts +90 -8
- package/src/runtime/root/release-manifest.ts +80 -40
- package/src/runtime/root/release-materialize.ts +372 -106
- package/src/runtime/root/release-store.ts +395 -36
- package/src/runtime/root/runtime-lane.ts +191 -0
- package/src/runtime/root/runtime.ts +160 -29
- package/src/runtime/root/scheduled-controller-composition.ts +29 -3
- package/src/runtime/root/service-runner.ts +2 -2
- package/src/runtime/root/service.ts +126 -44
- package/src/runtime/root/status.ts +48 -0
- package/src/runtime/root/types.ts +32 -9
- package/src/runtime/root/workflow-supervisor-composition.ts +681 -0
- package/src/runtime/root/workflow-supervisor-runtime.ts +564 -0
- package/src/runtime/root/write-fence.ts +50 -2
- package/src/runtime/safe-tooling/google-credential-store.ts +67 -22
- package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
- package/src/runtime/safe-tooling/ios-development.ts +22 -8
- package/src/runtime/safe-tooling/job-summary.ts +1 -1
- package/src/runtime/safe-tooling/workspace-auth.ts +5 -2
- package/src/runtime/shared/atomic-text-file.ts +21 -0
- package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
- package/src/runtime/shared/json-files.ts +8 -3
- package/src/runtime/shared/process-environment.ts +20 -9
- package/src/runtime/shared/response-budget.ts +1 -3
- package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
- package/src/runtime/standalone-recovery/core.ts +3792 -417
- package/src/runtime/standalone-recovery/entry.ts +507 -45
- package/src/runtime/standalone-recovery/installer.ts +262 -148
- package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
- package/src/runtime/standalone-recovery/operation-lock.ts +12 -2
- package/src/runtime/standalone-recovery/performance.ts +54 -16
- package/src/runtime/standalone-recovery/release.ts +53 -5
- package/src/runtime/standalone-recovery/service-labels.ts +5 -2
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
- package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +11 -3
- package/src/runtime/workflow/schedules/engine.ts +166 -178
- package/src/runtime/workflow/schedules/pending-activation.ts +11 -4
- package/src/runtime/workflow/schedules/work-continuation.ts +95 -11
- package/src/runtime/workflows/runtime.ts +15 -19
- package/src/testing/test-governance.ts +5 -1
- package/supervisor/chatgpt-conversation.ts +23 -0
- package/supervisor/client.ts +218 -0
- package/supervisor/control-plane.ts +963 -0
- package/supervisor/entry.ts +15 -0
- package/supervisor/forge-validators.ts +147 -0
- package/supervisor/index.ts +5 -0
- package/supervisor/native-browser-adapter.ts +1151 -0
- package/supervisor/native-messaging/host.ts +58 -0
- package/supervisor/native-messaging/manifest.ts +26 -0
- package/supervisor/native-messaging/protocol.ts +27 -0
- package/supervisor/paths.ts +18 -0
- package/supervisor/protocol.ts +250 -0
- package/supervisor/server.ts +412 -0
- package/supervisor/store.ts +1870 -0
- package/supervisor/tsconfig.json +8 -0
- package/supervisor/types.ts +261 -0
- package/SKILL.md +0 -427
- package/adapters/chatgpt/controller-host.ts +0 -119
- package/adapters/mcp/controller-round-compatibility.ts +0 -184
- package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
- package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
- package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +0 -1
- package/adapters/mcp/toolset-selection.ts +0 -41
- package/agents/openai.yaml +0 -4
- package/assets/skill-hooks.json +0 -41
- package/assets/skill-version.json +0 -189
- package/assets/skills/claude-review/SKILL.md +0 -231
- package/assets/skills/codex-review/SKILL.md +0 -103
- package/assets/templates/helpers/check-skill-version.ts +0 -193
- package/packages/kernel/progression/api/index.ts +0 -2
- package/packages/kernel/progression/application/projector.ts +0 -211
- package/packages/kernel/progression/domain/types.ts +0 -116
- package/packages/kernel/progression/index.ts +0 -1
- package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
- package/packages/kernel/scheduler/domain/continuation.ts +0 -38
- package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
- package/packages/kernel/work/domain/admission-policy.ts +0 -34
- package/scripts/benchmark-background-check-overlap.ts +0 -228
- package/scripts/benchmark-computer-hotpath.ts +0 -255
- package/scripts/benchmark-controller-hotpath.ts +0 -212
- package/scripts/benchmark-controller-round2.ts +0 -191
- package/scripts/benchmark-ios-agent-device.ts +0 -511
- package/scripts/benchmark-mcp-host.sh +0 -117
- package/scripts/benchmark-mcp-transport.ts +0 -169
- package/scripts/benchmark-operational-memory-activation.ts +0 -235
- package/scripts/benchmark-operational-shadow.ts +0 -28
- package/scripts/benchmark-quality-harness.ts +0 -146
- package/scripts/benchmark-route-session-concurrency.ts +0 -915
- package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
- package/scripts/benchmark-thin-harness.ts +0 -251
- package/scripts/benchmark-typescript-navigation.ts +0 -186
- package/scripts/benchmark-work-efficiency.ts +0 -334
- package/scripts/build-controller-ui.ts +0 -28
- package/scripts/check-npm-release.sh +0 -32
- package/scripts/check-public-release-surface.sh +0 -19
- package/scripts/check-release-published.sh +0 -57
- package/scripts/check-release-readiness.sh +0 -37
- package/scripts/check-release-version.mjs +0 -74
- package/scripts/check-skill-version.ts +0 -5
- package/scripts/check-tarball-install-smoke.sh +0 -150
- package/scripts/ensure-codegraph.sh +0 -16
- package/scripts/package-source-archive.sh +0 -147
- package/scripts/public-release-files.txt +0 -39
- package/scripts/public-release.ts +0 -174
- package/scripts/publish-release-tarball.sh +0 -27
- package/scripts/route-nl-vs-ts-eval.ts +0 -679
- package/scripts/run-skill-hook.ts +0 -244
- package/scripts/stage-runtime-release.ts +0 -44
- package/scripts/sync-codex-installed-copies.sh +0 -182
- package/src/cli/commands/tools.ts +0 -167
- package/src/cli/controller/progress.ts +0 -656
- package/src/cli/controller/work-mode.ts +0 -181
- package/src/cli/local-bridge/console-assets.ts +0 -17
- package/src/cli/local-bridge/dashboard.ts +0 -17
- package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
- package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
- package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
- package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
- package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/styles.css +0 -28
- package/src/cli/local-bridge/frontend/src/types.ts +0 -15
- package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
- package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
- package/src/cli/local-bridge/ui-dist/app.css +0 -1
- package/src/cli/local-bridge/ui-dist/app.js +0 -11228
- package/src/cli/mcp/access-mode.ts +0 -2
- package/src/cli/mcp/access-tools.ts +0 -2
- package/src/cli/mcp/audit.ts +0 -2
- package/src/cli/mcp/auth.ts +0 -2
- package/src/cli/mcp/instructions.ts +0 -2
- package/src/cli/mcp/legacy-context.ts +0 -2
- package/src/cli/mcp/legacy-tool-service.ts +0 -2
- package/src/cli/mcp/multi-repository.ts +0 -2
- package/src/cli/mcp/oauth.ts +0 -2
- package/src/cli/mcp/openai-secure-tunnel.ts +0 -2
- package/src/cli/mcp/paths.ts +0 -2
- package/src/cli/mcp/policy.ts +0 -2
- package/src/cli/mcp/post-finalize-work-attribution.ts +0 -2
- package/src/cli/mcp/proxy-env.ts +0 -2
- package/src/cli/mcp/readiness-projection.ts +0 -2
- package/src/cli/mcp/redaction.ts +0 -2
- package/src/cli/mcp/repo.ts +0 -2
- package/src/cli/mcp/repository-tools.ts +0 -2
- package/src/cli/mcp/server.ts +0 -2
- package/src/cli/mcp/setup.ts +0 -2
- package/src/cli/mcp/tool-capability-cache.ts +0 -2
- package/src/cli/mcp/tool-contract.ts +0 -2
- package/src/cli/mcp/tools.ts +0 -2
- package/src/cli/mcp/toolset-names.ts +0 -2
- package/src/cli/mcp/toolset-selection.ts +0 -2
- package/src/cli/mcp/toolset.ts +0 -2
- package/src/cli/mcp/transports/http.ts +0 -2
- package/src/cli/mcp/transports/session-registry.ts +0 -2
- package/src/cli/mcp/transports/stdio.ts +0 -2
- package/src/cli/mcp/types.ts +0 -2
- package/src/cli/mcp/umbrella-tools.ts +0 -2
- package/src/cli/tools/codegraph.ts +0 -695
- package/src/core/adoption/helper-wrapper-plan.ts +0 -159
- package/src/runtime/context/codegraph-cache-boundary.ts +0 -255
- package/src/runtime/context/codegraph-read-provider.ts +0 -611
- package/src/runtime/context/codegraph-sidecar.cjs +0 -248
- package/src/runtime/control-plane/codegraph-cache-retention.ts +0 -164
- package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
- package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
- package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
- package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
- package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
- package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
- package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
- package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
- package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
- package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
- package/src/runtime/control-plane/routing/index.ts +0 -1
- package/src/runtime/control-plane/routing/route-policy.ts +0 -401
- package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
- package/src/runtime/gateway/mcp/execution-tools.ts +0 -2
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +0 -2
- package/src/runtime/gateway/mcp/persisted-check-process.ts +0 -2
- package/src/runtime/gateway/mcp/process-tools.ts +0 -2
- package/src/runtime/gateway/mcp/router.ts +0 -2
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +0 -2
- package/src/runtime/gateway/mcp/runtime-tools.ts +0 -2
- package/src/runtime/gateway/mcp/work-validation-reconciler.ts +0 -2
- package/src/runtime/plugins/browser-provider-registry.ts +0 -2
|
@@ -1,169 +1,35 @@
|
|
|
1
1
|
import type { CallToolResult, McpToolDefinition } from '../../../packages/protocols/mcp/tool-contract';
|
|
2
2
|
export type { CallToolResult, McpToolDefinition } from '../../../packages/protocols/mcp/tool-contract';
|
|
3
3
|
import { createHash } from "crypto";
|
|
4
|
-
import {
|
|
5
|
-
existsSync,
|
|
6
|
-
mkdirSync,
|
|
7
|
-
readdirSync,
|
|
8
|
-
readFileSync,
|
|
9
|
-
statSync,
|
|
10
|
-
writeFileSync,
|
|
11
|
-
appendFileSync,
|
|
12
|
-
} from "fs";
|
|
4
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync, appendFileSync } from "fs";
|
|
13
5
|
import { basename, dirname, join } from "path";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
createEditSavepoint,
|
|
19
|
-
EditSessionPatchError,
|
|
20
|
-
finalizeEditSession,
|
|
21
|
-
getEditSession,
|
|
22
|
-
getEditSessionDiff,
|
|
23
|
-
listEditSessions,
|
|
24
|
-
PREFERRED_EDIT_PATCH_BATCH_OPERATIONS,
|
|
25
|
-
rollbackEditSession,
|
|
26
|
-
verifyEditSession,
|
|
27
|
-
} from "../../../src/cli/editing/edit-session";
|
|
28
|
-
import {
|
|
29
|
-
EDIT_OPERATION_INPUT_SCHEMA,
|
|
30
|
-
normalizeEditOperations,
|
|
31
|
-
} from "../../../src/cli/editing/edit-operation-contract";
|
|
32
|
-
import {
|
|
33
|
-
cancelAgentJob,
|
|
34
|
-
getAgentJob,
|
|
35
|
-
getAgentJobEvents,
|
|
36
|
-
getAgentJobLog,
|
|
37
|
-
listAgentJobs,
|
|
38
|
-
} from "../../../src/cli/agent-jobs/job-manager";
|
|
39
|
-
import {
|
|
40
|
-
classifyGitHubCopilotPreflight,
|
|
41
|
-
classifyLocalExecutorHealth,
|
|
42
|
-
executorHealthCode,
|
|
43
|
-
isExecutorHealthError,
|
|
44
|
-
type ExecutorHealth,
|
|
45
|
-
} from "../../../src/cli/agent-jobs/executor-health";
|
|
46
|
-
import { integrateAgentJob, taskRunDiff } from "../../../src/cli/agent-jobs/integration";
|
|
47
|
-
import {
|
|
48
|
-
appendTask,
|
|
49
|
-
archiveIssue,
|
|
50
|
-
createIssue,
|
|
51
|
-
getIssue,
|
|
52
|
-
getIssueEffectiveView,
|
|
53
|
-
getIssueReadView,
|
|
54
|
-
inspectIssueReadiness,
|
|
55
|
-
inspectTaskReadiness,
|
|
56
|
-
acceptVerifiedTask,
|
|
57
|
-
listIssueEffectiveViews,
|
|
58
|
-
listIssues,
|
|
59
|
-
projectIssueEffectiveView,
|
|
60
|
-
planIssue,
|
|
61
|
-
projectBoard,
|
|
62
|
-
recordTaskVerification,
|
|
63
|
-
restoreIssue,
|
|
64
|
-
setTaskDependencies,
|
|
65
|
-
splitTask,
|
|
66
|
-
supersedeTask,
|
|
67
|
-
updateIssue,
|
|
68
|
-
updateTask,
|
|
69
|
-
} from "../../../src/cli/controller/issue-store";
|
|
70
|
-
import { applyMigratedIssueDecision } from '../../../src/cli/controller/migrated-issue-decision';
|
|
71
|
-
import { legacyIssueAuthorityRetired } from '../../../src/cli/controller/legacy-issue-cutover';
|
|
72
|
-
import {
|
|
73
|
-
listControllerChecks,
|
|
74
|
-
} from "../../../src/cli/controller/check-runner";
|
|
75
|
-
import { normalizeCheckIds } from '../../../src/runtime/control-plane/facade/check-normalization';
|
|
6
|
+
import { beginEditSession, applyEditOperations, createEditSavepoint, EditSessionPatchError, finalizeEditSession, getEditSession, getEditSessionDiff, listEditSessions, PREFERRED_EDIT_PATCH_BATCH_OPERATIONS, rollbackEditSession } from "../../../src/cli/editing/edit-session";
|
|
7
|
+
import { EDIT_OPERATION_INPUT_SCHEMA, normalizeEditOperations } from "../../../src/cli/editing/edit-operation-contract";
|
|
8
|
+
import { listAgentJobs } from "../../../src/cli/agent-jobs/job-manager";
|
|
9
|
+
import { listControllerChecks } from "../../../src/cli/controller/check-runner";
|
|
76
10
|
import { buildExecutionDiagnostics, buildRequirementBoard } from '../../../src/runtime/control-plane/facade/requirement-board';
|
|
77
|
-
import { acceptVerifiedTaskFromControllerWork } from '../../../src/runtime/control-plane/execution/work-task-receipt';
|
|
78
11
|
import { getWorkContract } from '../../../packages/kernel/work/api';
|
|
79
12
|
import { admitDirectEditWorkContract } from '../../../src/runtime/control-plane/facade/repository-work-admission';
|
|
80
|
-
import { decideRoute } from '../../../src/runtime/control-plane/routing/route-policy';
|
|
81
13
|
import { listCapabilityDescriptors, summarizeCapabilityGroups } from '../../../src/runtime/control-plane/facade/capability-registry';
|
|
82
|
-
import {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
getTaskProgressDetail,
|
|
86
|
-
getTaskProgressReadView,
|
|
87
|
-
} from "../../../src/cli/controller/progress";
|
|
88
|
-
import { exportControllerWorklog, parseWorklogCategory } from "../../../src/cli/controller/worklog";
|
|
89
|
-
import { inspectProjectGovernance, reconcileProjectGovernance } from "../../../src/cli/controller/governance";
|
|
90
|
-
import { assessWorkMode, parseExplicitTaskMode } from "../../../src/cli/controller/work-mode";
|
|
91
|
-
import { taskExecutionPolicy } from "../../../src/cli/controller/execution-policy";
|
|
92
|
-
import { finishEditSession, finishTaskRun } from "../../../src/cli/controller/completion-orchestrator";
|
|
93
|
-
import { buildControllerTaskLedgerProjection } from "../../../src/cli/controller/task-ledger";
|
|
94
|
-
import { buildControllerContextPack } from "../../../src/cli/controller/context-pack";
|
|
95
|
-
import { loadControllerProjectState, saveControllerProjectState } from "../../../src/cli/controller/project-state";
|
|
96
|
-
import {
|
|
97
|
-
FORGE_MCP_SCHEMA_VERSION,
|
|
98
|
-
FORGE_TOOL_SURFACE,
|
|
99
|
-
FORGE_VERSION,
|
|
100
|
-
forgeToolSurfaceFingerprint,
|
|
101
|
-
MIN_AGENT_TIMEOUT_MS,
|
|
102
|
-
formatDurationMs,
|
|
103
|
-
normalizeAgentTimeoutMs,
|
|
104
|
-
} from "../../../src/cli/controller/runtime-config";
|
|
105
|
-
import { DEFAULT_CONTROLLER_TOOL_NAMES, PREFERRED_FACADE_TOOL_NAMES } from "../toolset-names";
|
|
14
|
+
import { exportControllerWorklog, listControllerWorklogEvents, parseWorklogCategory } from "../../../src/cli/controller/worklog";
|
|
15
|
+
import { FORGE_MCP_SCHEMA_VERSION, FORGE_TOOL_SURFACE, FORGE_VERSION, forgeToolSurfaceFingerprint, MIN_AGENT_TIMEOUT_MS, formatDurationMs, normalizeAgentTimeoutMs } from "../../../src/cli/controller/runtime-config";
|
|
16
|
+
import { PREFERRED_FACADE_TOOL_NAMES } from "../toolset-names";
|
|
106
17
|
import { buildLocalConnectorStatusForRepo } from "../../../src/cli/local-bridge/connector-freshness";
|
|
107
|
-
import
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
IssueStatus,
|
|
112
|
-
TaskDraft,
|
|
113
|
-
TaskRisk,
|
|
114
|
-
TaskCommandEvidence,
|
|
115
|
-
TaskStatus,
|
|
116
|
-
TaskVerification,
|
|
117
|
-
} from "../../../src/cli/controller/types";
|
|
118
|
-
import {
|
|
119
|
-
gitDiff,
|
|
120
|
-
gitSnapshot,
|
|
121
|
-
searchRepository,
|
|
122
|
-
} from "../../../src/cli/repository/inspector";
|
|
123
|
-
import {
|
|
124
|
-
closeGitHubIssue,
|
|
125
|
-
getGitHubStatus,
|
|
126
|
-
publishIssueToGitHub,
|
|
127
|
-
refreshGitHubIssue,
|
|
128
|
-
} from "../../../src/cli/github/github";
|
|
129
|
-
import {
|
|
130
|
-
getGitHubPluginStatus,
|
|
131
|
-
saveGitHubPluginConfig,
|
|
132
|
-
} from "../../../src/cli/github/plugin";
|
|
133
|
-
import {
|
|
134
|
-
getLocalBridgeJobEvents,
|
|
135
|
-
getLocalBridgeJobSnapshot,
|
|
136
|
-
listLocalBridgeJobs,
|
|
137
|
-
readLocalBridgeJobOutput,
|
|
138
|
-
reconcileLocalBridgeJobs,
|
|
139
|
-
} from "../../../src/cli/local-bridge/job-store";
|
|
18
|
+
import { gitDiff, gitSnapshot, searchRepository } from "../../../src/cli/repository/inspector";
|
|
19
|
+
import { getGitHubStatus } from "../../../src/cli/github/github";
|
|
20
|
+
import { getGitHubPluginStatus, saveGitHubPluginConfig } from "../../../src/cli/github/plugin";
|
|
21
|
+
import { getLocalBridgeJobEvents, getLocalBridgeJobSnapshot, listLocalBridgeJobs, readLocalBridgeJobOutput, reconcileLocalBridgeJobs } from "../../../src/cli/local-bridge/job-store";
|
|
140
22
|
import { runHelper } from "../../../src/cli/runtime/helper-runner";
|
|
141
|
-
import {
|
|
142
|
-
|
|
143
|
-
openSession,
|
|
144
|
-
readSession,
|
|
145
|
-
runBrowserConsult,
|
|
146
|
-
runBrowserFollowup,
|
|
147
|
-
} from "../../../src/cli/chatgpt-browser/engine";
|
|
148
|
-
import type {
|
|
149
|
-
BrowserProviderName,
|
|
150
|
-
NativeBrowserChannel,
|
|
151
|
-
ThinkingLevel,
|
|
152
|
-
} from "../../../src/cli/chatgpt-browser/types";
|
|
23
|
+
import { listSessions, openSession, readSession, runBrowserConsult, runBrowserFollowup } from "../../../src/cli/chatgpt-browser/engine";
|
|
24
|
+
import type { BrowserProviderName, NativeBrowserChannel, ThinkingLevel } from "../../../src/cli/chatgpt-browser/types";
|
|
153
25
|
import { hashMcpInput, tryWriteMcpAuditEntry } from "../audit";
|
|
154
|
-
import { loadMcpRuntimeState } from "../auth";
|
|
155
26
|
import { resolveLocalBridgeSurface, summarizeRecentJobs } from "../../../src/runtime/shared/local-bridge-surface";
|
|
156
27
|
import { resolveRepoPreferredControllerHome } from "../../../src/cli/repositories/controller-home";
|
|
157
28
|
import { resolveRepositoryCheckStorage } from '../../../src/runtime/execution/process-runtime/check-storage';
|
|
158
29
|
import { resolveRepositorySelection } from '../../../src/cli/repositories/registry';
|
|
159
30
|
import { ensureRepositoryRuntimeStorageBinding } from '../../../src/cli/repositories/runtime-storage';
|
|
160
|
-
import {
|
|
161
|
-
import { runPersistedCheckViaProcessRuntime } from '../runtime-gateway/persisted-check-process';
|
|
162
|
-
import { getProcessRecord } from '../../../src/runtime/execution/process-runtime/store';
|
|
163
|
-
import { processCheckCompletionReceipt } from '../../../src/runtime/execution/process-runtime/check-receipt';
|
|
164
|
-
import { normalizeMcpRelativePath, resolveMcpPath } from "../paths";
|
|
31
|
+
import { resolveMcpPath } from "../paths";
|
|
165
32
|
import { currentGitBranch, isForgeAdopted } from "../repo";
|
|
166
|
-
import { repositoryToolNames } from "./repository-tools";
|
|
167
33
|
import { redactMcpText } from "../redaction";
|
|
168
34
|
import type { McpPolicy } from "../types";
|
|
169
35
|
|
|
@@ -179,10 +45,14 @@ export interface McpToolContext {
|
|
|
179
45
|
principalId?: string;
|
|
180
46
|
/** Authenticated transport controller/provider type. */
|
|
181
47
|
controllerType?: 'chatgpt' | 'codex' | 'claude' | 'grok' | 'human';
|
|
48
|
+
/** Host-provided ChatGPT session correlation. Never authorization and never a canonical conversation URL. */
|
|
49
|
+
hostConversationSessionId?: string;
|
|
182
50
|
controllerInstanceId?: string;
|
|
183
51
|
/** Bound repository identity for session cache keys. */
|
|
184
52
|
repoId?: string;
|
|
185
53
|
checkoutId?: string;
|
|
54
|
+
/** Canonical tools/list projection supplied by the MCP registry; never authored by the client. */
|
|
55
|
+
publishedToolNames?: readonly string[];
|
|
186
56
|
/** Request-scoped MCP cancellation; never persisted or reused across calls. */
|
|
187
57
|
signal?: AbortSignal;
|
|
188
58
|
}
|
|
@@ -219,30 +89,6 @@ function errorResult(
|
|
|
219
89
|
return result;
|
|
220
90
|
}
|
|
221
91
|
|
|
222
|
-
function dispatchErrorResult(
|
|
223
|
-
code: string,
|
|
224
|
-
message: string,
|
|
225
|
-
options: {
|
|
226
|
-
requestId?: string;
|
|
227
|
-
retryable?: boolean;
|
|
228
|
-
details?: unknown;
|
|
229
|
-
} = {},
|
|
230
|
-
): CallToolResult {
|
|
231
|
-
const payload = {
|
|
232
|
-
accepted: false,
|
|
233
|
-
code,
|
|
234
|
-
message: redactMcpText(message).text,
|
|
235
|
-
retryable: options.retryable === true,
|
|
236
|
-
requestId: options.requestId,
|
|
237
|
-
details: options.details,
|
|
238
|
-
};
|
|
239
|
-
const result = textResult({
|
|
240
|
-
error: payload,
|
|
241
|
-
...payload,
|
|
242
|
-
});
|
|
243
|
-
result.isError = true;
|
|
244
|
-
return result;
|
|
245
|
-
}
|
|
246
92
|
|
|
247
93
|
function audit(
|
|
248
94
|
ctx: McpToolContext,
|
|
@@ -324,433 +170,25 @@ function knownRunPathReplacements(
|
|
|
324
170
|
.map(([from, to]) => ({ from, to }));
|
|
325
171
|
}
|
|
326
172
|
|
|
327
|
-
function redactRunText(
|
|
328
|
-
text: string,
|
|
329
|
-
repoRoot: string,
|
|
330
|
-
run: Partial<{
|
|
331
|
-
executionRoot: string;
|
|
332
|
-
worktree: string;
|
|
333
|
-
worktreePath: string;
|
|
334
|
-
}>,
|
|
335
|
-
maxChars: number,
|
|
336
|
-
): { text: string; truncated: boolean; redactions: Array<{ type: string; count: number }> } {
|
|
337
|
-
let scrubbed = text;
|
|
338
|
-
for (const entry of knownRunPathReplacements(repoRoot, run)) {
|
|
339
|
-
scrubbed = scrubbed.split(entry.from).join(entry.to);
|
|
340
|
-
}
|
|
341
|
-
scrubbed = scrubbed
|
|
342
|
-
.replace(/\/(?:private\/)?tmp\/[^\s"']+/g, "<abs-path>")
|
|
343
|
-
.replace(/\/(?:private\/)?var\/folders\/[^\s"']+/g, "<abs-path>")
|
|
344
|
-
.replace(/\/Users\/[^\s"']+/g, "<abs-path>")
|
|
345
|
-
.replace(/[A-Za-z]:\\[^\s"']+/g, "<abs-path>");
|
|
346
|
-
const redacted = redactMcpText(scrubbed);
|
|
347
|
-
if (redacted.text.length <= maxChars) {
|
|
348
|
-
return { text: redacted.text, truncated: false, redactions: redacted.redactions };
|
|
349
|
-
}
|
|
350
|
-
return {
|
|
351
|
-
text: redacted.text.slice(-maxChars),
|
|
352
|
-
truncated: true,
|
|
353
|
-
redactions: redacted.redactions,
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
173
|
|
|
357
|
-
function maybeTail(
|
|
358
|
-
value: string | undefined,
|
|
359
|
-
repoRoot: string,
|
|
360
|
-
run: Partial<{
|
|
361
|
-
executionRoot: string;
|
|
362
|
-
worktree: string;
|
|
363
|
-
worktreePath: string;
|
|
364
|
-
}>,
|
|
365
|
-
maxChars: number,
|
|
366
|
-
): { text: string; truncated: boolean; redactions: Array<{ type: string; count: number }> } | undefined {
|
|
367
|
-
if (!value) return undefined;
|
|
368
|
-
return redactRunText(value, repoRoot, run, maxChars);
|
|
369
|
-
}
|
|
370
174
|
|
|
371
|
-
function summarizeAgentRun(
|
|
372
|
-
repoRoot: string,
|
|
373
|
-
run: Record<string, unknown>,
|
|
374
|
-
options: {
|
|
375
|
-
includePaths?: boolean;
|
|
376
|
-
includeOutput?: boolean;
|
|
377
|
-
tailChars?: number;
|
|
378
|
-
} = {},
|
|
379
|
-
): Record<string, unknown> {
|
|
380
|
-
const tailChars = Math.min(Math.max(options.tailChars ?? 4096, 256), 16 * 1024);
|
|
381
|
-
const base: Record<string, unknown> = {
|
|
382
|
-
runId: run.runId,
|
|
383
|
-
issueId: run.issueId,
|
|
384
|
-
taskId: run.taskId,
|
|
385
|
-
agent: run.agent,
|
|
386
|
-
provider: run.provider,
|
|
387
|
-
executionMode: run.executionMode,
|
|
388
|
-
executionClass: run.executionClass,
|
|
389
|
-
allowedPaths: run.allowedPaths,
|
|
390
|
-
status: run.status,
|
|
391
|
-
closureState: run.closureState,
|
|
392
|
-
closureUpdatedAt: run.closureUpdatedAt,
|
|
393
|
-
preservationReason: run.preservationReason,
|
|
394
|
-
preservationDetails: typeof run.preservationDetails === "string"
|
|
395
|
-
? redactRunText(run.preservationDetails, repoRoot, {
|
|
396
|
-
executionRoot: typeof run.executionRoot === "string" ? run.executionRoot : undefined,
|
|
397
|
-
worktree: typeof run.worktree === "string" ? run.worktree : undefined,
|
|
398
|
-
worktreePath: typeof run.worktreePath === "string" ? run.worktreePath : undefined,
|
|
399
|
-
}, 1000).text
|
|
400
|
-
: run.preservationDetails,
|
|
401
|
-
branch: run.branch,
|
|
402
|
-
baseRevision: run.baseRevision,
|
|
403
|
-
changedFiles: Array.isArray(run.changedFiles) ? run.changedFiles.slice(0, 100) : run.changedFiles,
|
|
404
|
-
exitCode: run.exitCode,
|
|
405
|
-
error: typeof run.error === "string"
|
|
406
|
-
? redactRunText(run.error, repoRoot, {
|
|
407
|
-
executionRoot: typeof run.executionRoot === "string" ? run.executionRoot : undefined,
|
|
408
|
-
worktree: typeof run.worktree === "string" ? run.worktree : undefined,
|
|
409
|
-
worktreePath: typeof run.worktreePath === "string" ? run.worktreePath : undefined,
|
|
410
|
-
}, 1000).text
|
|
411
|
-
: run.error,
|
|
412
|
-
executorHealth: run.executorHealth,
|
|
413
|
-
timeoutMs: run.timeoutMs,
|
|
414
|
-
deadlineAt: run.deadlineAt,
|
|
415
|
-
startupDeadlineAt: run.startupDeadlineAt,
|
|
416
|
-
lastHeartbeatAt: run.lastHeartbeatAt,
|
|
417
|
-
progress: run.progress,
|
|
418
|
-
autoIntegrate: run.autoIntegrate,
|
|
419
|
-
autoIntegrationError: typeof run.autoIntegrationError === "string"
|
|
420
|
-
? redactRunText(run.autoIntegrationError, repoRoot, {
|
|
421
|
-
executionRoot: typeof run.executionRoot === "string" ? run.executionRoot : undefined,
|
|
422
|
-
worktree: typeof run.worktree === "string" ? run.worktree : undefined,
|
|
423
|
-
worktreePath: typeof run.worktreePath === "string" ? run.worktreePath : undefined,
|
|
424
|
-
}, 1000).text
|
|
425
|
-
: run.autoIntegrationError,
|
|
426
|
-
worktreeCleanedAt: run.worktreeCleanedAt,
|
|
427
|
-
cleanupBranchDeletedAt: run.cleanupBranchDeletedAt,
|
|
428
|
-
diffArtifactPath: run.diffArtifactPath,
|
|
429
|
-
terminationReason: run.terminationReason,
|
|
430
|
-
createdAt: run.createdAt,
|
|
431
|
-
startedAt: run.startedAt,
|
|
432
|
-
finishedAt: run.finishedAt,
|
|
433
|
-
integratedSessionId: run.integratedSessionId,
|
|
434
|
-
integratedAt: run.integratedAt,
|
|
435
|
-
timing: run.timing,
|
|
436
|
-
github: run.github && typeof run.github === "object"
|
|
437
|
-
? {
|
|
438
|
-
owner: (run.github as Record<string, unknown>).owner,
|
|
439
|
-
repo: (run.github as Record<string, unknown>).repo,
|
|
440
|
-
taskId: (run.github as Record<string, unknown>).taskId,
|
|
441
|
-
state: (run.github as Record<string, unknown>).state,
|
|
442
|
-
url: (run.github as Record<string, unknown>).url,
|
|
443
|
-
pullRequestUrl: (run.github as Record<string, unknown>).pullRequestUrl,
|
|
444
|
-
baseRef: (run.github as Record<string, unknown>).baseRef,
|
|
445
|
-
model: (run.github as Record<string, unknown>).model,
|
|
446
|
-
createPullRequest: (run.github as Record<string, unknown>).createPullRequest,
|
|
447
|
-
}
|
|
448
|
-
: run.github,
|
|
449
|
-
detail: {
|
|
450
|
-
pathsIncluded: options.includePaths === true,
|
|
451
|
-
outputIncluded: options.includeOutput !== false,
|
|
452
|
-
next: {
|
|
453
|
-
log: "Call get_task_run_log for a larger bounded tail.",
|
|
454
|
-
diff: "Call get_task_diff to inspect Git changes from an isolated worktree.",
|
|
455
|
-
},
|
|
456
|
-
},
|
|
457
|
-
};
|
|
458
|
-
if (options.includeOutput !== false) {
|
|
459
|
-
const stdout = maybeTail(
|
|
460
|
-
typeof run.stdoutTail === "string" ? run.stdoutTail : undefined,
|
|
461
|
-
repoRoot,
|
|
462
|
-
{
|
|
463
|
-
executionRoot: typeof run.executionRoot === "string" ? run.executionRoot : undefined,
|
|
464
|
-
worktree: typeof run.worktree === "string" ? run.worktree : undefined,
|
|
465
|
-
worktreePath: typeof run.worktreePath === "string" ? run.worktreePath : undefined,
|
|
466
|
-
},
|
|
467
|
-
tailChars,
|
|
468
|
-
);
|
|
469
|
-
const stderr = maybeTail(
|
|
470
|
-
typeof run.stderrTail === "string" ? run.stderrTail : undefined,
|
|
471
|
-
repoRoot,
|
|
472
|
-
{
|
|
473
|
-
executionRoot: typeof run.executionRoot === "string" ? run.executionRoot : undefined,
|
|
474
|
-
worktree: typeof run.worktree === "string" ? run.worktree : undefined,
|
|
475
|
-
worktreePath: typeof run.worktreePath === "string" ? run.worktreePath : undefined,
|
|
476
|
-
},
|
|
477
|
-
tailChars,
|
|
478
|
-
);
|
|
479
|
-
if (stdout) {
|
|
480
|
-
base.stdoutTail = stdout.text;
|
|
481
|
-
base.stdoutTailTruncated = stdout.truncated;
|
|
482
|
-
}
|
|
483
|
-
if (stderr) {
|
|
484
|
-
base.stderrTail = stderr.text;
|
|
485
|
-
base.stderrTailTruncated = stderr.truncated;
|
|
486
|
-
}
|
|
487
|
-
const redactions = [...(stdout?.redactions ?? []), ...(stderr?.redactions ?? [])];
|
|
488
|
-
if (redactions.length > 0) base.redactions = redactions;
|
|
489
|
-
}
|
|
490
|
-
if (options.includePaths === true) {
|
|
491
|
-
Object.assign(base, {
|
|
492
|
-
repoRoot: run.repoRoot,
|
|
493
|
-
executionRoot: run.executionRoot,
|
|
494
|
-
worktree: run.worktree,
|
|
495
|
-
worktreePath: run.worktreePath,
|
|
496
|
-
promptPath: run.promptPath,
|
|
497
|
-
stdoutPath: run.stdoutPath,
|
|
498
|
-
stderrPath: run.stderrPath,
|
|
499
|
-
resultPath: run.resultPath,
|
|
500
|
-
eventsPath: run.eventsPath,
|
|
501
|
-
controllerPid: run.controllerPid,
|
|
502
|
-
controllerEpoch: run.controllerEpoch,
|
|
503
|
-
controllerEpochPath: run.controllerEpochPath,
|
|
504
|
-
launchPid: run.launchPid,
|
|
505
|
-
workerPid: run.workerPid,
|
|
506
|
-
agentPid: run.agentPid,
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
return base;
|
|
510
|
-
}
|
|
511
175
|
|
|
512
|
-
function summarizeRunList(
|
|
513
|
-
repoRoot: string,
|
|
514
|
-
runs: Array<Record<string, unknown>>,
|
|
515
|
-
includePaths = false,
|
|
516
|
-
): Array<Record<string, unknown>> {
|
|
517
|
-
return runs.map((run) => summarizeAgentRun(repoRoot, run, { includePaths, includeOutput: false }));
|
|
518
|
-
}
|
|
519
176
|
|
|
520
|
-
function compactDispatchRun(run: Record<string, unknown>): Record<string, unknown> {
|
|
521
|
-
const runId = typeof run.runId === "string" ? run.runId : String(run.runId ?? "");
|
|
522
|
-
const detail: Record<string, unknown> = runId
|
|
523
|
-
? {
|
|
524
|
-
get_task_run: { run_id: runId },
|
|
525
|
-
get_task_run_log: { run_id: runId },
|
|
526
|
-
get_task_run_events: { run_id: runId },
|
|
527
|
-
get_task_diff: { run_id: runId },
|
|
528
|
-
}
|
|
529
|
-
: {};
|
|
530
|
-
return {
|
|
531
|
-
runId: run.runId,
|
|
532
|
-
issueId: run.issueId,
|
|
533
|
-
taskId: run.taskId,
|
|
534
|
-
status: run.status,
|
|
535
|
-
agent: run.agent,
|
|
536
|
-
provider: run.provider,
|
|
537
|
-
executionMode: run.executionMode,
|
|
538
|
-
executionClass: run.executionClass,
|
|
539
|
-
timeoutMs: run.timeoutMs,
|
|
540
|
-
startedAt: run.startedAt,
|
|
541
|
-
deadlineAt: run.deadlineAt,
|
|
542
|
-
finishedAt: run.finishedAt,
|
|
543
|
-
integratedSessionId: run.integratedSessionId,
|
|
544
|
-
autoIntegrationError: run.autoIntegrationError,
|
|
545
|
-
worktreeCleanedAt: run.worktreeCleanedAt,
|
|
546
|
-
accepted: run.accepted,
|
|
547
|
-
reused: run.reused,
|
|
548
|
-
github: run.github,
|
|
549
|
-
error: run.error,
|
|
550
|
-
detail,
|
|
551
|
-
};
|
|
552
|
-
}
|
|
553
177
|
|
|
554
|
-
function compactTaskView(task: Record<string, unknown>): Record<string, unknown> {
|
|
555
|
-
return {
|
|
556
|
-
id: task.id,
|
|
557
|
-
title: task.title,
|
|
558
|
-
status: task.status,
|
|
559
|
-
effectiveStatus: task.effectiveStatus,
|
|
560
|
-
declaredStatus: task.declaredStatus,
|
|
561
|
-
latestRunId: task.latestRunId,
|
|
562
|
-
latestRunStatus: task.latestRunStatus,
|
|
563
|
-
activeRunId: task.activeRunId,
|
|
564
|
-
activeRunStatus: task.activeRunStatus,
|
|
565
|
-
verificationStatus: task.verificationStatus,
|
|
566
|
-
dispatchable: task.dispatchable,
|
|
567
|
-
retryable: task.retryable,
|
|
568
|
-
requiresExplicitRetry: task.requiresExplicitRetry,
|
|
569
|
-
};
|
|
570
|
-
}
|
|
571
178
|
|
|
572
|
-
function compactIssueView(issue: Record<string, unknown>): Record<string, unknown> {
|
|
573
|
-
const id = typeof issue.id === "string" ? issue.id : String(issue.id ?? "");
|
|
574
|
-
const tasks = Array.isArray(issue.tasks) ? issue.tasks as Array<Record<string, unknown>> : [];
|
|
575
|
-
return {
|
|
576
|
-
id: issue.id,
|
|
577
|
-
title: issue.title,
|
|
578
|
-
status: issue.status,
|
|
579
|
-
lifecycleStatus: issue.lifecycleStatus,
|
|
580
|
-
github: issue.github,
|
|
581
|
-
taskCount: tasks.length,
|
|
582
|
-
tasks: tasks.map((task) => compactTaskView(task)),
|
|
583
|
-
detail: id ? { get_issue: { issue_id: id } } : {},
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
179
|
|
|
587
180
|
const PROJECT_BOARD_RECENT_ISSUE_LIMIT = 5;
|
|
588
181
|
const PROJECT_BOARD_TASK_LIMIT = 8;
|
|
589
182
|
|
|
590
|
-
function compactProjectBoardText(value: unknown, maxChars = 96): unknown {
|
|
591
|
-
if (typeof value !== "string" || value.length <= maxChars) return value;
|
|
592
|
-
return `${value.slice(0, Math.max(0, maxChars - 1))}…`;
|
|
593
|
-
}
|
|
594
183
|
|
|
595
|
-
function compactProjectBoardTask(
|
|
596
|
-
task: Record<string, unknown>,
|
|
597
|
-
options: { includeLifecycle?: boolean } = {},
|
|
598
|
-
): Record<string, unknown> {
|
|
599
|
-
const compact: Record<string, unknown> = {
|
|
600
|
-
issueId: task.issueId,
|
|
601
|
-
taskId: task.taskId,
|
|
602
|
-
id: task.id,
|
|
603
|
-
title: compactProjectBoardText(task.title),
|
|
604
|
-
agent: task.agent,
|
|
605
|
-
effectiveStatus: task.effectiveStatus,
|
|
606
|
-
executionClass: task.executionClass,
|
|
607
|
-
approval: task.approval,
|
|
608
|
-
};
|
|
609
|
-
if (options.includeLifecycle) {
|
|
610
|
-
Object.assign(compact, {
|
|
611
|
-
status: task.status,
|
|
612
|
-
declaredStatus: task.declaredStatus,
|
|
613
|
-
statusReason: task.statusReason,
|
|
614
|
-
verificationStatus: task.verificationStatus,
|
|
615
|
-
dispatchable: task.dispatchable,
|
|
616
|
-
queueable: task.queueable,
|
|
617
|
-
retryable: task.retryable,
|
|
618
|
-
requiresExplicitRetry: task.requiresExplicitRetry,
|
|
619
|
-
});
|
|
620
|
-
}
|
|
621
|
-
return compact;
|
|
622
|
-
}
|
|
623
184
|
|
|
624
|
-
function compactProjectBoardIssue(
|
|
625
|
-
issue: Record<string, unknown>,
|
|
626
|
-
options: { includeTasks?: boolean } = {},
|
|
627
|
-
): Record<string, unknown> {
|
|
628
|
-
const tasks = Array.isArray(issue.tasks) ? issue.tasks as Array<Record<string, unknown>> : [];
|
|
629
|
-
const taskCounts = tasks.reduce<Record<string, number>>((counts, task) => {
|
|
630
|
-
const status = typeof task.effectiveStatus === "string" ? task.effectiveStatus : "unknown";
|
|
631
|
-
counts[status] = (counts[status] ?? 0) + 1;
|
|
632
|
-
return counts;
|
|
633
|
-
}, {});
|
|
634
|
-
const compact: Record<string, unknown> = {
|
|
635
|
-
id: issue.id,
|
|
636
|
-
title: compactProjectBoardText(issue.title),
|
|
637
|
-
kind: issue.kind,
|
|
638
|
-
status: issue.status,
|
|
639
|
-
lifecycleStatus: issue.lifecycleStatus,
|
|
640
|
-
updatedAt: issue.updatedAt,
|
|
641
|
-
isCurrent: issue.isCurrent === true,
|
|
642
|
-
taskCount: tasks.length,
|
|
643
|
-
taskCounts,
|
|
644
|
-
readyTaskCount: tasks.filter((task) => task.dispatchable === true).length,
|
|
645
|
-
queueableTaskCount: tasks.filter((task) => task.queueable === true).length,
|
|
646
|
-
};
|
|
647
|
-
if (options.includeTasks) {
|
|
648
|
-
compact.tasks = tasks
|
|
649
|
-
.slice(0, PROJECT_BOARD_TASK_LIMIT)
|
|
650
|
-
.map((task) => compactProjectBoardTask(task, { includeLifecycle: true }));
|
|
651
|
-
compact.taskTruncatedCount = Math.max(0, tasks.length - PROJECT_BOARD_TASK_LIMIT);
|
|
652
|
-
}
|
|
653
|
-
return compact;
|
|
654
|
-
}
|
|
655
185
|
|
|
656
|
-
function summarizeProjectBoard(board: Record<string, unknown>): Record<string, unknown> {
|
|
657
|
-
const issues = Array.isArray(board.issues) ? board.issues as Array<Record<string, unknown>> : [];
|
|
658
|
-
const readyTasks = Array.isArray(board.readyTasks) ? board.readyTasks as Array<Record<string, unknown>> : [];
|
|
659
|
-
const queueableTasks = Array.isArray(board.queueableTasks) ? board.queueableTasks as Array<Record<string, unknown>> : [];
|
|
660
|
-
const currentIssue = issues.find((issue) => issue.isCurrent === true);
|
|
661
|
-
const recentIssueCandidates = currentIssue
|
|
662
|
-
? issues.filter((issue) => issue !== currentIssue)
|
|
663
|
-
: issues;
|
|
664
|
-
const recentIssues = recentIssueCandidates.slice(0, PROJECT_BOARD_RECENT_ISSUE_LIMIT);
|
|
665
|
-
return {
|
|
666
|
-
detailLevel: "summary",
|
|
667
|
-
issueCount: issues.length,
|
|
668
|
-
archivedIssueCount: board.archivedIssueCount,
|
|
669
|
-
counts: board.counts,
|
|
670
|
-
declaredCounts: board.declaredCounts,
|
|
671
|
-
archivedCounts: board.archivedCounts,
|
|
672
|
-
currentIssueId: board.currentIssueId,
|
|
673
|
-
currentIssue: currentIssue ? compactProjectBoardIssue(currentIssue, { includeTasks: true }) : undefined,
|
|
674
|
-
recentIssues: recentIssues.map((issue) => compactProjectBoardIssue(issue)),
|
|
675
|
-
recentIssueTruncatedCount: Math.max(0, recentIssueCandidates.length - recentIssues.length),
|
|
676
|
-
readyTaskCount: readyTasks.length,
|
|
677
|
-
readyTasks: readyTasks.slice(0, PROJECT_BOARD_TASK_LIMIT).map((task) => compactProjectBoardTask(task)),
|
|
678
|
-
readyTaskTruncatedCount: Math.max(0, readyTasks.length - PROJECT_BOARD_TASK_LIMIT),
|
|
679
|
-
queueableTaskCount: queueableTasks.length,
|
|
680
|
-
queueableTasks: queueableTasks.slice(0, PROJECT_BOARD_TASK_LIMIT).map((task) => compactProjectBoardTask(task)),
|
|
681
|
-
queueableTaskTruncatedCount: Math.max(0, queueableTasks.length - PROJECT_BOARD_TASK_LIMIT),
|
|
682
|
-
detailPointer: {
|
|
683
|
-
tool: "get_project_board",
|
|
684
|
-
arguments: { detail_level: "detail" },
|
|
685
|
-
},
|
|
686
|
-
};
|
|
687
|
-
}
|
|
688
186
|
|
|
689
187
|
const UPDATE_TASK_SUMMARY_TASK_LIMIT = 12;
|
|
690
188
|
|
|
691
|
-
function compactUpdatedTaskView(task: Record<string, unknown>): Record<string, unknown> {
|
|
692
|
-
return {
|
|
693
|
-
...compactTaskView(task),
|
|
694
|
-
title: compactProjectBoardText(task.title),
|
|
695
|
-
};
|
|
696
|
-
}
|
|
697
189
|
|
|
698
|
-
function summarizeUpdatedIssue(
|
|
699
|
-
issue: Record<string, unknown>,
|
|
700
|
-
taskId: string,
|
|
701
|
-
): Record<string, unknown> {
|
|
702
|
-
const tasks = Array.isArray(issue.tasks) ? issue.tasks as Array<Record<string, unknown>> : [];
|
|
703
|
-
const updatedTask = tasks.find((task) => task.id === taskId);
|
|
704
|
-
return {
|
|
705
|
-
detailLevel: "summary",
|
|
706
|
-
id: issue.id,
|
|
707
|
-
title: compactProjectBoardText(issue.title),
|
|
708
|
-
status: issue.status,
|
|
709
|
-
lifecycleStatus: issue.lifecycleStatus,
|
|
710
|
-
github: issue.github,
|
|
711
|
-
taskCount: tasks.length,
|
|
712
|
-
tasks: tasks.slice(0, UPDATE_TASK_SUMMARY_TASK_LIMIT).map(compactUpdatedTaskView),
|
|
713
|
-
taskTruncatedCount: Math.max(0, tasks.length - UPDATE_TASK_SUMMARY_TASK_LIMIT),
|
|
714
|
-
updatedTask: updatedTask ? compactUpdatedTaskView(updatedTask) : undefined,
|
|
715
|
-
detailPointer: {
|
|
716
|
-
tool: "get_issue",
|
|
717
|
-
arguments: { issue_id: issue.id, detail_level: "full" },
|
|
718
|
-
},
|
|
719
|
-
};
|
|
720
|
-
}
|
|
721
190
|
|
|
722
|
-
function dispatchExecutorHealthResult(
|
|
723
|
-
health: ExecutorHealth,
|
|
724
|
-
options: { requestId?: string; retryable?: boolean } = {},
|
|
725
|
-
): CallToolResult {
|
|
726
|
-
return dispatchErrorResult(executorHealthCode(health), health.message, {
|
|
727
|
-
requestId: options.requestId,
|
|
728
|
-
retryable: options.retryable,
|
|
729
|
-
details: { executorHealth: health },
|
|
730
|
-
});
|
|
731
|
-
}
|
|
732
191
|
|
|
733
|
-
function taskExecutorHealth(
|
|
734
|
-
ctx: McpToolContext,
|
|
735
|
-
task: ControllerTask,
|
|
736
|
-
agent: ControllerAgent,
|
|
737
|
-
githubRepo?: string,
|
|
738
|
-
): ExecutorHealth | null {
|
|
739
|
-
if (agent === "github-copilot") {
|
|
740
|
-
return classifyGitHubCopilotPreflight(
|
|
741
|
-
getGitHubStatus(ctx.repoRoot, githubRepo),
|
|
742
|
-
task,
|
|
743
|
-
);
|
|
744
|
-
}
|
|
745
|
-
return classifyLocalExecutorHealth(
|
|
746
|
-
agent,
|
|
747
|
-
{
|
|
748
|
-
agentRunner: ctx.policy.execution.agentRunner,
|
|
749
|
-
allowedAgents: ctx.policy.execution.allowedAgents,
|
|
750
|
-
},
|
|
751
|
-
task,
|
|
752
|
-
);
|
|
753
|
-
}
|
|
754
192
|
|
|
755
193
|
function listFilesUnder(
|
|
756
194
|
repoRoot: string,
|
|
@@ -829,28 +267,7 @@ function timestampPrefix(date = new Date()): string {
|
|
|
829
267
|
return `${yyyy}${mm}${dd}-${hh}${min}`;
|
|
830
268
|
}
|
|
831
269
|
|
|
832
|
-
function parseControllerAgent(value: unknown): ControllerAgent | null {
|
|
833
|
-
const normalized = String(value ?? "")
|
|
834
|
-
.trim()
|
|
835
|
-
.toLowerCase();
|
|
836
|
-
return normalized === "codex" ||
|
|
837
|
-
normalized === "claude" ||
|
|
838
|
-
normalized === "github-copilot"
|
|
839
|
-
? normalized
|
|
840
|
-
: null;
|
|
841
|
-
}
|
|
842
270
|
|
|
843
|
-
function resolveDispatchAgent(
|
|
844
|
-
ctx: McpToolContext,
|
|
845
|
-
task: ControllerTask,
|
|
846
|
-
requested: unknown,
|
|
847
|
-
): ControllerAgent | null {
|
|
848
|
-
const hasExplicitRequest = requested !== undefined && requested !== null && String(requested).trim() !== "";
|
|
849
|
-
if (hasExplicitRequest) return parseControllerAgent(requested);
|
|
850
|
-
if (task.recommendedAgent) return task.recommendedAgent;
|
|
851
|
-
const firstLocal = ctx.policy.execution.allowedAgents[0];
|
|
852
|
-
return firstLocal ?? task.recommendedAgent ?? null;
|
|
853
|
-
}
|
|
854
271
|
|
|
855
272
|
function runnerTimeoutMs(ctx: McpToolContext, value: unknown): number {
|
|
856
273
|
return normalizeAgentTimeoutMs(value, {
|
|
@@ -1000,50 +417,8 @@ interface TaskVerificationLeaseConflict {
|
|
|
1000
417
|
blockingProcessId?: string;
|
|
1001
418
|
}
|
|
1002
419
|
|
|
1003
|
-
function taskVerificationLeaseConflict(record: {
|
|
1004
|
-
error?: { message?: unknown };
|
|
1005
|
-
}): TaskVerificationLeaseConflict | undefined {
|
|
1006
|
-
const message = typeof record.error?.message === "string" ? record.error.message.trim() : "";
|
|
1007
|
-
if (!message.startsWith("PROCESS_LEASE_CONFLICT:")) return undefined;
|
|
1008
|
-
const match = /^PROCESS_LEASE_CONFLICT:\s*(.+?)@process:([A-Za-z0-9._-]+)$/.exec(message);
|
|
1009
|
-
return {
|
|
1010
|
-
message,
|
|
1011
|
-
resourceKey: match?.[1],
|
|
1012
|
-
blockingProcessId: match?.[2],
|
|
1013
|
-
};
|
|
1014
|
-
}
|
|
1015
420
|
|
|
1016
|
-
function taskVerificationRetryRequestId(
|
|
1017
|
-
requestBase: string,
|
|
1018
|
-
checkId: string,
|
|
1019
|
-
conflictedProcessId: string,
|
|
1020
|
-
): string {
|
|
1021
|
-
const stableBase = requestBase.replace(/:retry:[a-f0-9]{16}$/i, "");
|
|
1022
|
-
const retryToken = createHash("sha256")
|
|
1023
|
-
.update(`${stableBase}\0${checkId}\0${conflictedProcessId}`)
|
|
1024
|
-
.digest("hex")
|
|
1025
|
-
.slice(0, 16);
|
|
1026
|
-
return `${stableBase}:retry:${retryToken}`;
|
|
1027
|
-
}
|
|
1028
421
|
|
|
1029
|
-
function controllerTaskDrafts(value: unknown): TaskDraft[] {
|
|
1030
|
-
return taskObjects(value).map((task) => ({
|
|
1031
|
-
title: String(task.title ?? "").trim(),
|
|
1032
|
-
objective: String(task.objective ?? "").trim(),
|
|
1033
|
-
dependsOn: stringList(task.depends_on ?? task.dependsOn),
|
|
1034
|
-
allowedPaths: stringList(task.allowed_paths ?? task.allowedPaths),
|
|
1035
|
-
forbiddenPaths: stringList(task.forbidden_paths ?? task.forbiddenPaths),
|
|
1036
|
-
checks: stringList(task.checks),
|
|
1037
|
-
acceptanceCriteria: stringList(
|
|
1038
|
-
task.acceptance_criteria ?? task.acceptanceCriteria,
|
|
1039
|
-
),
|
|
1040
|
-
risk: (["readonly", "low", "medium", "high", "destructive"].includes(String(task.risk))
|
|
1041
|
-
? String(task.risk)
|
|
1042
|
-
: "medium") as TaskRisk,
|
|
1043
|
-
recommendedAgent:
|
|
1044
|
-
parseControllerAgent(task.agent ?? task.recommendedAgent) ?? undefined,
|
|
1045
|
-
}));
|
|
1046
|
-
}
|
|
1047
422
|
|
|
1048
423
|
function renderPrdFromIdeaBody(args: Record<string, unknown>): string {
|
|
1049
424
|
const title = String(args.title ?? "Untitled PRD").trim() || "Untitled PRD";
|
|
@@ -1575,18 +950,12 @@ export function buildMcpToolDefinitions(
|
|
|
1575
950
|
{
|
|
1576
951
|
name: "controller_context",
|
|
1577
952
|
description:
|
|
1578
|
-
"Return one compact controller start-work context: Git status, current Issue focus, active Runs and Jobs,
|
|
953
|
+
"Return one compact controller start-work context: Git status, current Issue focus, active Runs and Jobs, and available checks.",
|
|
1579
954
|
inputSchema: {
|
|
1580
955
|
type: "object",
|
|
1581
956
|
properties: {
|
|
1582
957
|
description: { type: "string" },
|
|
1583
|
-
mode: { type: "string", enum: ["direct", "plan", "debug", "review", "release", "scale", "-direct", "-plan", "-debug", "-review", "-release", "-scale"] },
|
|
1584
958
|
known_paths: { type: "array", items: { type: "string" } },
|
|
1585
|
-
expected_files: { type: "number" },
|
|
1586
|
-
expected_changed_lines: { type: "number" },
|
|
1587
|
-
requires_investigation: { type: "boolean" },
|
|
1588
|
-
requires_parallelism: { type: "boolean" },
|
|
1589
|
-
requires_long_running_checks: { type: "boolean" },
|
|
1590
959
|
needs_dependencies: { type: "boolean" },
|
|
1591
960
|
risk: { type: "string", enum: ["readonly", "low", "medium", "high", "destructive"] },
|
|
1592
961
|
},
|
|
@@ -1765,101 +1134,6 @@ export function buildMcpToolDefinitions(
|
|
|
1765
1134
|
inputSchema: EMPTY_SCHEMA,
|
|
1766
1135
|
annotations: readOnly,
|
|
1767
1136
|
},
|
|
1768
|
-
{
|
|
1769
|
-
name: "list_issues",
|
|
1770
|
-
description: "List controller-managed issues and task summaries.",
|
|
1771
|
-
inputSchema: EMPTY_SCHEMA,
|
|
1772
|
-
annotations: readOnly,
|
|
1773
|
-
},
|
|
1774
|
-
{
|
|
1775
|
-
name: "get_project_board",
|
|
1776
|
-
description: "Return the bounded Requirement Board by default. Explicit detail/full mode returns bounded Execution Diagnostics without exposing the full legacy Task/Run/Process ledger.",
|
|
1777
|
-
inputSchema: {
|
|
1778
|
-
type: "object",
|
|
1779
|
-
properties: {
|
|
1780
|
-
detail_level: { type: "string", enum: ["summary", "detail", "full"] },
|
|
1781
|
-
requirement_id: { type: "string" },
|
|
1782
|
-
},
|
|
1783
|
-
additionalProperties: false,
|
|
1784
|
-
},
|
|
1785
|
-
annotations: readOnly,
|
|
1786
|
-
},
|
|
1787
|
-
{
|
|
1788
|
-
name: "get_project_progress",
|
|
1789
|
-
description:
|
|
1790
|
-
"Return evidence-gate completion, effective status, blockers, throughput, current-focus progress, and attention items without lifecycle-percentage estimates.",
|
|
1791
|
-
inputSchema: EMPTY_SCHEMA,
|
|
1792
|
-
annotations: readOnly,
|
|
1793
|
-
},
|
|
1794
|
-
{
|
|
1795
|
-
name: "get_project_governance",
|
|
1796
|
-
description:
|
|
1797
|
-
"Return the current execution focus, evidence-driven execution queue, dead dependencies, pending review/acceptance, duplicate active Issues, and closeout anomalies.",
|
|
1798
|
-
inputSchema: EMPTY_SCHEMA,
|
|
1799
|
-
annotations: readOnly,
|
|
1800
|
-
},
|
|
1801
|
-
{
|
|
1802
|
-
name: "reconcile_project_governance",
|
|
1803
|
-
description:
|
|
1804
|
-
"Apply only safe governance repairs: replace superseded dependencies, return failed attempts to a retryable Task state, close fully completed Issues, and select the sole active Issue as focus.",
|
|
1805
|
-
inputSchema: EMPTY_SCHEMA,
|
|
1806
|
-
annotations: write,
|
|
1807
|
-
},
|
|
1808
|
-
{
|
|
1809
|
-
name: "get_project_state",
|
|
1810
|
-
description: "Return the current execution focus and Issue creation policy.",
|
|
1811
|
-
inputSchema: EMPTY_SCHEMA,
|
|
1812
|
-
annotations: readOnly,
|
|
1813
|
-
},
|
|
1814
|
-
{
|
|
1815
|
-
name: "set_current_issue",
|
|
1816
|
-
description: "Select the one active Issue that is allowed to drive the execution queue.",
|
|
1817
|
-
inputSchema: {
|
|
1818
|
-
type: "object",
|
|
1819
|
-
properties: { issue_id: { type: "string" } },
|
|
1820
|
-
required: ["issue_id"],
|
|
1821
|
-
additionalProperties: false,
|
|
1822
|
-
},
|
|
1823
|
-
annotations: write,
|
|
1824
|
-
},
|
|
1825
|
-
{
|
|
1826
|
-
name: "archive_issue",
|
|
1827
|
-
description: "Move a done or cancelled Issue out of the current workspace while retaining its full evidence history.",
|
|
1828
|
-
inputSchema: {
|
|
1829
|
-
type: "object",
|
|
1830
|
-
properties: { issue_id: { type: "string" } },
|
|
1831
|
-
required: ["issue_id"],
|
|
1832
|
-
additionalProperties: false,
|
|
1833
|
-
},
|
|
1834
|
-
annotations: write,
|
|
1835
|
-
},
|
|
1836
|
-
{
|
|
1837
|
-
name: "restore_issue",
|
|
1838
|
-
description: "Restore an archived Issue to the normal controller views.",
|
|
1839
|
-
inputSchema: {
|
|
1840
|
-
type: "object",
|
|
1841
|
-
properties: { issue_id: { type: "string" } },
|
|
1842
|
-
required: ["issue_id"],
|
|
1843
|
-
additionalProperties: false,
|
|
1844
|
-
},
|
|
1845
|
-
annotations: write,
|
|
1846
|
-
},
|
|
1847
|
-
{
|
|
1848
|
-
name: "get_task_progress_detail",
|
|
1849
|
-
description:
|
|
1850
|
-
"Return one Task with effective progress, bounded Run and timeline summaries by default, and full detail on demand.",
|
|
1851
|
-
inputSchema: {
|
|
1852
|
-
type: "object",
|
|
1853
|
-
properties: {
|
|
1854
|
-
issue_id: { type: "string" },
|
|
1855
|
-
task_id: { type: "string" },
|
|
1856
|
-
detail_level: { type: "string", enum: ["summary", "full"] },
|
|
1857
|
-
},
|
|
1858
|
-
required: ["issue_id", "task_id"],
|
|
1859
|
-
additionalProperties: false,
|
|
1860
|
-
},
|
|
1861
|
-
annotations: readOnly,
|
|
1862
|
-
},
|
|
1863
1137
|
{
|
|
1864
1138
|
name: "get_worklog_timeline",
|
|
1865
1139
|
description:
|
|
@@ -1926,345 +1200,135 @@ export function buildMcpToolDefinitions(
|
|
|
1926
1200
|
annotations: write,
|
|
1927
1201
|
},
|
|
1928
1202
|
{
|
|
1929
|
-
name: "
|
|
1930
|
-
description:
|
|
1203
|
+
name: "github_status",
|
|
1204
|
+
description:
|
|
1205
|
+
"Check GitHub CLI authentication, repository mapping, Projects readiness, and cloud-agent session support.",
|
|
1931
1206
|
inputSchema: {
|
|
1932
1207
|
type: "object",
|
|
1933
|
-
properties: {
|
|
1934
|
-
issue_id: { type: "string" },
|
|
1935
|
-
detail_level: { type: "string", enum: ["summary", "full"] },
|
|
1936
|
-
},
|
|
1937
|
-
required: ["issue_id"],
|
|
1208
|
+
properties: { repo: { type: "string" } },
|
|
1938
1209
|
additionalProperties: false,
|
|
1939
1210
|
},
|
|
1940
1211
|
annotations: readOnly,
|
|
1941
1212
|
},
|
|
1942
1213
|
{
|
|
1943
|
-
name: "
|
|
1214
|
+
name: "begin_edit_session",
|
|
1944
1215
|
description:
|
|
1945
|
-
"
|
|
1216
|
+
"Open a bounded direct-edit session tied to a purpose and optional Issue/Task.",
|
|
1946
1217
|
inputSchema: {
|
|
1947
1218
|
type: "object",
|
|
1948
|
-
properties: {
|
|
1219
|
+
properties: {
|
|
1220
|
+
purpose: { type: "string" },
|
|
1221
|
+
work_id: { type: "string", description: "Optional existing WorkContract. Omit to create lightweight direct-control Work lineage." },
|
|
1222
|
+
issue_id: { type: "string" },
|
|
1223
|
+
task_id: { type: "string" },
|
|
1224
|
+
allowed_paths: { type: "array", items: { type: "string" } },
|
|
1225
|
+
max_files: { type: "number" },
|
|
1226
|
+
max_changed_lines: { type: "number" },
|
|
1227
|
+
checks: { type: "array", items: { type: "string" }, description: "Named checks to run before finalization." },
|
|
1228
|
+
},
|
|
1229
|
+
required: ["purpose"],
|
|
1949
1230
|
additionalProperties: false,
|
|
1950
1231
|
},
|
|
1951
|
-
annotations:
|
|
1232
|
+
annotations: write,
|
|
1952
1233
|
},
|
|
1953
1234
|
{
|
|
1954
|
-
name: "
|
|
1235
|
+
name: "apply_patch",
|
|
1955
1236
|
description:
|
|
1956
|
-
"
|
|
1237
|
+
"Append one bounded patch batch to an active edit session. Prefer batches of 100 operations or fewer and pass expected_revision to avoid stale revisions.",
|
|
1957
1238
|
inputSchema: {
|
|
1958
1239
|
type: "object",
|
|
1959
1240
|
properties: {
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1241
|
+
session_id: { type: "string" },
|
|
1242
|
+
expected_revision: { type: "number", description: "Optional current revision precondition for the edit session." },
|
|
1243
|
+
operations: {
|
|
1244
|
+
type: "array",
|
|
1245
|
+
items: EDIT_OPERATION_INPUT_SCHEMA,
|
|
1246
|
+
},
|
|
1966
1247
|
},
|
|
1967
|
-
required: ["
|
|
1248
|
+
required: ["session_id", "operations"],
|
|
1968
1249
|
additionalProperties: false,
|
|
1969
1250
|
},
|
|
1970
1251
|
annotations: {
|
|
1971
1252
|
readOnlyHint: false,
|
|
1972
|
-
openWorldHint:
|
|
1253
|
+
openWorldHint: false,
|
|
1973
1254
|
destructiveHint: false,
|
|
1974
1255
|
},
|
|
1975
1256
|
},
|
|
1976
1257
|
{
|
|
1977
|
-
name: "
|
|
1978
|
-
description:
|
|
1979
|
-
"Refresh the linked GitHub Issue metadata and remote state.",
|
|
1258
|
+
name: "get_edit_session",
|
|
1259
|
+
description: "Read an edit session, revisions, savepoints, and operation manifest.",
|
|
1980
1260
|
inputSchema: {
|
|
1981
1261
|
type: "object",
|
|
1982
|
-
properties: {
|
|
1983
|
-
required: ["
|
|
1262
|
+
properties: { session_id: { type: "string" } },
|
|
1263
|
+
required: ["session_id"],
|
|
1984
1264
|
additionalProperties: false,
|
|
1985
1265
|
},
|
|
1986
1266
|
annotations: readOnly,
|
|
1987
1267
|
},
|
|
1988
1268
|
{
|
|
1989
|
-
name: "
|
|
1990
|
-
description:
|
|
1991
|
-
"Close the linked GitHub Issue after local controller acceptance.",
|
|
1269
|
+
name: "list_edit_sessions",
|
|
1270
|
+
description: "List recent direct-edit sessions with revision, changed-file, and check summaries.",
|
|
1992
1271
|
inputSchema: {
|
|
1993
1272
|
type: "object",
|
|
1994
|
-
properties: {
|
|
1995
|
-
required: ["issue_id"],
|
|
1273
|
+
properties: { limit: { type: "number" } },
|
|
1996
1274
|
additionalProperties: false,
|
|
1997
1275
|
},
|
|
1998
|
-
annotations:
|
|
1999
|
-
readOnlyHint: false,
|
|
2000
|
-
openWorldHint: true,
|
|
2001
|
-
destructiveHint: true,
|
|
2002
|
-
},
|
|
1276
|
+
annotations: readOnly,
|
|
2003
1277
|
},
|
|
2004
1278
|
{
|
|
2005
|
-
name: "
|
|
2006
|
-
description:
|
|
2007
|
-
"Score launch readiness, list blockers and warnings, and summarize executable Tasks. Agent selection happens at dispatch time.",
|
|
1279
|
+
name: "get_edit_session_diff",
|
|
1280
|
+
description: "Read the current aggregate localized diff for one direct-edit session.",
|
|
2008
1281
|
inputSchema: {
|
|
2009
1282
|
type: "object",
|
|
2010
|
-
properties: {
|
|
2011
|
-
required: ["
|
|
1283
|
+
properties: { session_id: { type: "string" } },
|
|
1284
|
+
required: ["session_id"],
|
|
2012
1285
|
additionalProperties: false,
|
|
2013
1286
|
},
|
|
2014
1287
|
annotations: readOnly,
|
|
2015
1288
|
},
|
|
2016
1289
|
{
|
|
2017
|
-
name: "
|
|
2018
|
-
description:
|
|
2019
|
-
"Evaluate launch readiness for one Task only. Other Issues, focus selection, unrelated Tasks, and missing named checks do not block it.",
|
|
1290
|
+
name: "create_edit_savepoint",
|
|
1291
|
+
description: "Name the current edit revision so later patch batches can be rolled back to it.",
|
|
2020
1292
|
inputSchema: {
|
|
2021
1293
|
type: "object",
|
|
2022
1294
|
properties: {
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
retry_from_run_id: { type: "string" },
|
|
2026
|
-
approve_destructive: { type: "boolean" },
|
|
1295
|
+
session_id: { type: "string" },
|
|
1296
|
+
name: { type: "string" },
|
|
2027
1297
|
},
|
|
2028
|
-
required: ["
|
|
1298
|
+
required: ["session_id", "name"],
|
|
2029
1299
|
additionalProperties: false,
|
|
2030
1300
|
},
|
|
2031
|
-
annotations:
|
|
1301
|
+
annotations: write,
|
|
2032
1302
|
},
|
|
2033
1303
|
{
|
|
2034
|
-
name: "
|
|
2035
|
-
description:
|
|
2036
|
-
"Return an Issue Launcher preview without starting any agent session.",
|
|
1304
|
+
name: "verify_edit_session",
|
|
1305
|
+
description: "Verify the current edit revision through persisted Process Runtime checks. Retries with the same request_id reuse the original process and terminal receipts are attached to the exact revision.",
|
|
2037
1306
|
inputSchema: {
|
|
2038
1307
|
type: "object",
|
|
2039
1308
|
properties: {
|
|
2040
|
-
|
|
2041
|
-
|
|
1309
|
+
session_id: { type: "string" },
|
|
1310
|
+
check_ids: { type: "array", items: { type: "string" } },
|
|
1311
|
+
request_id: { type: "string" },
|
|
1312
|
+
reviewer: { type: "string" },
|
|
1313
|
+
note: { type: "string" },
|
|
2042
1314
|
},
|
|
2043
|
-
required: ["
|
|
1315
|
+
required: ["session_id"],
|
|
2044
1316
|
additionalProperties: false,
|
|
2045
1317
|
},
|
|
2046
|
-
annotations:
|
|
1318
|
+
annotations: write,
|
|
2047
1319
|
},
|
|
2048
1320
|
{
|
|
2049
|
-
name: "
|
|
1321
|
+
name: "rollback_edit_session",
|
|
2050
1322
|
description:
|
|
2051
|
-
"
|
|
1323
|
+
"Rollback an active edit session completely, to a prior revision, or to a named savepoint.",
|
|
2052
1324
|
inputSchema: {
|
|
2053
1325
|
type: "object",
|
|
2054
1326
|
properties: {
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
expected_files: { type: "number" },
|
|
2059
|
-
expected_changed_lines: { type: "number" },
|
|
2060
|
-
requires_investigation: { type: "boolean" },
|
|
2061
|
-
requires_parallelism: { type: "boolean" },
|
|
2062
|
-
requires_long_running_checks: { type: "boolean" },
|
|
2063
|
-
needs_dependencies: { type: "boolean" },
|
|
2064
|
-
risk: { type: "string", enum: ["readonly", "low", "medium", "high", "destructive"] },
|
|
1327
|
+
session_id: { type: "string" },
|
|
1328
|
+
to_revision: { type: "number", description: "Keep revisions up to this value; omit for full rollback." },
|
|
1329
|
+
savepoint: { type: "string", description: "Rollback to a named savepoint." },
|
|
2065
1330
|
},
|
|
2066
|
-
required: ["
|
|
2067
|
-
additionalProperties: false,
|
|
2068
|
-
},
|
|
2069
|
-
annotations: readOnly,
|
|
2070
|
-
},
|
|
2071
|
-
{
|
|
2072
|
-
name: "create_issue",
|
|
2073
|
-
description:
|
|
2074
|
-
"Create a durable Issue only for broad, long-running, dependency-aware, parallel, protected-path, or high-risk work. File discovery by itself is not a reason to create an Issue or start an Agent; search first and use bounded direct edits when practical.",
|
|
2075
|
-
inputSchema: {
|
|
2076
|
-
type: "object",
|
|
2077
|
-
properties: {
|
|
2078
|
-
title: { type: "string" },
|
|
2079
|
-
kind: {
|
|
2080
|
-
type: "string",
|
|
2081
|
-
enum: ["bug", "feature", "governance", "investigation"],
|
|
2082
|
-
},
|
|
2083
|
-
summary: { type: "string" },
|
|
2084
|
-
goals: { type: "array", items: { type: "string" } },
|
|
2085
|
-
non_goals: { type: "array", items: { type: "string" } },
|
|
2086
|
-
acceptance_criteria: { type: "array", items: { type: "string" } },
|
|
2087
|
-
related_artifacts: { type: "array", items: { type: "string" } },
|
|
2088
|
-
tasks: { type: "array", items: taskItemSchema },
|
|
2089
|
-
allow_while_focused: { type: "boolean", description: "Explicitly allow a separate Issue while another Issue is the current execution focus." },
|
|
2090
|
-
allow_duplicate: { type: "boolean", description: "Explicitly allow an active Issue with the same normalized title." },
|
|
2091
|
-
allow_when_paused: { type: "boolean", description: "Explicitly override a paused Issue-creation policy." },
|
|
2092
|
-
},
|
|
2093
|
-
required: ["title"],
|
|
2094
|
-
additionalProperties: false,
|
|
2095
|
-
},
|
|
2096
|
-
annotations: write,
|
|
2097
|
-
},
|
|
2098
|
-
{
|
|
2099
|
-
name: "update_issue",
|
|
2100
|
-
description: "Update issue intent, artifacts, or lifecycle status.",
|
|
2101
|
-
inputSchema: {
|
|
2102
|
-
type: "object",
|
|
2103
|
-
properties: {
|
|
2104
|
-
issue_id: { type: "string" },
|
|
2105
|
-
title: { type: "string" },
|
|
2106
|
-
summary: { type: "string" },
|
|
2107
|
-
status: {
|
|
2108
|
-
type: "string",
|
|
2109
|
-
enum: [
|
|
2110
|
-
"backlog",
|
|
2111
|
-
"analysis",
|
|
2112
|
-
"planned",
|
|
2113
|
-
"launch_blocked",
|
|
2114
|
-
"in_progress",
|
|
2115
|
-
"review",
|
|
2116
|
-
"done",
|
|
2117
|
-
"cancelled",
|
|
2118
|
-
],
|
|
2119
|
-
},
|
|
2120
|
-
goals: { type: "array", items: { type: "string" } },
|
|
2121
|
-
non_goals: { type: "array", items: { type: "string" } },
|
|
2122
|
-
acceptance_criteria: { type: "array", items: { type: "string" } },
|
|
2123
|
-
related_artifacts: { type: "array", items: { type: "string" } },
|
|
2124
|
-
},
|
|
2125
|
-
required: ["issue_id"],
|
|
2126
|
-
additionalProperties: false,
|
|
2127
|
-
},
|
|
2128
|
-
annotations: write,
|
|
2129
|
-
},
|
|
2130
|
-
{
|
|
2131
|
-
name: "plan_issue",
|
|
2132
|
-
description:
|
|
2133
|
-
"Replace the pre-execution task plan for an Issue with ordered dependency-aware tasks.",
|
|
2134
|
-
inputSchema: {
|
|
2135
|
-
type: "object",
|
|
2136
|
-
properties: {
|
|
2137
|
-
issue_id: { type: "string" },
|
|
2138
|
-
tasks: { type: "array", items: taskItemSchema },
|
|
2139
|
-
},
|
|
2140
|
-
required: ["issue_id", "tasks"],
|
|
2141
|
-
additionalProperties: false,
|
|
2142
|
-
},
|
|
2143
|
-
annotations: write,
|
|
2144
|
-
},
|
|
2145
|
-
{
|
|
2146
|
-
name: "append_task",
|
|
2147
|
-
description:
|
|
2148
|
-
"Append a stable Task to an Issue after execution has already started.",
|
|
2149
|
-
inputSchema: {
|
|
2150
|
-
type: "object",
|
|
2151
|
-
properties: { issue_id: { type: "string" }, task: taskItemSchema },
|
|
2152
|
-
required: ["issue_id", "task"],
|
|
2153
|
-
additionalProperties: false,
|
|
2154
|
-
},
|
|
2155
|
-
annotations: write,
|
|
2156
|
-
},
|
|
2157
|
-
{
|
|
2158
|
-
name: "split_task",
|
|
2159
|
-
description:
|
|
2160
|
-
"Supersede one not-running Task with two or more smaller replacement Tasks while preserving downstream dependencies.",
|
|
2161
|
-
inputSchema: {
|
|
2162
|
-
type: "object",
|
|
2163
|
-
properties: {
|
|
2164
|
-
issue_id: { type: "string" },
|
|
2165
|
-
task_id: { type: "string" },
|
|
2166
|
-
tasks: { type: "array", minItems: 2, items: taskItemSchema },
|
|
2167
|
-
},
|
|
2168
|
-
required: ["issue_id", "task_id", "tasks"],
|
|
2169
|
-
additionalProperties: false,
|
|
2170
|
-
},
|
|
2171
|
-
annotations: write,
|
|
2172
|
-
},
|
|
2173
|
-
{
|
|
2174
|
-
name: "supersede_task",
|
|
2175
|
-
description:
|
|
2176
|
-
"Mark a Task as superseded and optionally link replacement Task IDs.",
|
|
2177
|
-
inputSchema: {
|
|
2178
|
-
type: "object",
|
|
2179
|
-
properties: {
|
|
2180
|
-
issue_id: { type: "string" },
|
|
2181
|
-
task_id: { type: "string" },
|
|
2182
|
-
replacement_task_ids: { type: "array", items: { type: "string" } },
|
|
2183
|
-
},
|
|
2184
|
-
required: ["issue_id", "task_id"],
|
|
2185
|
-
additionalProperties: false,
|
|
2186
|
-
},
|
|
2187
|
-
annotations: write,
|
|
2188
|
-
},
|
|
2189
|
-
{
|
|
2190
|
-
name: "set_task_dependencies",
|
|
2191
|
-
description:
|
|
2192
|
-
"Replace one Task dependency list and revalidate the Issue DAG.",
|
|
2193
|
-
inputSchema: {
|
|
2194
|
-
type: "object",
|
|
2195
|
-
properties: {
|
|
2196
|
-
issue_id: { type: "string" },
|
|
2197
|
-
task_id: { type: "string" },
|
|
2198
|
-
depends_on: { type: "array", items: { type: "string" } },
|
|
2199
|
-
},
|
|
2200
|
-
required: ["issue_id", "task_id", "depends_on"],
|
|
2201
|
-
additionalProperties: false,
|
|
2202
|
-
},
|
|
2203
|
-
annotations: write,
|
|
2204
|
-
},
|
|
2205
|
-
{
|
|
2206
|
-
name: "update_task",
|
|
2207
|
-
description: "Update one task status or append a controller note.",
|
|
2208
|
-
inputSchema: {
|
|
2209
|
-
type: "object",
|
|
2210
|
-
properties: {
|
|
2211
|
-
issue_id: { type: "string" },
|
|
2212
|
-
task_id: { type: "string" },
|
|
2213
|
-
status: {
|
|
2214
|
-
type: "string",
|
|
2215
|
-
enum: [
|
|
2216
|
-
"backlog",
|
|
2217
|
-
"analysis",
|
|
2218
|
-
"planned",
|
|
2219
|
-
"ready",
|
|
2220
|
-
"launch_blocked",
|
|
2221
|
-
"running",
|
|
2222
|
-
"blocked",
|
|
2223
|
-
"review",
|
|
2224
|
-
"integrated",
|
|
2225
|
-
"verifying",
|
|
2226
|
-
"changes_requested",
|
|
2227
|
-
"verified",
|
|
2228
|
-
"done",
|
|
2229
|
-
"cancelled",
|
|
2230
|
-
"superseded",
|
|
2231
|
-
],
|
|
2232
|
-
},
|
|
2233
|
-
note: { type: "string" },
|
|
2234
|
-
detail_level: { type: "string", enum: ["summary", "detail", "full"] },
|
|
2235
|
-
},
|
|
2236
|
-
required: ["issue_id", "task_id"],
|
|
2237
|
-
additionalProperties: false,
|
|
2238
|
-
},
|
|
2239
|
-
annotations: write,
|
|
2240
|
-
},
|
|
2241
|
-
{
|
|
2242
|
-
name: "dispatch_task",
|
|
2243
|
-
description:
|
|
2244
|
-
"Execute one Task with an agent selected at dispatch time. Task definitions remain executor-neutral; Codex, Claude, and GitHub Copilot are optional implementation tools.",
|
|
2245
|
-
inputSchema: {
|
|
2246
|
-
type: "object",
|
|
2247
|
-
properties: {
|
|
2248
|
-
issue_id: { type: "string" },
|
|
2249
|
-
task_id: { type: "string" },
|
|
2250
|
-
request_id: { type: "string" },
|
|
2251
|
-
agent: {
|
|
2252
|
-
type: "string",
|
|
2253
|
-
enum: ["codex", "claude", "github-copilot"],
|
|
2254
|
-
},
|
|
2255
|
-
timeout_ms: agentTimeoutSchema,
|
|
2256
|
-
isolate: {
|
|
2257
|
-
type: "boolean",
|
|
2258
|
-
description:
|
|
2259
|
-
"Optional. Omit for automatic placement: use the current workspace when no local Run is active and a worktree only for concurrency. false forces the current workspace and is rejected during concurrency; true forces a worktree.",
|
|
2260
|
-
},
|
|
2261
|
-
github_repo: { type: "string" },
|
|
2262
|
-
base_ref: { type: "string" },
|
|
2263
|
-
model: { type: "string" },
|
|
2264
|
-
create_pull_request: { type: "boolean" },
|
|
2265
|
-
approve_destructive: { type: "boolean", description: "Explicit same-request authorization for destructive or irreversible execution." },
|
|
2266
|
-
},
|
|
2267
|
-
required: ["issue_id", "task_id"],
|
|
1331
|
+
required: ["session_id"],
|
|
2268
1332
|
additionalProperties: false,
|
|
2269
1333
|
},
|
|
2270
1334
|
annotations: {
|
|
@@ -2274,62 +1338,40 @@ export function buildMcpToolDefinitions(
|
|
|
2274
1338
|
},
|
|
2275
1339
|
},
|
|
2276
1340
|
{
|
|
2277
|
-
name: "
|
|
1341
|
+
name: "finalize_edit_session",
|
|
2278
1342
|
description:
|
|
2279
|
-
"
|
|
1343
|
+
"Close an active edit session. Configured checks must pass; sessions without configured checks finalize directly.",
|
|
2280
1344
|
inputSchema: {
|
|
2281
1345
|
type: "object",
|
|
2282
1346
|
properties: {
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
timeout_ms: agentTimeoutSchema,
|
|
2288
|
-
isolate: {
|
|
2289
|
-
type: "boolean",
|
|
2290
|
-
description:
|
|
2291
|
-
"Optional. Omit for automatic placement: use the current workspace when no local Run is active and a worktree only for concurrency. false forces the current workspace and is rejected during concurrency; true forces a worktree.",
|
|
2292
|
-
},
|
|
2293
|
-
github_repo: { type: "string" },
|
|
2294
|
-
base_ref: { type: "string" },
|
|
2295
|
-
model: { type: "string" },
|
|
2296
|
-
create_pull_request: { type: "boolean" },
|
|
2297
|
-
approve_destructive: { type: "boolean", description: "Explicit same-request authorization for destructive or irreversible execution." },
|
|
1347
|
+
session_id: { type: "string" },
|
|
1348
|
+
reviewer: { type: "string" },
|
|
1349
|
+
note: { type: "string" },
|
|
1350
|
+
confirm_authorization: { type: "boolean", description: "Required when post-diff assurance detects protected paths or high semantic risk." },
|
|
2298
1351
|
},
|
|
2299
|
-
required: ["
|
|
1352
|
+
required: ["session_id"],
|
|
2300
1353
|
additionalProperties: false,
|
|
2301
1354
|
},
|
|
2302
|
-
annotations:
|
|
2303
|
-
readOnlyHint: false,
|
|
2304
|
-
openWorldHint: true,
|
|
2305
|
-
destructiveHint: false,
|
|
2306
|
-
},
|
|
1355
|
+
annotations: write,
|
|
2307
1356
|
},
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
if (policy.execution.fixedWorkflowCheck) {
|
|
1361
|
+
tools.push({
|
|
1362
|
+
name: "run_workflow_check",
|
|
1363
|
+
description: "Run the fixed forge strict workflow check.",
|
|
1364
|
+
inputSchema: EMPTY_SCHEMA,
|
|
1365
|
+
annotations: write,
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
if (opts.enableChatgptBrowser === true) {
|
|
1369
|
+
tools.push(
|
|
2308
1370
|
{
|
|
2309
|
-
name: "
|
|
1371
|
+
name: "run_chatgpt_browser_consult",
|
|
2310
1372
|
description:
|
|
2311
|
-
"
|
|
2312
|
-
inputSchema:
|
|
2313
|
-
type: "object",
|
|
2314
|
-
properties: {
|
|
2315
|
-
issue_id: { type: "string" },
|
|
2316
|
-
max_parallel: { type: "number" },
|
|
2317
|
-
request_id: { type: "string" },
|
|
2318
|
-
agent: { type: "string", enum: ["codex", "claude", "github-copilot"], description: "Optional runtime executor override for selected Tasks." },
|
|
2319
|
-
timeout_ms: agentTimeoutSchema,
|
|
2320
|
-
isolate: {
|
|
2321
|
-
type: "boolean",
|
|
2322
|
-
description:
|
|
2323
|
-
"Optional. Omit for automatic placement: use the current workspace when no local Run is active and a worktree only for concurrency. false forces the current workspace and is rejected during concurrency; true forces a worktree.",
|
|
2324
|
-
},
|
|
2325
|
-
github_repo: { type: "string" },
|
|
2326
|
-
base_ref: { type: "string" },
|
|
2327
|
-
model: { type: "string" },
|
|
2328
|
-
create_pull_request: { type: "boolean" },
|
|
2329
|
-
approve_destructive: { type: "boolean", description: "Explicit same-request authorization for destructive or irreversible execution." },
|
|
2330
|
-
},
|
|
2331
|
-
additionalProperties: false,
|
|
2332
|
-
},
|
|
1373
|
+
"Run a local ChatGPT Web browser consult through forge. This may create a real ChatGPT Web conversation unless dryRun is true.",
|
|
1374
|
+
inputSchema: browserRunSchema,
|
|
2333
1375
|
annotations: {
|
|
2334
1376
|
readOnlyHint: false,
|
|
2335
1377
|
openWorldHint: true,
|
|
@@ -2337,522 +1379,97 @@ export function buildMcpToolDefinitions(
|
|
|
2337
1379
|
},
|
|
2338
1380
|
},
|
|
2339
1381
|
{
|
|
2340
|
-
name: "
|
|
2341
|
-
description:
|
|
2342
|
-
"Read one persistent agent run with current status, bounded output tails, and opt-in path details.",
|
|
2343
|
-
inputSchema: {
|
|
2344
|
-
type: "object",
|
|
2345
|
-
properties: {
|
|
2346
|
-
run_id: { type: "string" },
|
|
2347
|
-
include_paths: { type: "boolean", description: "Opt in to full local filesystem paths and PIDs." },
|
|
2348
|
-
include_output: { type: "boolean", description: "Return bounded stdout/stderr tails. Defaults to true." },
|
|
2349
|
-
tail_chars: { type: "number", description: "Per-stream character budget for the bounded tails; capped at 16384." },
|
|
2350
|
-
},
|
|
2351
|
-
required: ["run_id"],
|
|
2352
|
-
additionalProperties: false,
|
|
2353
|
-
},
|
|
2354
|
-
annotations: readOnly,
|
|
2355
|
-
},
|
|
2356
|
-
{
|
|
2357
|
-
name: "get_task_run_events",
|
|
1382
|
+
name: "read_chatgpt_browser_session",
|
|
2358
1383
|
description:
|
|
2359
|
-
"Read
|
|
2360
|
-
inputSchema:
|
|
2361
|
-
type: "object",
|
|
2362
|
-
properties: {
|
|
2363
|
-
run_id: { type: "string" },
|
|
2364
|
-
limit: { type: "number" },
|
|
2365
|
-
since_event_index: { type: "number" },
|
|
2366
|
-
include_heartbeats: { type: "boolean" },
|
|
2367
|
-
},
|
|
2368
|
-
required: ["run_id"],
|
|
2369
|
-
additionalProperties: false,
|
|
2370
|
-
},
|
|
1384
|
+
"Read a saved forge ChatGPT browser consult session.",
|
|
1385
|
+
inputSchema: browserSessionSchema,
|
|
2371
1386
|
annotations: readOnly,
|
|
2372
1387
|
},
|
|
2373
1388
|
{
|
|
2374
|
-
name: "
|
|
1389
|
+
name: "list_chatgpt_browser_sessions",
|
|
2375
1390
|
description:
|
|
2376
|
-
"
|
|
1391
|
+
"List saved forge ChatGPT browser consult sessions.",
|
|
2377
1392
|
inputSchema: {
|
|
2378
1393
|
type: "object",
|
|
2379
|
-
properties: {
|
|
2380
|
-
run_id: { type: "string" },
|
|
2381
|
-
max_bytes: { type: "number", description: "Bounded log tail size; capped at 1 MiB." },
|
|
2382
|
-
},
|
|
2383
|
-
required: ["run_id"],
|
|
1394
|
+
properties: { limit: { type: "number" } },
|
|
2384
1395
|
additionalProperties: false,
|
|
2385
1396
|
},
|
|
2386
1397
|
annotations: readOnly,
|
|
2387
1398
|
},
|
|
2388
1399
|
{
|
|
2389
|
-
name: "
|
|
1400
|
+
name: "open_chatgpt_browser_session",
|
|
2390
1401
|
description:
|
|
2391
|
-
"
|
|
2392
|
-
inputSchema:
|
|
2393
|
-
type: "object",
|
|
2394
|
-
properties: {
|
|
2395
|
-
run_id: { type: "string" },
|
|
2396
|
-
max_bytes: { type: "number" },
|
|
2397
|
-
},
|
|
2398
|
-
required: ["run_id"],
|
|
2399
|
-
additionalProperties: false,
|
|
2400
|
-
},
|
|
1402
|
+
"Return the ChatGPT conversation URL for a saved browser session. The MCP tool does not launch the local browser.",
|
|
1403
|
+
inputSchema: browserSessionSchema,
|
|
2401
1404
|
annotations: readOnly,
|
|
2402
1405
|
},
|
|
2403
1406
|
{
|
|
2404
|
-
name: "
|
|
2405
|
-
description:
|
|
2406
|
-
"Integrate one reviewed isolated Task Run into the main working tree through a rollback-capable edit session.",
|
|
2407
|
-
inputSchema: {
|
|
2408
|
-
type: "object",
|
|
2409
|
-
properties: { run_id: { type: "string" } },
|
|
2410
|
-
required: ["run_id"],
|
|
2411
|
-
additionalProperties: false,
|
|
2412
|
-
},
|
|
2413
|
-
annotations: {
|
|
2414
|
-
readOnlyHint: false,
|
|
2415
|
-
openWorldHint: false,
|
|
2416
|
-
destructiveHint: true,
|
|
2417
|
-
},
|
|
2418
|
-
},
|
|
2419
|
-
{
|
|
2420
|
-
name: "finish_task_run",
|
|
1407
|
+
name: "continue_chatgpt_browser_session",
|
|
2421
1408
|
description:
|
|
2422
|
-
"
|
|
1409
|
+
"Create a follow-up ChatGPT browser consult record linked to an existing session.",
|
|
2423
1410
|
inputSchema: {
|
|
2424
1411
|
type: "object",
|
|
2425
1412
|
properties: {
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
enum: ["auto", "approve_and_finish", "request_changes", "discard"],
|
|
2430
|
-
},
|
|
2431
|
-
reviewer: { type: "string" },
|
|
2432
|
-
note: { type: "string" },
|
|
2433
|
-
cleanup: { type: "boolean" },
|
|
2434
|
-
commit: { type: "boolean", description: "Create a selected-path Git commit after successful finish. Refuses to mix with pre-staged changes." },
|
|
1413
|
+
sessionId: { type: "string" },
|
|
1414
|
+
prompt: { type: "string" },
|
|
1415
|
+
dryRun: { type: "boolean" },
|
|
2435
1416
|
},
|
|
2436
|
-
required: ["
|
|
1417
|
+
required: ["sessionId", "prompt"],
|
|
2437
1418
|
additionalProperties: false,
|
|
2438
1419
|
},
|
|
2439
1420
|
annotations: {
|
|
2440
1421
|
readOnlyHint: false,
|
|
2441
|
-
openWorldHint:
|
|
1422
|
+
openWorldHint: true,
|
|
2442
1423
|
destructiveHint: false,
|
|
2443
1424
|
},
|
|
2444
1425
|
},
|
|
2445
|
-
{
|
|
2446
|
-
name: "list_task_runs",
|
|
2447
|
-
description: "List recent persistent agent runs.",
|
|
2448
|
-
inputSchema: {
|
|
2449
|
-
type: "object",
|
|
2450
|
-
properties: {
|
|
2451
|
-
limit: { type: "number" },
|
|
2452
|
-
include_paths: { type: "boolean", description: "Opt in to full local filesystem paths and PIDs." },
|
|
2453
|
-
},
|
|
2454
|
-
additionalProperties: false,
|
|
2455
|
-
},
|
|
2456
|
-
annotations: readOnly,
|
|
2457
|
-
},
|
|
2458
|
-
{
|
|
2459
|
-
name: "cancel_task_run",
|
|
2460
|
-
description: "Cancel a queued or running local agent task.",
|
|
2461
|
-
inputSchema: {
|
|
2462
|
-
type: "object",
|
|
2463
|
-
properties: { run_id: { type: "string" } },
|
|
2464
|
-
required: ["run_id"],
|
|
2465
|
-
additionalProperties: false,
|
|
2466
|
-
},
|
|
2467
|
-
annotations: {
|
|
2468
|
-
readOnlyHint: false,
|
|
2469
|
-
openWorldHint: false,
|
|
2470
|
-
destructiveHint: true,
|
|
2471
|
-
},
|
|
2472
|
-
},
|
|
2473
|
-
{
|
|
2474
|
-
name: "retry_task_run",
|
|
2475
|
-
description:
|
|
2476
|
-
"Create a new run for a failed, blocked, cancelled, or change-requested task.",
|
|
2477
|
-
inputSchema: {
|
|
2478
|
-
type: "object",
|
|
2479
|
-
properties: {
|
|
2480
|
-
run_id: { type: "string" },
|
|
2481
|
-
timeout_ms: agentTimeoutSchema,
|
|
2482
|
-
isolate: {
|
|
2483
|
-
type: "boolean",
|
|
2484
|
-
description:
|
|
2485
|
-
"Optional. Omit for automatic placement: use the current workspace when no local Run is active and a worktree only for concurrency. false forces the current workspace and is rejected during concurrency; true forces a worktree.",
|
|
2486
|
-
},
|
|
2487
|
-
},
|
|
2488
|
-
required: ["run_id"],
|
|
2489
|
-
additionalProperties: false,
|
|
2490
|
-
},
|
|
2491
|
-
annotations: write,
|
|
2492
|
-
},
|
|
2493
|
-
{
|
|
2494
|
-
name: "verify_task",
|
|
2495
|
-
description:
|
|
2496
|
-
"Record task-local completion evidence. Declared checks execute through persisted Process Runtime receipts; retries reuse the same processes and reported command evidence can satisfy risk-adaptive verification.",
|
|
2497
|
-
inputSchema: {
|
|
2498
|
-
type: "object",
|
|
2499
|
-
properties: {
|
|
2500
|
-
issue_id: { type: "string" },
|
|
2501
|
-
task_id: { type: "string" },
|
|
2502
|
-
run_id: { type: "string" },
|
|
2503
|
-
integrated_revision: { type: "string" },
|
|
2504
|
-
reviewed_diff_hash: { type: "string" },
|
|
2505
|
-
reviewer: { type: "string" },
|
|
2506
|
-
request_id: { type: "string", description: "Stable idempotency key for Process Runtime checks; retries reuse the original processes." },
|
|
2507
|
-
check_results: {
|
|
2508
|
-
type: "array",
|
|
2509
|
-
items: {
|
|
2510
|
-
type: "object",
|
|
2511
|
-
properties: {
|
|
2512
|
-
check_id: { type: "string" },
|
|
2513
|
-
ok: { type: "boolean", description: "Deprecated compatibility field. The Controller executes the named check and uses the actual outcome." },
|
|
2514
|
-
summary: { type: "string" },
|
|
2515
|
-
},
|
|
2516
|
-
required: ["check_id"],
|
|
2517
|
-
additionalProperties: false,
|
|
2518
|
-
},
|
|
2519
|
-
},
|
|
2520
|
-
reported_commands: {
|
|
2521
|
-
type: "array",
|
|
2522
|
-
items: {
|
|
2523
|
-
type: "object",
|
|
2524
|
-
properties: {
|
|
2525
|
-
command: { type: "array", items: { type: "string" }, minItems: 1 },
|
|
2526
|
-
cwd: { type: "string" },
|
|
2527
|
-
ok: { type: "boolean" },
|
|
2528
|
-
exit_code: { type: "number" },
|
|
2529
|
-
stdout: { type: "string" },
|
|
2530
|
-
stderr: { type: "string" },
|
|
2531
|
-
artifact_path: { type: "string" },
|
|
2532
|
-
executed_at: { type: "string" },
|
|
2533
|
-
},
|
|
2534
|
-
required: ["command", "ok"],
|
|
2535
|
-
additionalProperties: false,
|
|
2536
|
-
},
|
|
2537
|
-
},
|
|
2538
|
-
acceptance_results: {
|
|
2539
|
-
type: "array",
|
|
2540
|
-
items: {
|
|
2541
|
-
type: "object",
|
|
2542
|
-
properties: {
|
|
2543
|
-
criterion: { type: "string" },
|
|
2544
|
-
ok: { type: "boolean" },
|
|
2545
|
-
evidence: { type: "string" },
|
|
2546
|
-
},
|
|
2547
|
-
required: ["criterion", "ok"],
|
|
2548
|
-
additionalProperties: false,
|
|
2549
|
-
},
|
|
2550
|
-
},
|
|
2551
|
-
},
|
|
2552
|
-
required: ["issue_id", "task_id", "reviewer"],
|
|
2553
|
-
additionalProperties: false,
|
|
2554
|
-
},
|
|
2555
|
-
annotations: write,
|
|
2556
|
-
},
|
|
2557
|
-
{
|
|
2558
|
-
name: "accept_task",
|
|
2559
|
-
description:
|
|
2560
|
-
"Accept a verified task, mark it done, and unlock dependent tasks.",
|
|
2561
|
-
inputSchema: {
|
|
2562
|
-
type: "object",
|
|
2563
|
-
properties: {
|
|
2564
|
-
issue_id: { type: "string" },
|
|
2565
|
-
task_id: { type: "string" },
|
|
2566
|
-
work_id: { type: "string" },
|
|
2567
|
-
note: { type: "string" },
|
|
2568
|
-
},
|
|
2569
|
-
required: ["issue_id", "task_id"],
|
|
2570
|
-
additionalProperties: false,
|
|
2571
|
-
},
|
|
2572
|
-
annotations: write,
|
|
2573
|
-
},
|
|
2574
|
-
{
|
|
2575
|
-
name: "request_task_changes",
|
|
2576
|
-
description:
|
|
2577
|
-
"Return a reviewed task for another focused execution run.",
|
|
2578
|
-
inputSchema: {
|
|
2579
|
-
type: "object",
|
|
2580
|
-
properties: {
|
|
2581
|
-
issue_id: { type: "string" },
|
|
2582
|
-
task_id: { type: "string" },
|
|
2583
|
-
note: { type: "string" },
|
|
2584
|
-
},
|
|
2585
|
-
required: ["issue_id", "task_id", "note"],
|
|
2586
|
-
additionalProperties: false,
|
|
2587
|
-
},
|
|
2588
|
-
annotations: write,
|
|
2589
|
-
},
|
|
2590
|
-
{
|
|
2591
|
-
name: "begin_edit_session",
|
|
2592
|
-
description:
|
|
2593
|
-
"Open a bounded direct-edit session tied to a purpose and optional Issue/Task.",
|
|
2594
|
-
inputSchema: {
|
|
2595
|
-
type: "object",
|
|
2596
|
-
properties: {
|
|
2597
|
-
purpose: { type: "string" },
|
|
2598
|
-
work_id: { type: "string", description: "Optional existing WorkContract. Omit to create lightweight direct-control Work lineage." },
|
|
2599
|
-
issue_id: { type: "string" },
|
|
2600
|
-
task_id: { type: "string" },
|
|
2601
|
-
allowed_paths: { type: "array", items: { type: "string" } },
|
|
2602
|
-
max_files: { type: "number" },
|
|
2603
|
-
max_changed_lines: { type: "number" },
|
|
2604
|
-
checks: { type: "array", items: { type: "string" }, description: "Named checks to run before finalization." },
|
|
2605
|
-
},
|
|
2606
|
-
required: ["purpose"],
|
|
2607
|
-
additionalProperties: false,
|
|
2608
|
-
},
|
|
2609
|
-
annotations: write,
|
|
2610
|
-
},
|
|
2611
|
-
{
|
|
2612
|
-
name: "apply_patch",
|
|
2613
|
-
description:
|
|
2614
|
-
"Append one bounded patch batch to an active edit session. Prefer batches of 100 operations or fewer and pass expected_revision to avoid stale revisions.",
|
|
2615
|
-
inputSchema: {
|
|
2616
|
-
type: "object",
|
|
2617
|
-
properties: {
|
|
2618
|
-
session_id: { type: "string" },
|
|
2619
|
-
expected_revision: { type: "number", description: "Optional current revision precondition for the edit session." },
|
|
2620
|
-
operations: {
|
|
2621
|
-
type: "array",
|
|
2622
|
-
items: EDIT_OPERATION_INPUT_SCHEMA,
|
|
2623
|
-
},
|
|
2624
|
-
},
|
|
2625
|
-
required: ["session_id", "operations"],
|
|
2626
|
-
additionalProperties: false,
|
|
2627
|
-
},
|
|
2628
|
-
annotations: {
|
|
2629
|
-
readOnlyHint: false,
|
|
2630
|
-
openWorldHint: false,
|
|
2631
|
-
destructiveHint: false,
|
|
2632
|
-
},
|
|
2633
|
-
},
|
|
2634
|
-
{
|
|
2635
|
-
name: "get_edit_session",
|
|
2636
|
-
description: "Read an edit session, revisions, savepoints, and operation manifest.",
|
|
2637
|
-
inputSchema: {
|
|
2638
|
-
type: "object",
|
|
2639
|
-
properties: { session_id: { type: "string" } },
|
|
2640
|
-
required: ["session_id"],
|
|
2641
|
-
additionalProperties: false,
|
|
2642
|
-
},
|
|
2643
|
-
annotations: readOnly,
|
|
2644
|
-
},
|
|
2645
|
-
{
|
|
2646
|
-
name: "list_edit_sessions",
|
|
2647
|
-
description: "List recent direct-edit sessions with revision, changed-file, and check summaries.",
|
|
2648
|
-
inputSchema: {
|
|
2649
|
-
type: "object",
|
|
2650
|
-
properties: { limit: { type: "number" } },
|
|
2651
|
-
additionalProperties: false,
|
|
2652
|
-
},
|
|
2653
|
-
annotations: readOnly,
|
|
2654
|
-
},
|
|
2655
|
-
{
|
|
2656
|
-
name: "get_edit_session_diff",
|
|
2657
|
-
description: "Read the current aggregate localized diff for one direct-edit session.",
|
|
2658
|
-
inputSchema: {
|
|
2659
|
-
type: "object",
|
|
2660
|
-
properties: { session_id: { type: "string" } },
|
|
2661
|
-
required: ["session_id"],
|
|
2662
|
-
additionalProperties: false,
|
|
2663
|
-
},
|
|
2664
|
-
annotations: readOnly,
|
|
2665
|
-
},
|
|
2666
|
-
{
|
|
2667
|
-
name: "create_edit_savepoint",
|
|
2668
|
-
description: "Name the current edit revision so later patch batches can be rolled back to it.",
|
|
2669
|
-
inputSchema: {
|
|
2670
|
-
type: "object",
|
|
2671
|
-
properties: {
|
|
2672
|
-
session_id: { type: "string" },
|
|
2673
|
-
name: { type: "string" },
|
|
2674
|
-
},
|
|
2675
|
-
required: ["session_id", "name"],
|
|
2676
|
-
additionalProperties: false,
|
|
2677
|
-
},
|
|
2678
|
-
annotations: write,
|
|
2679
|
-
},
|
|
2680
|
-
{
|
|
2681
|
-
name: "verify_edit_session",
|
|
2682
|
-
description: "Verify the current edit revision through persisted Process Runtime checks. Retries with the same request_id reuse the original process and terminal receipts are attached to the exact revision.",
|
|
2683
|
-
inputSchema: {
|
|
2684
|
-
type: "object",
|
|
2685
|
-
properties: {
|
|
2686
|
-
session_id: { type: "string" },
|
|
2687
|
-
check_ids: { type: "array", items: { type: "string" } },
|
|
2688
|
-
request_id: { type: "string" },
|
|
2689
|
-
reviewer: { type: "string" },
|
|
2690
|
-
note: { type: "string" },
|
|
2691
|
-
},
|
|
2692
|
-
required: ["session_id"],
|
|
2693
|
-
additionalProperties: false,
|
|
2694
|
-
},
|
|
2695
|
-
annotations: write,
|
|
2696
|
-
},
|
|
2697
|
-
{
|
|
2698
|
-
name: "rollback_edit_session",
|
|
2699
|
-
description:
|
|
2700
|
-
"Rollback an active edit session completely, to a prior revision, or to a named savepoint.",
|
|
2701
|
-
inputSchema: {
|
|
2702
|
-
type: "object",
|
|
2703
|
-
properties: {
|
|
2704
|
-
session_id: { type: "string" },
|
|
2705
|
-
to_revision: { type: "number", description: "Keep revisions up to this value; omit for full rollback." },
|
|
2706
|
-
savepoint: { type: "string", description: "Rollback to a named savepoint." },
|
|
2707
|
-
},
|
|
2708
|
-
required: ["session_id"],
|
|
2709
|
-
additionalProperties: false,
|
|
2710
|
-
},
|
|
2711
|
-
annotations: {
|
|
2712
|
-
readOnlyHint: false,
|
|
2713
|
-
openWorldHint: false,
|
|
2714
|
-
destructiveHint: false,
|
|
2715
|
-
},
|
|
2716
|
-
},
|
|
2717
|
-
{
|
|
2718
|
-
name: "finalize_edit_session",
|
|
2719
|
-
description:
|
|
2720
|
-
"Close an active edit session. Configured checks must pass; sessions without configured checks finalize directly.",
|
|
2721
|
-
inputSchema: {
|
|
2722
|
-
type: "object",
|
|
2723
|
-
properties: {
|
|
2724
|
-
session_id: { type: "string" },
|
|
2725
|
-
reviewer: { type: "string" },
|
|
2726
|
-
note: { type: "string" },
|
|
2727
|
-
confirm_authorization: { type: "boolean", description: "Required when post-diff assurance detects protected paths or high semantic risk." },
|
|
2728
|
-
},
|
|
2729
|
-
required: ["session_id"],
|
|
2730
|
-
additionalProperties: false,
|
|
2731
|
-
},
|
|
2732
|
-
annotations: write,
|
|
2733
|
-
},
|
|
2734
|
-
{
|
|
2735
|
-
name: "finish_edit_session",
|
|
2736
|
-
description:
|
|
2737
|
-
"Verify, finalize, selected-path commit, receipt, and complete the Task bound to one Direct Edit session.",
|
|
2738
|
-
inputSchema: {
|
|
2739
|
-
type: "object",
|
|
2740
|
-
properties: {
|
|
2741
|
-
session_id: { type: "string" },
|
|
2742
|
-
decision: { type: "string", enum: ["auto", "approve_and_finish", "request_changes", "discard"] },
|
|
2743
|
-
reviewer: { type: "string" },
|
|
2744
|
-
note: { type: "string" },
|
|
2745
|
-
check_ids: { type: "array", items: { type: "string" } },
|
|
2746
|
-
commit: { type: "boolean" },
|
|
2747
|
-
},
|
|
2748
|
-
required: ["session_id"],
|
|
2749
|
-
additionalProperties: false,
|
|
2750
|
-
},
|
|
2751
|
-
annotations: write,
|
|
2752
|
-
},
|
|
2753
1426
|
);
|
|
2754
1427
|
}
|
|
1428
|
+
return tools.filter((tool) => !RETIRED_LEGACY_PUBLIC_TOOLS.has(tool.name));
|
|
1429
|
+
}
|
|
2755
1430
|
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
inputSchema: EMPTY_SCHEMA,
|
|
2761
|
-
annotations: write,
|
|
2762
|
-
});
|
|
2763
|
-
}
|
|
2764
|
-
if (opts.enableChatgptBrowser === true) {
|
|
2765
|
-
tools.push(
|
|
2766
|
-
{
|
|
2767
|
-
name: "run_chatgpt_browser_consult",
|
|
2768
|
-
description:
|
|
2769
|
-
"Run a local ChatGPT Web browser consult through forge. This may create a real ChatGPT Web conversation unless dryRun is true.",
|
|
2770
|
-
inputSchema: browserRunSchema,
|
|
2771
|
-
annotations: {
|
|
2772
|
-
readOnlyHint: false,
|
|
2773
|
-
openWorldHint: true,
|
|
2774
|
-
destructiveHint: false,
|
|
2775
|
-
},
|
|
2776
|
-
},
|
|
2777
|
-
{
|
|
2778
|
-
name: "read_chatgpt_browser_session",
|
|
2779
|
-
description:
|
|
2780
|
-
"Read a saved forge ChatGPT browser consult session.",
|
|
2781
|
-
inputSchema: browserSessionSchema,
|
|
2782
|
-
annotations: readOnly,
|
|
2783
|
-
},
|
|
2784
|
-
{
|
|
2785
|
-
name: "list_chatgpt_browser_sessions",
|
|
2786
|
-
description:
|
|
2787
|
-
"List saved forge ChatGPT browser consult sessions.",
|
|
2788
|
-
inputSchema: {
|
|
2789
|
-
type: "object",
|
|
2790
|
-
properties: { limit: { type: "number" } },
|
|
2791
|
-
additionalProperties: false,
|
|
2792
|
-
},
|
|
2793
|
-
annotations: readOnly,
|
|
2794
|
-
},
|
|
2795
|
-
{
|
|
2796
|
-
name: "open_chatgpt_browser_session",
|
|
2797
|
-
description:
|
|
2798
|
-
"Return the ChatGPT conversation URL for a saved browser session. The MCP tool does not launch the local browser.",
|
|
2799
|
-
inputSchema: browserSessionSchema,
|
|
2800
|
-
annotations: readOnly,
|
|
2801
|
-
},
|
|
2802
|
-
{
|
|
2803
|
-
name: "continue_chatgpt_browser_session",
|
|
2804
|
-
description:
|
|
2805
|
-
"Create a follow-up ChatGPT browser consult record linked to an existing session.",
|
|
2806
|
-
inputSchema: {
|
|
2807
|
-
type: "object",
|
|
2808
|
-
properties: {
|
|
2809
|
-
sessionId: { type: "string" },
|
|
2810
|
-
prompt: { type: "string" },
|
|
2811
|
-
dryRun: { type: "boolean" },
|
|
2812
|
-
},
|
|
2813
|
-
required: ["sessionId", "prompt"],
|
|
2814
|
-
additionalProperties: false,
|
|
2815
|
-
},
|
|
2816
|
-
annotations: {
|
|
2817
|
-
readOnlyHint: false,
|
|
2818
|
-
openWorldHint: true,
|
|
2819
|
-
destructiveHint: false,
|
|
2820
|
-
},
|
|
2821
|
-
},
|
|
2822
|
-
);
|
|
2823
|
-
}
|
|
2824
|
-
return tools;
|
|
2825
|
-
}
|
|
2826
|
-
|
|
2827
|
-
export function controllerExpectedToolNames(
|
|
2828
|
-
policy: McpPolicy,
|
|
2829
|
-
opts: { enableChatgptBrowser?: boolean } = {},
|
|
2830
|
-
): string[] {
|
|
2831
|
-
const names = buildMcpToolDefinitions(policy, opts).map((tool) => tool.name);
|
|
2832
|
-
if (policy.profile !== "controller") return names;
|
|
2833
|
-
// The Connector readiness expectation must match the bounded default schema
|
|
2834
|
-
// served by toolset.ts. Full compatibility tools are intentionally omitted.
|
|
2835
|
-
return [...DEFAULT_CONTROLLER_TOOL_NAMES];
|
|
2836
|
-
}
|
|
2837
|
-
|
|
2838
|
-
const RETIRED_LEGACY_MUTATION_TOOLS = new Set([
|
|
1431
|
+
const RETIRED_LEGACY_PUBLIC_TOOLS = new Set([
|
|
1432
|
+
"list_issues",
|
|
1433
|
+
"get_project_board",
|
|
1434
|
+
"get_project_governance",
|
|
2839
1435
|
"reconcile_project_governance",
|
|
1436
|
+
"get_project_state",
|
|
2840
1437
|
"set_current_issue",
|
|
2841
1438
|
"archive_issue",
|
|
2842
1439
|
"restore_issue",
|
|
1440
|
+
"get_issue",
|
|
2843
1441
|
"publish_issue_to_github",
|
|
2844
1442
|
"refresh_github_issue",
|
|
2845
1443
|
"close_github_issue",
|
|
1444
|
+
"inspect_issue_readiness",
|
|
1445
|
+
"inspect_task_readiness",
|
|
2846
1446
|
"prepare_issue_launch",
|
|
2847
1447
|
"create_issue",
|
|
1448
|
+
"update_issue",
|
|
2848
1449
|
"plan_issue",
|
|
2849
1450
|
"append_task",
|
|
2850
1451
|
"split_task",
|
|
2851
1452
|
"supersede_task",
|
|
2852
1453
|
"set_task_dependencies",
|
|
2853
1454
|
"update_task",
|
|
1455
|
+
"dispatch_task",
|
|
1456
|
+
"launch_issue",
|
|
1457
|
+
"dispatch_ready_tasks",
|
|
1458
|
+
"get_task_run",
|
|
1459
|
+
"get_task_run_events",
|
|
1460
|
+
"get_task_run_log",
|
|
1461
|
+
"get_task_diff",
|
|
1462
|
+
"integrate_task_run",
|
|
1463
|
+
"finish_task_run",
|
|
1464
|
+
"list_task_runs",
|
|
1465
|
+
"cancel_task_run",
|
|
1466
|
+
"retry_task_run",
|
|
1467
|
+
"verify_task",
|
|
1468
|
+
"accept_task",
|
|
1469
|
+
"request_task_changes",
|
|
2854
1470
|
"record_task_verification",
|
|
2855
1471
|
"accept_verified_task",
|
|
1472
|
+
"finish_edit_session",
|
|
2856
1473
|
]);
|
|
2857
1474
|
|
|
2858
1475
|
export async function callMcpTool(
|
|
@@ -2861,1617 +1478,651 @@ export async function callMcpTool(
|
|
|
2861
1478
|
args: Record<string, unknown> = {},
|
|
2862
1479
|
): Promise<CallToolResult> {
|
|
2863
1480
|
try {
|
|
2864
|
-
if (
|
|
1481
|
+
if (RETIRED_LEGACY_PUBLIC_TOOLS.has(name)) {
|
|
2865
1482
|
audit(ctx, name, "blocked", args);
|
|
2866
|
-
return errorResult(
|
|
2867
|
-
"LEGACY_CONTROL_PLANE_MUTATION_RETIRED",
|
|
2868
|
-
`${name} cannot mutate frozen Issue/Task/currentIssue/project-board compatibility files after SQLite cutover. Use Requirement, Plan and Work APIs.`,
|
|
2869
|
-
);
|
|
1483
|
+
return errorResult("UNKNOWN_TOOL", `unknown tool: ${name}`);
|
|
2870
1484
|
}
|
|
2871
1485
|
switch (name) {
|
|
2872
1486
|
case "harness_status": {
|
|
2873
1487
|
const roots = [
|
|
2874
1488
|
"docs/spec.md",
|
|
2875
|
-
"plans",
|
|
2876
|
-
"tasks/current.md",
|
|
2877
|
-
".ai/harness/session",
|
|
2878
|
-
".ai/harness/controller/packets",
|
|
2879
|
-
".ai/harness/projections",
|
|
2880
|
-
".ai/harness/checks",
|
|
2881
|
-
];
|
|
2882
|
-
audit(ctx, name, "ok", args);
|
|
2883
|
-
return textResult({
|
|
2884
|
-
repoRoot: ctx.repoRoot,
|
|
2885
|
-
adopted: isForgeAdopted(ctx.repoRoot),
|
|
2886
|
-
profile: ctx.policy.profile,
|
|
2887
|
-
branch: currentGitBranch(ctx.repoRoot),
|
|
2888
|
-
workflowRoots: roots.map((path) => ({
|
|
2889
|
-
path,
|
|
2890
|
-
exists: existsSync(join(ctx.repoRoot, path)),
|
|
2891
|
-
})),
|
|
2892
|
-
});
|
|
2893
|
-
}
|
|
2894
|
-
case "harness_doctor": {
|
|
2895
|
-
const localConfig = existsSync(
|
|
2896
|
-
join(ctx.repoRoot, ".forge", "mcp.local.json"),
|
|
2897
|
-
);
|
|
2898
|
-
const codexConfig = existsSync(
|
|
2899
|
-
join(ctx.repoRoot, ".codex", "config.toml"),
|
|
2900
|
-
);
|
|
2901
|
-
audit(ctx, name, "ok", args);
|
|
2902
|
-
return textResult({
|
|
2903
|
-
status: isForgeAdopted(ctx.repoRoot)
|
|
2904
|
-
? "ready_local"
|
|
2905
|
-
: "not_adopted",
|
|
2906
|
-
repo: ctx.repoRoot,
|
|
2907
|
-
profile: ctx.policy.profile,
|
|
2908
|
-
mcp: {
|
|
2909
|
-
localConfig,
|
|
2910
|
-
policy: "builtin",
|
|
2911
|
-
profile: ctx.policy.profile,
|
|
2912
|
-
toolSurface:
|
|
2913
|
-
ctx.policy.profile === "controller"
|
|
2914
|
-
? FORGE_TOOL_SURFACE
|
|
2915
|
-
: `${ctx.policy.profile}-legacy-v1`,
|
|
2916
|
-
toolCount: buildMcpToolDefinitions(ctx.policy, {
|
|
2917
|
-
enableChatgptBrowser: ctx.enableChatgptBrowser === true,
|
|
2918
|
-
}).length,
|
|
2919
|
-
repositoryRead:
|
|
2920
|
-
ctx.policy.profile === "controller"
|
|
2921
|
-
? "ordinary repository source and document files are readable; immutable secret and runtime paths remain denied"
|
|
2922
|
-
: "workflow-scoped",
|
|
2923
|
-
deniedPaths: ctx.policy.denyGlobs.length,
|
|
2924
|
-
runner: {
|
|
2925
|
-
enabled: ctx.policy.execution.agentRunner,
|
|
2926
|
-
defaultTimeoutMs: ctx.policy.execution.runnerTimeoutMs,
|
|
2927
|
-
maxTimeoutMs: ctx.policy.execution.runnerMaxTimeoutMs,
|
|
2928
|
-
},
|
|
2929
|
-
},
|
|
2930
|
-
codex: {
|
|
2931
|
-
configured: codexConfig,
|
|
2932
|
-
fix: codexConfig
|
|
2933
|
-
? null
|
|
2934
|
-
: "forge mcp setup codex --repo . --scope project",
|
|
2935
|
-
},
|
|
2936
|
-
chatgpt: {
|
|
2937
|
-
localEndpoint: "http://127.0.0.1:8765/mcp",
|
|
2938
|
-
manualStepsRequired: true,
|
|
2939
|
-
guide: "docs/forge-chatgpt-mcp-setup.md",
|
|
2940
|
-
},
|
|
2941
|
-
});
|
|
2942
|
-
}
|
|
2943
|
-
case "controller_capabilities": {
|
|
2944
|
-
if (ctx.policy.profile !== "controller")
|
|
2945
|
-
return errorResult(
|
|
2946
|
-
"TOOL_DISABLED",
|
|
2947
|
-
"controller_capabilities requires the controller profile",
|
|
2948
|
-
);
|
|
2949
|
-
const expectedTools = controllerExpectedToolNames(ctx.policy, {
|
|
2950
|
-
enableChatgptBrowser: ctx.enableChatgptBrowser === true,
|
|
2951
|
-
});
|
|
2952
|
-
const preferredTools: string[] = [...PREFERRED_FACADE_TOOL_NAMES];
|
|
2953
|
-
const capabilityDescriptors = listCapabilityDescriptors();
|
|
2954
|
-
const connectorSnapshot = Array.isArray(args.connector_tool_names)
|
|
2955
|
-
? args.connector_tool_names.map(String)
|
|
2956
|
-
: Array.isArray(args.connectorToolNames)
|
|
2957
|
-
? args.connectorToolNames.map(String)
|
|
2958
|
-
: undefined;
|
|
2959
|
-
const connectorFreshness = await buildLocalConnectorStatusForRepo({
|
|
2960
|
-
repoRoot: ctx.repoRoot,
|
|
2961
|
-
expectedTools,
|
|
2962
|
-
connectorToolNames: connectorSnapshot,
|
|
2963
|
-
});
|
|
2964
|
-
// staleConnector only when ChatGPT snapshot is supplied and missing rh_*.
|
|
2965
|
-
const missingFacadeTools = connectorFreshness.missingConnectorTools;
|
|
2966
|
-
const staleConnector = connectorFreshness.status === "chatgpt_snapshot_missing_facade";
|
|
2967
|
-
const payload = {
|
|
2968
|
-
schemaVersion: FORGE_MCP_SCHEMA_VERSION,
|
|
2969
|
-
toolSurface: FORGE_TOOL_SURFACE,
|
|
2970
|
-
version: FORGE_VERSION,
|
|
2971
|
-
toolSurfaceFingerprint: forgeToolSurfaceFingerprint(expectedTools),
|
|
2972
|
-
executionModel: "chatgpt-controller-execution-bridge",
|
|
2973
|
-
profile: ctx.policy.profile,
|
|
2974
|
-
capabilities: {
|
|
2975
|
-
repositoryInspection: true,
|
|
2976
|
-
issueLauncher: true,
|
|
2977
|
-
githubIssuesAndProjects: true,
|
|
2978
|
-
localAgentRuns: ctx.policy.execution.agentRunner,
|
|
2979
|
-
githubCopilotSessions: true,
|
|
2980
|
-
dynamicTaskGraph: true,
|
|
2981
|
-
runtimeAgentSelection: true,
|
|
2982
|
-
taskAgentBinding: false,
|
|
2983
|
-
structuredRunEvents: true,
|
|
2984
|
-
boundedDirectEdits: true,
|
|
2985
|
-
multiRevisionDirectEdits: true,
|
|
2986
|
-
editSavepoints: true,
|
|
2987
|
-
partialEditRollback: true,
|
|
2988
|
-
directEditFirstRouting: true,
|
|
2989
|
-
persistedEditDiffs: true,
|
|
2990
|
-
verifiedEditFinalization: true,
|
|
2991
|
-
verificationGate: true,
|
|
2992
|
-
localRunWatch: true,
|
|
2993
|
-
localVisualController: true,
|
|
2994
|
-
hierarchicalControllerUI: true,
|
|
2995
|
-
localApprovalQueue: false,
|
|
2996
|
-
localRiskApprovalGate: false,
|
|
2997
|
-
quickAgentSessions: true,
|
|
2998
|
-
persistentTimeouts: true,
|
|
2999
|
-
timeoutProgress: true,
|
|
3000
|
-
connectorSchemaDiagnostics: true,
|
|
3001
|
-
projectProgressAggregation: true,
|
|
3002
|
-
effectiveTaskStatus: true,
|
|
3003
|
-
unifiedWorklogTimeline: true,
|
|
3004
|
-
exportableWorklogReports: true,
|
|
3005
|
-
githubPluginConfiguration: true,
|
|
3006
|
-
serverSentEventDashboard: true,
|
|
3007
|
-
singleExecutionFocus: false,
|
|
3008
|
-
taskLocalReadiness: true,
|
|
3009
|
-
riskAdaptiveVerification: true,
|
|
3010
|
-
ephemeralQuickAgentSessions: true,
|
|
3011
|
-
automaticRunContinuation: true,
|
|
3012
|
-
reportedCommandEvidence: true,
|
|
3013
|
-
governanceDiagnostics: true,
|
|
3014
|
-
safeGovernanceReconciliation: true,
|
|
3015
|
-
evidenceGateProgress: true,
|
|
3016
|
-
directTaskActions: true,
|
|
3017
|
-
issueArchiving: true,
|
|
3018
|
-
retryableRunFailures: true,
|
|
3019
|
-
issueCreationGuardrails: true,
|
|
3020
|
-
persistedCheckEvidence: true,
|
|
3021
|
-
persistedCheckReuse: true,
|
|
3022
|
-
directVerification: true,
|
|
3023
|
-
controllerContextAggregation: true,
|
|
3024
|
-
taskLedgerProjection: true,
|
|
3025
|
-
assistantPluginRuntime: true,
|
|
3026
|
-
chatgptFacadeTools: true,
|
|
3027
|
-
goalWorkloop: true,
|
|
3028
|
-
handoffInbox: true,
|
|
3029
|
-
codexGrokDelegation: true,
|
|
3030
|
-
selfHealingRepair: true,
|
|
3031
|
-
},
|
|
3032
|
-
runner: {
|
|
3033
|
-
enabled: ctx.policy.execution.agentRunner,
|
|
3034
|
-
allowedAgents: ctx.policy.execution.allowedAgents,
|
|
3035
|
-
defaultTimeoutMs: ctx.policy.execution.runnerTimeoutMs,
|
|
3036
|
-
defaultTimeout: formatDurationMs(
|
|
3037
|
-
ctx.policy.execution.runnerTimeoutMs,
|
|
3038
|
-
),
|
|
3039
|
-
maxTimeoutMs: ctx.policy.execution.runnerMaxTimeoutMs,
|
|
3040
|
-
maxTimeout: formatDurationMs(
|
|
3041
|
-
ctx.policy.execution.runnerMaxTimeoutMs,
|
|
3042
|
-
),
|
|
3043
|
-
note: "Requested timeout values are validated explicitly and are never silently reduced to the default.",
|
|
3044
|
-
},
|
|
3045
|
-
preferredTools,
|
|
3046
|
-
capabilityGroups: summarizeCapabilityGroups(),
|
|
3047
|
-
toolArchitecture: {
|
|
3048
|
-
facadeTools: preferredTools,
|
|
3049
|
-
atomicTypedToolsRetained: true,
|
|
3050
|
-
internalHandlersRetained: true,
|
|
3051
|
-
domainSchemaLoading: 'static_stable_surface',
|
|
3052
|
-
dynamicDomainSchemaLoadingSupported: false,
|
|
3053
|
-
capabilityDescriptorCount: capabilityDescriptors.length,
|
|
3054
|
-
},
|
|
3055
|
-
toolExposure: {
|
|
3056
|
-
preferred: preferredTools,
|
|
3057
|
-
note: "Prefer the five rh_* workflow facades for orchestration. Typed repository, Git, Issue/Task, plugin, browser, iOS, artifact, and recovery tools remain available because the current MCP transport cannot load domain schemas per conversation.",
|
|
3058
|
-
advanced: expectedTools.filter((tool) => !preferredTools.includes(tool)).slice(0, 40),
|
|
3059
|
-
compatibilityRetained: true,
|
|
3060
|
-
},
|
|
3061
|
-
expectedTools,
|
|
3062
|
-
facadeToolsPresentInExpectedTools: preferredTools.every((tool: string) => expectedTools.includes(tool)),
|
|
3063
|
-
staleConnector,
|
|
3064
|
-
missingFacadeTools,
|
|
3065
|
-
connectorFreshness: {
|
|
3066
|
-
status: connectorFreshness.status,
|
|
3067
|
-
severity: connectorFreshness.severity,
|
|
3068
|
-
summary: connectorFreshness.summary,
|
|
3069
|
-
missingLocalTools: connectorFreshness.missingLocalTools,
|
|
3070
|
-
missingConnectorTools: connectorFreshness.missingConnectorTools,
|
|
3071
|
-
expectedFacadeTools: connectorFreshness.expectedFacadeTools,
|
|
3072
|
-
restartRecommended: connectorFreshness.restartRecommended,
|
|
3073
|
-
reconnectRecommended: connectorFreshness.reconnectRecommended,
|
|
3074
|
-
suggestedActions: connectorFreshness.suggestedActions,
|
|
3075
|
-
},
|
|
3076
|
-
docs: [
|
|
3077
|
-
"docs/architecture/current/README.md",
|
|
3078
|
-
"docs/architecture/history.md",
|
|
3079
|
-
"docs/operations/controller-reliability-runbook.md",
|
|
3080
|
-
"docs/forge-github-issue-launcher.md",
|
|
3081
|
-
"docs/forge-chatgpt-mcp-setup.md",
|
|
3082
|
-
],
|
|
3083
|
-
staleConnectorHint: staleConnector
|
|
3084
|
-
? `Stale ChatGPT connector tool snapshot is missing facade tools: ${missingFacadeTools.join(", ")}. Refresh/reconnect MCP so tools/list reloads rh_status, rh_inbox, rh_context, and rh_work.`
|
|
3085
|
-
: connectorFreshness.status === "unable_to_verify_chatgpt_snapshot"
|
|
3086
|
-
? `Local MCP tool surface includes preferred facade tools. ChatGPT connector snapshot was not supplied, so freshness cannot be verified from this call. If ChatGPT tools/list is missing rh_status/rh_inbox/rh_context/rh_work, reconnect MCP. Pass connector_tool_names for an exact check.`
|
|
3087
|
-
: connectorFreshness.status === "stale_fingerprint"
|
|
3088
|
-
? `Local MCP process fingerprint/version may be stale. Restart controller/MCP, then reconnect ChatGPT if rh_* are still missing.`
|
|
3089
|
-
: connectorFreshness.status === "local_mcp_missing_facade"
|
|
3090
|
-
? `Local MCP tool surface is missing facade tools: ${connectorFreshness.missingLocalTools.join(", ")}. Restart controller/MCP.`
|
|
3091
|
-
: `Connector clients must match ${FORGE_TOOL_SURFACE} version ${FORGE_VERSION} / schema ${FORGE_MCP_SCHEMA_VERSION}. Prefer rh_status/rh_inbox/rh_context/rh_work. Pass connector_tool_names to detect a stale ChatGPT tool snapshot precisely.`,
|
|
3092
|
-
};
|
|
3093
|
-
audit(ctx, name, "ok", args);
|
|
3094
|
-
return textResult(payload);
|
|
3095
|
-
}
|
|
3096
|
-
case "local_bridge_status": {
|
|
3097
|
-
if (ctx.policy.profile !== "controller")
|
|
3098
|
-
return errorResult(
|
|
3099
|
-
"TOOL_DISABLED",
|
|
3100
|
-
"local_bridge_status requires the controller profile",
|
|
3101
|
-
);
|
|
3102
|
-
const detailLevel = args.detail_level === "detail" || args.detail === true
|
|
3103
|
-
? "detail"
|
|
3104
|
-
: "summary";
|
|
3105
|
-
const controllerHome = resolveRepoPreferredControllerHome(ctx.repoRoot);
|
|
3106
|
-
const surface = resolveLocalBridgeSurface({
|
|
3107
|
-
controllerHome,
|
|
3108
|
-
repoRoot: ctx.repoRoot,
|
|
3109
|
-
allowProcessScan: detailLevel === "detail",
|
|
3110
|
-
});
|
|
3111
|
-
const jobs = listLocalBridgeJobs(ctx.repoRoot, detailLevel === "detail" ? 12 : 20);
|
|
3112
|
-
const { activeJobCount, recentJobSummary } = summarizeRecentJobs(jobs);
|
|
3113
|
-
// Prefer authoritative surface; never invent a legacy 8766 endpoint.
|
|
3114
|
-
const endpoint = surface.endpoint ?? null;
|
|
3115
|
-
const running = surface.enabled
|
|
3116
|
-
&& (surface.processRunning === true
|
|
3117
|
-
|| (surface.endpointConfigured && surface.mode === "embedded"));
|
|
3118
|
-
if (detailLevel === "summary") {
|
|
3119
|
-
const payload = {
|
|
3120
|
-
detailLevel: "summary",
|
|
3121
|
-
repoId: ctx.repoId,
|
|
3122
|
-
running,
|
|
3123
|
-
ready: surface.enabled ? (surface.processRunning !== false) : true,
|
|
3124
|
-
health: surface.enabled
|
|
3125
|
-
? (surface.processRunning === true || surface.mode === "embedded" ? "ready" : "warning")
|
|
3126
|
-
: "disabled",
|
|
3127
|
-
mode: surface.mode,
|
|
3128
|
-
endpoint,
|
|
3129
|
-
endpointConfigured: surface.endpointConfigured,
|
|
3130
|
-
endpointReachable: null as boolean | null,
|
|
3131
|
-
processRunning: surface.processRunning ?? null,
|
|
3132
|
-
expectedSurface: surface.expectedSurface,
|
|
3133
|
-
requiredForReadiness: surface.requiredForReadiness,
|
|
3134
|
-
warnings: surface.error && surface.requiredForReadiness
|
|
3135
|
-
? [{ code: "LOCAL_BRIDGE_ERROR", message: surface.error.slice(0, 300) }]
|
|
3136
|
-
: [],
|
|
3137
|
-
activeJobCount,
|
|
3138
|
-
recentJobSummary,
|
|
3139
|
-
statusSource: surface.source,
|
|
3140
|
-
nonBlocking: !surface.requiredForReadiness,
|
|
3141
|
-
approvalQueue: false,
|
|
3142
|
-
};
|
|
3143
|
-
audit(ctx, name, "ok", args);
|
|
3144
|
-
return textResult(payload);
|
|
3145
|
-
}
|
|
3146
|
-
const reconciliation = reconcileLocalBridgeJobs(ctx.repoRoot);
|
|
3147
|
-
const payload = {
|
|
3148
|
-
detailLevel: "detail",
|
|
3149
|
-
endpoint,
|
|
3150
|
-
endpointConfigured: surface.endpointConfigured,
|
|
3151
|
-
running,
|
|
3152
|
-
error: surface.error,
|
|
3153
|
-
mode: surface.mode,
|
|
3154
|
-
requiredForReadiness: surface.requiredForReadiness,
|
|
3155
|
-
statusSource: surface.source,
|
|
3156
|
-
counts: recentJobSummary,
|
|
3157
|
-
activeJobCount,
|
|
3158
|
-
recentJobSummary,
|
|
3159
|
-
approvalQueue: false,
|
|
3160
|
-
reconciliation,
|
|
3161
|
-
recentJobs: jobs.map((job) => ({
|
|
3162
|
-
jobId: job.jobId,
|
|
3163
|
-
action: job.action,
|
|
3164
|
-
status: job.status,
|
|
3165
|
-
checkId: job.action === "run-check" ? (job.payload as { checkId?: string }).checkId : undefined,
|
|
3166
|
-
runId: job.runId,
|
|
3167
|
-
issueId: job.issueId,
|
|
3168
|
-
taskId: job.taskId,
|
|
3169
|
-
createdAt: job.createdAt,
|
|
3170
|
-
updatedAt: job.updatedAt,
|
|
3171
|
-
finishedAt: job.finishedAt,
|
|
3172
|
-
revision: job.revision,
|
|
3173
|
-
deadlineAt: job.deadlineAt,
|
|
3174
|
-
error: job.error?.slice(0, 300),
|
|
3175
|
-
})),
|
|
3176
|
-
nonBlocking: !surface.requiredForReadiness,
|
|
3177
|
-
fallback:
|
|
3178
|
-
"Open the localhost Local Controller to launch work or inspect execution when a ChatGPT write action is unavailable.",
|
|
3179
|
-
};
|
|
3180
|
-
audit(ctx, name, "ok", args);
|
|
3181
|
-
return textResult(payload);
|
|
3182
|
-
}
|
|
3183
|
-
case "controller_context": {
|
|
3184
|
-
if (ctx.policy.profile !== "controller")
|
|
3185
|
-
return errorResult(
|
|
3186
|
-
"TOOL_DISABLED",
|
|
3187
|
-
"controller_context requires the controller profile",
|
|
3188
|
-
);
|
|
3189
|
-
const controllerHome = resolveRepoPreferredControllerHome(ctx.repoRoot);
|
|
3190
|
-
const requirementBoard = buildRequirementBoard({ controllerHome, repoId: ctx.repoId });
|
|
3191
|
-
const executionDiagnostics = buildExecutionDiagnostics({
|
|
3192
|
-
controllerHome,
|
|
3193
|
-
repoId: ctx.repoId,
|
|
3194
|
-
detailLevel: "detail",
|
|
3195
|
-
});
|
|
3196
|
-
const runs = listAgentJobs(ctx.repoRoot, 8);
|
|
3197
|
-
const reconciliation = reconcileLocalBridgeJobs(ctx.repoRoot);
|
|
3198
|
-
const jobs = listLocalBridgeJobs(ctx.repoRoot, 8);
|
|
3199
|
-
const checks = listControllerChecks(ctx.repoRoot).map((check) => ({
|
|
3200
|
-
id: check.id,
|
|
3201
|
-
description: check.description,
|
|
3202
|
-
timeoutMs: check.timeoutMs,
|
|
3203
|
-
source: check.source,
|
|
3204
|
-
}));
|
|
3205
|
-
const assessment = assessWorkMode({
|
|
3206
|
-
description: typeof args.description === "string" && args.description.trim()
|
|
3207
|
-
? String(args.description)
|
|
3208
|
-
: "Inspect the selected repository context.",
|
|
3209
|
-
knownPaths: stringList(args.known_paths),
|
|
3210
|
-
expectedFiles: typeof args.expected_files === "number" ? args.expected_files : undefined,
|
|
3211
|
-
expectedChangedLines: typeof args.expected_changed_lines === "number" ? args.expected_changed_lines : undefined,
|
|
3212
|
-
requiresInvestigation: args.requires_investigation === true,
|
|
3213
|
-
requiresParallelism: args.requires_parallelism === true,
|
|
3214
|
-
requiresLongRunningChecks: args.requires_long_running_checks === true,
|
|
3215
|
-
needsDependencies: args.needs_dependencies === true,
|
|
3216
|
-
risk: typeof args.risk === "string" ? args.risk as TaskRisk : undefined,
|
|
3217
|
-
explicitMode: parseExplicitTaskMode(args.mode)
|
|
3218
|
-
?? (typeof args.description === "string" && args.description.trim() ? undefined : "direct"),
|
|
3219
|
-
});
|
|
3220
|
-
const modeContextPack = assessment.modeBehavior.structuralContext === "required"
|
|
3221
|
-
? buildControllerContextPack(ctx.repoRoot, ctx.policy, {
|
|
3222
|
-
description: typeof args.description === "string" ? args.description : undefined,
|
|
3223
|
-
knownPaths: stringList(args.known_paths),
|
|
3224
|
-
structuralContext: "required",
|
|
3225
|
-
maxFiles: 8,
|
|
3226
|
-
maxSnippets: 20,
|
|
3227
|
-
})
|
|
3228
|
-
: undefined;
|
|
3229
|
-
const payload = {
|
|
3230
|
-
git: gitSnapshot(ctx.repoRoot),
|
|
3231
|
-
requirementBoard,
|
|
3232
|
-
executionDiagnostics,
|
|
3233
|
-
legacyCompatibility: {
|
|
3234
|
-
currentIssue: "deprecated_frozen",
|
|
3235
|
-
issueTaskBoard: "deprecated_frozen",
|
|
3236
|
-
authority: "controller-home-sqlite",
|
|
3237
|
-
},
|
|
3238
|
-
activeRuns: runs.map((run) => ({
|
|
3239
|
-
runId: run.runId,
|
|
3240
|
-
issueId: run.issueId,
|
|
3241
|
-
taskId: run.taskId,
|
|
3242
|
-
status: run.status,
|
|
3243
|
-
agent: run.agent,
|
|
3244
|
-
provider: run.provider,
|
|
3245
|
-
executionMode: run.executionMode,
|
|
3246
|
-
progress: run.progress,
|
|
3247
|
-
lastHeartbeatAt: run.lastHeartbeatAt,
|
|
3248
|
-
error: run.error?.slice(0, 300),
|
|
3249
|
-
})),
|
|
3250
|
-
localBridge: {
|
|
3251
|
-
reconciliation,
|
|
3252
|
-
recentJobs: jobs.map((job) => ({
|
|
3253
|
-
jobId: job.jobId,
|
|
3254
|
-
action: job.action,
|
|
3255
|
-
status: job.status,
|
|
3256
|
-
checkId: job.action === "run-check" ? (job.payload as { checkId?: string }).checkId : undefined,
|
|
3257
|
-
issueId: job.issueId,
|
|
3258
|
-
taskId: job.taskId,
|
|
3259
|
-
updatedAt: job.updatedAt,
|
|
3260
|
-
})),
|
|
3261
|
-
},
|
|
3262
|
-
checks,
|
|
3263
|
-
recommendedExecution: assessment,
|
|
3264
|
-
...(modeContextPack ? { modeContextPack } : {}),
|
|
3265
|
-
};
|
|
3266
|
-
audit(ctx, name, "ok", args);
|
|
3267
|
-
return textResult(payload);
|
|
3268
|
-
}
|
|
3269
|
-
case "quick_agent_session":
|
|
3270
|
-
case "submit_local_job": {
|
|
3271
|
-
if (ctx.policy.profile !== "controller") {
|
|
3272
|
-
return errorResult("TOOL_DISABLED", `${name} requires the controller profile`);
|
|
3273
|
-
}
|
|
3274
|
-
audit(ctx, name, "blocked", args);
|
|
3275
|
-
return errorResult(
|
|
3276
|
-
name === "quick_agent_session" ? "AGENT_RUN_DEPRECATED" : "LOCAL_BRIDGE_JOB_RETIRED",
|
|
3277
|
-
"Kernel-managed Agent and Local Bridge Jobs are retired. Create or claim WorkContract and use Process Runtime or the Thin Launcher.",
|
|
3278
|
-
);
|
|
3279
|
-
}
|
|
3280
|
-
case "list_local_jobs": {
|
|
3281
|
-
if (ctx.policy.profile !== "controller")
|
|
3282
|
-
return errorResult(
|
|
3283
|
-
"TOOL_DISABLED",
|
|
3284
|
-
"list_local_jobs requires the controller profile",
|
|
3285
|
-
);
|
|
3286
|
-
const limit = typeof args.limit === "number" ? args.limit : 50;
|
|
3287
|
-
const jobs = listLocalBridgeJobs(ctx.repoRoot, limit);
|
|
3288
|
-
audit(ctx, name, "ok", args);
|
|
3289
|
-
return textResult({ jobs });
|
|
3290
|
-
}
|
|
3291
|
-
case "get_local_job": {
|
|
3292
|
-
if (ctx.policy.profile !== "controller")
|
|
3293
|
-
return errorResult(
|
|
3294
|
-
"TOOL_DISABLED",
|
|
3295
|
-
"get_local_job requires the controller profile",
|
|
3296
|
-
);
|
|
3297
|
-
const jobId = String(args.job_id ?? "").trim();
|
|
3298
|
-
const includeEvents = args.include_events === true;
|
|
3299
|
-
const includeOutput = args.include_output === true;
|
|
3300
|
-
const snapshot = getLocalBridgeJobSnapshot(ctx.repoRoot, jobId);
|
|
3301
|
-
const payload = {
|
|
3302
|
-
job: snapshot.job,
|
|
3303
|
-
...(snapshot.status !== "ok" ? { lookup: snapshot } : {}),
|
|
3304
|
-
...(includeEvents && snapshot.status === "ok" ? { events: getLocalBridgeJobEvents(ctx.repoRoot, jobId) } : {}),
|
|
3305
|
-
...(includeOutput
|
|
3306
|
-
? {
|
|
3307
|
-
output: readLocalBridgeJobOutput(ctx.repoRoot, jobId, {
|
|
3308
|
-
stream: args.stream === "stderr" ? "stderr" : "stdout",
|
|
3309
|
-
maxBytes: typeof args.max_bytes === "number" ? args.max_bytes : undefined,
|
|
3310
|
-
}),
|
|
3311
|
-
}
|
|
3312
|
-
: {}),
|
|
3313
|
-
};
|
|
3314
|
-
audit(ctx, name, "ok", args);
|
|
3315
|
-
return textResult(payload);
|
|
3316
|
-
}
|
|
3317
|
-
case "get_local_job_output": {
|
|
3318
|
-
if (ctx.policy.profile !== "controller")
|
|
3319
|
-
return errorResult(
|
|
3320
|
-
"TOOL_DISABLED",
|
|
3321
|
-
"get_local_job_output requires the controller profile",
|
|
3322
|
-
);
|
|
3323
|
-
const jobId = String(args.job_id ?? "").trim();
|
|
3324
|
-
const payload = readLocalBridgeJobOutput(ctx.repoRoot, jobId, {
|
|
3325
|
-
stream: args.stream === "stderr" ? "stderr" : "stdout",
|
|
3326
|
-
maxBytes: typeof args.max_bytes === "number" ? args.max_bytes : undefined,
|
|
3327
|
-
});
|
|
3328
|
-
audit(ctx, name, "ok", args);
|
|
3329
|
-
return textResult(payload);
|
|
3330
|
-
}
|
|
3331
|
-
case "project_snapshot": {
|
|
3332
|
-
if (ctx.policy.profile !== "controller") return errorResult("TOOL_DISABLED", "project_snapshot requires the controller profile");
|
|
3333
|
-
const markerPaths = [
|
|
3334
|
-
".ai/harness/active-plan",
|
|
3335
|
-
".ai/harness/active-sprint",
|
|
3336
|
-
".ai/harness/active-worktree",
|
|
3337
|
-
"tasks/current.md",
|
|
3338
|
-
];
|
|
3339
|
-
const markers = markerPaths.map((path) => {
|
|
3340
|
-
const absolute = join(ctx.repoRoot, path);
|
|
3341
|
-
if (!existsSync(absolute)) return { path, exists: false };
|
|
3342
|
-
const raw = readFileSync(absolute, "utf-8");
|
|
3343
|
-
return {
|
|
3344
|
-
path,
|
|
3345
|
-
exists: true,
|
|
3346
|
-
bytes: Buffer.byteLength(raw),
|
|
3347
|
-
lines: raw.split(/\r?\n/).length,
|
|
3348
|
-
sha256: createHash("sha256").update(raw).digest("hex").slice(0, 16),
|
|
3349
|
-
preview: redactMcpText(raw).text.slice(0, 400),
|
|
3350
|
-
};
|
|
3351
|
-
});
|
|
3352
|
-
const controllerHome = resolveRepoPreferredControllerHome(ctx.repoRoot);
|
|
3353
|
-
const requirementBoard = buildRequirementBoard({ controllerHome, repoId: ctx.repoId });
|
|
3354
|
-
const executionDiagnostics = buildExecutionDiagnostics({
|
|
3355
|
-
controllerHome,
|
|
3356
|
-
repoId: ctx.repoId,
|
|
3357
|
-
detailLevel: "detail",
|
|
3358
|
-
});
|
|
3359
|
-
const snapshotRuns = listAgentJobs(ctx.repoRoot, 11);
|
|
3360
|
-
const runs = snapshotRuns.slice(0, 10).map((run) => ({
|
|
3361
|
-
runId: run.runId,
|
|
3362
|
-
issueId: run.issueId,
|
|
3363
|
-
taskId: run.taskId,
|
|
3364
|
-
agent: run.agent,
|
|
3365
|
-
provider: run.provider,
|
|
3366
|
-
executionMode: run.executionMode,
|
|
3367
|
-
status: run.status,
|
|
3368
|
-
progress: run.progress,
|
|
3369
|
-
createdAt: run.createdAt,
|
|
3370
|
-
finishedAt: run.finishedAt,
|
|
3371
|
-
error: run.error?.slice(0, 300),
|
|
3372
|
-
}));
|
|
3373
|
-
const payload = {
|
|
3374
|
-
git: gitSnapshot(ctx.repoRoot),
|
|
3375
|
-
requirementBoard,
|
|
3376
|
-
executionDiagnostics,
|
|
3377
|
-
legacyCompatibility: {
|
|
3378
|
-
currentIssue: "deprecated_frozen",
|
|
3379
|
-
issueTaskBoard: "deprecated_frozen",
|
|
3380
|
-
authority: "controller-home-sqlite",
|
|
3381
|
-
},
|
|
3382
|
-
runs,
|
|
3383
|
-
markers,
|
|
3384
|
-
truncated: {
|
|
3385
|
-
runs: snapshotRuns.length > 10,
|
|
3386
|
-
},
|
|
3387
|
-
};
|
|
3388
|
-
audit(ctx, name, "ok", args);
|
|
3389
|
-
return textResult(payload);
|
|
3390
|
-
}
|
|
3391
|
-
case "search_repository": {
|
|
3392
|
-
if (ctx.policy.profile !== "controller")
|
|
3393
|
-
return errorResult(
|
|
3394
|
-
"TOOL_DISABLED",
|
|
3395
|
-
"search_repository requires the controller profile",
|
|
3396
|
-
);
|
|
3397
|
-
const session = ctx.sessionId && ctx.repoId
|
|
3398
|
-
? {
|
|
3399
|
-
sessionId: ctx.sessionId,
|
|
3400
|
-
repoId: ctx.repoId,
|
|
3401
|
-
checkoutId: ctx.checkoutId ?? ctx.repoId,
|
|
3402
|
-
}
|
|
3403
|
-
: undefined;
|
|
3404
|
-
const result = searchRepository(ctx.repoRoot, ctx.policy, {
|
|
3405
|
-
query: String(args.query ?? ""),
|
|
3406
|
-
includeGlobs: stringList(args.include_globs),
|
|
3407
|
-
excludeGlobs: stringList(args.exclude_globs),
|
|
3408
|
-
maxResults:
|
|
3409
|
-
typeof args.max_results === "number" ? args.max_results : undefined,
|
|
3410
|
-
maxFiles:
|
|
3411
|
-
typeof args.max_files === "number" ? args.max_files : undefined,
|
|
3412
|
-
caseSensitive: args.case_sensitive === true,
|
|
3413
|
-
session,
|
|
3414
|
-
});
|
|
3415
|
-
audit(ctx, name, "ok", args);
|
|
3416
|
-
return textResult(result);
|
|
3417
|
-
}
|
|
3418
|
-
case "get_git_diff": {
|
|
3419
|
-
if (ctx.policy.profile !== "controller")
|
|
3420
|
-
return errorResult(
|
|
3421
|
-
"TOOL_DISABLED",
|
|
3422
|
-
"get_git_diff requires the controller profile",
|
|
3423
|
-
);
|
|
3424
|
-
const path =
|
|
3425
|
-
typeof args.path === "string" && args.path.trim()
|
|
3426
|
-
? args.path.trim()
|
|
3427
|
-
: undefined;
|
|
3428
|
-
if (path) {
|
|
3429
|
-
const decision = resolveMcpPath(
|
|
3430
|
-
ctx.repoRoot,
|
|
3431
|
-
path,
|
|
3432
|
-
ctx.policy,
|
|
3433
|
-
"read",
|
|
3434
|
-
);
|
|
3435
|
-
if (!decision.ok)
|
|
3436
|
-
return errorResult(
|
|
3437
|
-
"POLICY_DENIED",
|
|
3438
|
-
decision.reason ?? "path denied",
|
|
3439
|
-
{ path },
|
|
3440
|
-
);
|
|
3441
|
-
}
|
|
3442
|
-
const maxBytes =
|
|
3443
|
-
typeof args.max_bytes === "number"
|
|
3444
|
-
? Math.min(Math.max(Math.trunc(args.max_bytes), 1024), 512 * 1024)
|
|
3445
|
-
: 128 * 1024;
|
|
3446
|
-
const result = gitDiff(ctx.repoRoot, path, maxBytes);
|
|
3447
|
-
const redacted = redactMcpText(result.diff);
|
|
3448
|
-
audit(ctx, name, "ok", args, path);
|
|
3449
|
-
return textResult({
|
|
3450
|
-
...result,
|
|
3451
|
-
diff: redacted.text,
|
|
3452
|
-
redactions: redacted.redactions,
|
|
3453
|
-
});
|
|
3454
|
-
}
|
|
3455
|
-
case "list_checks": {
|
|
3456
|
-
if (ctx.policy.profile !== "controller")
|
|
3457
|
-
return errorResult(
|
|
3458
|
-
"TOOL_DISABLED",
|
|
3459
|
-
"list_checks requires the controller profile",
|
|
3460
|
-
);
|
|
3461
|
-
const checks = listControllerChecks(ctx.repoRoot);
|
|
3462
|
-
audit(ctx, name, "ok", args);
|
|
3463
|
-
return textResult({ checks });
|
|
3464
|
-
}
|
|
3465
|
-
case "list_issues": {
|
|
3466
|
-
if (ctx.policy.profile !== "controller")
|
|
3467
|
-
return errorResult(
|
|
3468
|
-
"TOOL_DISABLED",
|
|
3469
|
-
"list_issues requires the controller profile",
|
|
3470
|
-
);
|
|
3471
|
-
const projectState = loadControllerProjectState(ctx.repoRoot);
|
|
3472
|
-
const issues = listIssueEffectiveViews(ctx.repoRoot).map((issue) => {
|
|
3473
|
-
const readiness = inspectIssueReadiness(ctx.repoRoot, issue.id);
|
|
3474
|
-
return {
|
|
3475
|
-
id: issue.id,
|
|
3476
|
-
title: issue.title,
|
|
3477
|
-
kind: issue.kind,
|
|
3478
|
-
status: issue.status,
|
|
3479
|
-
lifecycleStatus: issue.lifecycleStatus,
|
|
3480
|
-
archivedAt: issue.archivedAt,
|
|
3481
|
-
isCurrent: projectState.currentIssueId === issue.id,
|
|
3482
|
-
updatedAt: issue.updatedAt,
|
|
3483
|
-
taskCount: issue.tasks.length,
|
|
3484
|
-
taskCounts: issue.tasks.reduce<Record<string, number>>((counts, task) => {
|
|
3485
|
-
counts[task.effectiveStatus] = (counts[task.effectiveStatus] ?? 0) + 1;
|
|
3486
|
-
return counts;
|
|
3487
|
-
}, {}),
|
|
3488
|
-
declaredTaskCounts: issue.tasks.reduce<Record<string, number>>((counts, task) => {
|
|
3489
|
-
counts[task.declaredStatus] = (counts[task.declaredStatus] ?? 0) + 1;
|
|
3490
|
-
return counts;
|
|
3491
|
-
}, {}),
|
|
3492
|
-
readyTaskIds: readiness.readyTaskIds,
|
|
3493
|
-
queueableTaskIds: readiness.queueableTaskIds,
|
|
3494
|
-
approvalPendingTaskIds: readiness.approvalPendingTaskIds,
|
|
3495
|
-
};
|
|
3496
|
-
});
|
|
3497
|
-
audit(ctx, name, "ok", args);
|
|
3498
|
-
return textResult({ issues });
|
|
3499
|
-
}
|
|
3500
|
-
case "get_project_board": {
|
|
3501
|
-
if (ctx.policy.profile !== "controller")
|
|
3502
|
-
return errorResult(
|
|
3503
|
-
"TOOL_DISABLED",
|
|
3504
|
-
"get_project_board requires the controller profile",
|
|
3505
|
-
);
|
|
3506
|
-
const startedAt = performance.now();
|
|
3507
|
-
const controllerHome = resolveRepoPreferredControllerHome(ctx.repoRoot);
|
|
3508
|
-
const detailLevel = args.detail_level === "full" ? "full" : args.detail_level === "detail" ? "detail" : "summary";
|
|
3509
|
-
const payload = detailLevel === "summary"
|
|
3510
|
-
? buildRequirementBoard({ controllerHome, repoId: ctx.repoId })
|
|
3511
|
-
: buildExecutionDiagnostics({
|
|
3512
|
-
controllerHome,
|
|
3513
|
-
repoId: ctx.repoId,
|
|
3514
|
-
detailLevel,
|
|
3515
|
-
requirementId: typeof args.requirement_id === "string" ? args.requirement_id : undefined,
|
|
3516
|
-
});
|
|
3517
|
-
audit(ctx, name, "ok", args);
|
|
3518
|
-
const response = {
|
|
3519
|
-
...payload,
|
|
3520
|
-
responseMeta: {
|
|
3521
|
-
serverDurationMs: Number((performance.now() - startedAt).toFixed(2)),
|
|
3522
|
-
structuredPayloadBytes: 0,
|
|
3523
|
-
},
|
|
3524
|
-
};
|
|
3525
|
-
response.responseMeta.structuredPayloadBytes = Buffer.byteLength(JSON.stringify(response), "utf8");
|
|
3526
|
-
return textResult(response);
|
|
3527
|
-
}
|
|
3528
|
-
case "get_project_progress": {
|
|
3529
|
-
if (ctx.policy.profile !== "controller")
|
|
3530
|
-
return errorResult("TOOL_DISABLED", "get_project_progress requires the controller profile");
|
|
3531
|
-
const progress = getProjectProgress(ctx.repoRoot);
|
|
3532
|
-
audit(ctx, name, "ok", args);
|
|
3533
|
-
return textResult(progress);
|
|
3534
|
-
}
|
|
3535
|
-
case "get_project_governance": {
|
|
3536
|
-
if (ctx.policy.profile !== "controller")
|
|
3537
|
-
return errorResult("TOOL_DISABLED", "get_project_governance requires the controller profile");
|
|
3538
|
-
const governance = inspectProjectGovernance(ctx.repoRoot);
|
|
3539
|
-
audit(ctx, name, "ok", args);
|
|
3540
|
-
return textResult(governance);
|
|
3541
|
-
}
|
|
3542
|
-
case "reconcile_project_governance": {
|
|
3543
|
-
if (ctx.policy.profile !== "controller")
|
|
3544
|
-
return errorResult("TOOL_DISABLED", "reconcile_project_governance requires the controller profile");
|
|
3545
|
-
const result = reconcileProjectGovernance(ctx.repoRoot);
|
|
3546
|
-
audit(ctx, name, "ok", args, ".ai/harness/controller/project-state.json");
|
|
3547
|
-
return textResult(result);
|
|
3548
|
-
}
|
|
3549
|
-
case "get_project_state": {
|
|
3550
|
-
if (ctx.policy.profile !== "controller")
|
|
3551
|
-
return errorResult("TOOL_DISABLED", "get_project_state requires the controller profile");
|
|
3552
|
-
const state = loadControllerProjectState(ctx.repoRoot);
|
|
3553
|
-
audit(ctx, name, "ok", args);
|
|
3554
|
-
return textResult(state);
|
|
3555
|
-
}
|
|
3556
|
-
case "set_current_issue": {
|
|
3557
|
-
if (ctx.policy.profile !== "controller")
|
|
3558
|
-
return errorResult("TOOL_DISABLED", "set_current_issue requires the controller profile");
|
|
3559
|
-
const issue = getIssue(ctx.repoRoot, String(args.issue_id ?? ""));
|
|
3560
|
-
if (issue.archivedAt || ["done", "cancelled"].includes(issue.status))
|
|
3561
|
-
return errorResult("ISSUE_NOT_ACTIVE", `only an active, non-archived Issue can be selected (current: ${issue.status})`);
|
|
3562
|
-
const state = saveControllerProjectState(ctx.repoRoot, { currentIssueId: issue.id }, "chatgpt-controller");
|
|
3563
|
-
audit(ctx, name, "ok", args, ".ai/harness/controller/project-state.json");
|
|
3564
|
-
return textResult(state);
|
|
3565
|
-
}
|
|
3566
|
-
case "archive_issue": {
|
|
3567
|
-
if (ctx.policy.profile !== "controller")
|
|
3568
|
-
return errorResult("TOOL_DISABLED", "archive_issue requires the controller profile");
|
|
3569
|
-
const issue = archiveIssue(ctx.repoRoot, String(args.issue_id ?? ""));
|
|
3570
|
-
audit(ctx, name, "ok", args, `tasks/issues/${issue.id}`);
|
|
3571
|
-
return textResult(projectIssueEffectiveView(ctx.repoRoot, issue));
|
|
3572
|
-
}
|
|
3573
|
-
case "restore_issue": {
|
|
3574
|
-
if (ctx.policy.profile !== "controller")
|
|
3575
|
-
return errorResult("TOOL_DISABLED", "restore_issue requires the controller profile");
|
|
3576
|
-
const issue = restoreIssue(ctx.repoRoot, String(args.issue_id ?? ""));
|
|
3577
|
-
audit(ctx, name, "ok", args, `tasks/issues/${issue.id}`);
|
|
3578
|
-
return textResult(projectIssueEffectiveView(ctx.repoRoot, issue));
|
|
3579
|
-
}
|
|
3580
|
-
case "get_task_progress_detail": {
|
|
3581
|
-
if (ctx.policy.profile !== "controller")
|
|
3582
|
-
return errorResult("TOOL_DISABLED", "get_task_progress_detail requires the controller profile");
|
|
3583
|
-
const result = getTaskProgressReadView(
|
|
3584
|
-
ctx.repoRoot,
|
|
3585
|
-
String(args.issue_id ?? ""),
|
|
3586
|
-
String(args.task_id ?? ""),
|
|
3587
|
-
args.detail_level === "full" ? "full" : "summary",
|
|
3588
|
-
);
|
|
3589
|
-
audit(ctx, name, "ok", args, `tasks/issues/${result.issue.id}`);
|
|
3590
|
-
return textResult(result);
|
|
3591
|
-
}
|
|
3592
|
-
case "get_worklog_timeline": {
|
|
3593
|
-
if (ctx.policy.profile !== "controller")
|
|
3594
|
-
return errorResult("TOOL_DISABLED", "get_worklog_timeline requires the controller profile");
|
|
3595
|
-
const events = getControllerTimeline(ctx.repoRoot, {
|
|
3596
|
-
category: parseWorklogCategory(args.category),
|
|
3597
|
-
issueId: typeof args.issue_id === "string" ? args.issue_id : undefined,
|
|
3598
|
-
taskId: typeof args.task_id === "string" ? args.task_id : undefined,
|
|
3599
|
-
runId: typeof args.run_id === "string" ? args.run_id : undefined,
|
|
3600
|
-
editSessionId: typeof args.edit_session_id === "string" ? args.edit_session_id : undefined,
|
|
3601
|
-
since: typeof args.since === "string" ? args.since : undefined,
|
|
3602
|
-
until: typeof args.until === "string" ? args.until : undefined,
|
|
3603
|
-
limit: typeof args.limit === "number" ? Math.trunc(args.limit) : undefined,
|
|
3604
|
-
});
|
|
3605
|
-
audit(ctx, name, "ok", args);
|
|
3606
|
-
return textResult({ events });
|
|
3607
|
-
}
|
|
3608
|
-
case "export_worklog": {
|
|
3609
|
-
if (ctx.policy.profile !== "controller")
|
|
3610
|
-
return errorResult("TOOL_DISABLED", "export_worklog requires the controller profile");
|
|
3611
|
-
const result = exportControllerWorklog(ctx.repoRoot, {
|
|
3612
|
-
format: args.format === "json" ? "json" : "markdown",
|
|
3613
|
-
outputPath: typeof args.output_path === "string" ? args.output_path : undefined,
|
|
3614
|
-
filter: {
|
|
3615
|
-
issueId: typeof args.issue_id === "string" ? args.issue_id : undefined,
|
|
3616
|
-
taskId: typeof args.task_id === "string" ? args.task_id : undefined,
|
|
3617
|
-
runId: typeof args.run_id === "string" ? args.run_id : undefined,
|
|
3618
|
-
editSessionId: typeof args.edit_session_id === "string" ? args.edit_session_id : undefined,
|
|
3619
|
-
},
|
|
3620
|
-
});
|
|
3621
|
-
audit(ctx, name, "ok", args, result.path);
|
|
3622
|
-
return textResult(result);
|
|
3623
|
-
}
|
|
3624
|
-
case "get_github_plugin_status": {
|
|
3625
|
-
if (ctx.policy.profile !== "controller")
|
|
3626
|
-
return errorResult("TOOL_DISABLED", "get_github_plugin_status requires the controller profile");
|
|
3627
|
-
const status = getGitHubPluginStatus(ctx.repoRoot);
|
|
3628
|
-
audit(ctx, name, "ok", args, status.repository);
|
|
3629
|
-
return textResult(status);
|
|
3630
|
-
}
|
|
3631
|
-
case "configure_github_plugin": {
|
|
3632
|
-
if (ctx.policy.profile !== "controller")
|
|
3633
|
-
return errorResult("TOOL_DISABLED", "configure_github_plugin requires the controller profile");
|
|
3634
|
-
const config = saveGitHubPluginConfig(ctx.repoRoot, {
|
|
3635
|
-
enabled: typeof args.enabled === "boolean" ? args.enabled : undefined,
|
|
3636
|
-
repository: args.clear_repository === true ? "" : typeof args.repository === "string" ? args.repository : undefined,
|
|
3637
|
-
syncMode: args.sync_mode === "checkpoint" ? "checkpoint" : args.sync_mode === "manual" ? "manual" : undefined,
|
|
3638
|
-
includeTasks: typeof args.include_tasks === "boolean" ? args.include_tasks : undefined,
|
|
3639
|
-
projectOwner: args.clear_project === true ? "" : typeof args.project_owner === "string" ? args.project_owner : undefined,
|
|
3640
|
-
projectNumber: args.clear_project === true ? null : typeof args.project_number === "number" ? args.project_number : undefined,
|
|
1489
|
+
"plans",
|
|
1490
|
+
"tasks/current.md",
|
|
1491
|
+
".ai/harness/session",
|
|
1492
|
+
".ai/harness/controller/packets",
|
|
1493
|
+
".ai/harness/projections",
|
|
1494
|
+
".ai/harness/checks",
|
|
1495
|
+
];
|
|
1496
|
+
audit(ctx, name, "ok", args);
|
|
1497
|
+
return textResult({
|
|
1498
|
+
repoRoot: ctx.repoRoot,
|
|
1499
|
+
adopted: isForgeAdopted(ctx.repoRoot),
|
|
1500
|
+
profile: ctx.policy.profile,
|
|
1501
|
+
branch: currentGitBranch(ctx.repoRoot),
|
|
1502
|
+
workflowRoots: roots.map((path) => ({
|
|
1503
|
+
path,
|
|
1504
|
+
exists: existsSync(join(ctx.repoRoot, path)),
|
|
1505
|
+
})),
|
|
3641
1506
|
});
|
|
3642
|
-
audit(ctx, name, "ok", args, "repository-registry:github");
|
|
3643
|
-
return textResult(config);
|
|
3644
|
-
}
|
|
3645
|
-
case "get_issue": {
|
|
3646
|
-
if (ctx.policy.profile !== "controller")
|
|
3647
|
-
return errorResult(
|
|
3648
|
-
"TOOL_DISABLED",
|
|
3649
|
-
"get_issue requires the controller profile",
|
|
3650
|
-
);
|
|
3651
|
-
const issue = getIssueReadView(
|
|
3652
|
-
ctx.repoRoot,
|
|
3653
|
-
String(args.issue_id ?? ""),
|
|
3654
|
-
args.detail_level === "full" ? "full" : "summary",
|
|
3655
|
-
);
|
|
3656
|
-
audit(ctx, name, "ok", args, `tasks/issues/${issue.id}`);
|
|
3657
|
-
return textResult(issue);
|
|
3658
|
-
}
|
|
3659
|
-
case "github_status": {
|
|
3660
|
-
if (ctx.policy.profile !== "controller")
|
|
3661
|
-
return errorResult(
|
|
3662
|
-
"TOOL_DISABLED",
|
|
3663
|
-
"github_status requires the controller profile",
|
|
3664
|
-
);
|
|
3665
|
-
const status = getGitHubStatus(
|
|
3666
|
-
ctx.repoRoot,
|
|
3667
|
-
typeof args.repo === "string" ? args.repo : undefined,
|
|
3668
|
-
);
|
|
3669
|
-
audit(
|
|
3670
|
-
ctx,
|
|
3671
|
-
name,
|
|
3672
|
-
status.available && status.authenticated ? "ok" : "failed",
|
|
3673
|
-
args,
|
|
3674
|
-
status.repository?.nameWithOwner,
|
|
3675
|
-
status.errors.join("; "),
|
|
3676
|
-
);
|
|
3677
|
-
return textResult(status);
|
|
3678
1507
|
}
|
|
3679
|
-
case "
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
"TOOL_DISABLED",
|
|
3683
|
-
"publish_issue_to_github requires the controller profile",
|
|
3684
|
-
);
|
|
3685
|
-
const issue = publishIssueToGitHub(
|
|
3686
|
-
ctx.repoRoot,
|
|
3687
|
-
String(args.issue_id ?? ""),
|
|
3688
|
-
{
|
|
3689
|
-
repo: typeof args.repo === "string" ? args.repo : undefined,
|
|
3690
|
-
labels: stringList(args.labels),
|
|
3691
|
-
includeTasks: args.include_tasks === true,
|
|
3692
|
-
projectOwner:
|
|
3693
|
-
typeof args.project_owner === "string"
|
|
3694
|
-
? args.project_owner
|
|
3695
|
-
: undefined,
|
|
3696
|
-
projectNumber:
|
|
3697
|
-
typeof args.project_number === "number"
|
|
3698
|
-
? Math.trunc(args.project_number)
|
|
3699
|
-
: undefined,
|
|
3700
|
-
},
|
|
1508
|
+
case "harness_doctor": {
|
|
1509
|
+
const localConfig = existsSync(
|
|
1510
|
+
join(ctx.repoRoot, ".forge", "mcp.local.json"),
|
|
3701
1511
|
);
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
}
|
|
3705
|
-
case "refresh_github_issue": {
|
|
3706
|
-
if (ctx.policy.profile !== "controller")
|
|
3707
|
-
return errorResult(
|
|
3708
|
-
"TOOL_DISABLED",
|
|
3709
|
-
"refresh_github_issue requires the controller profile",
|
|
3710
|
-
);
|
|
3711
|
-
const result = refreshGitHubIssue(
|
|
3712
|
-
ctx.repoRoot,
|
|
3713
|
-
String(args.issue_id ?? ""),
|
|
1512
|
+
const codexConfig = existsSync(
|
|
1513
|
+
join(ctx.repoRoot, ".codex", "config.toml"),
|
|
3714
1514
|
);
|
|
3715
|
-
audit(ctx, name, "ok", args
|
|
1515
|
+
audit(ctx, name, "ok", args);
|
|
3716
1516
|
return textResult({
|
|
3717
|
-
|
|
3718
|
-
|
|
1517
|
+
status: isForgeAdopted(ctx.repoRoot)
|
|
1518
|
+
? "ready_local"
|
|
1519
|
+
: "not_adopted",
|
|
1520
|
+
repo: ctx.repoRoot,
|
|
1521
|
+
profile: ctx.policy.profile,
|
|
1522
|
+
mcp: {
|
|
1523
|
+
localConfig,
|
|
1524
|
+
policy: "builtin",
|
|
1525
|
+
profile: ctx.policy.profile,
|
|
1526
|
+
toolSurface:
|
|
1527
|
+
ctx.policy.profile === "controller"
|
|
1528
|
+
? FORGE_TOOL_SURFACE
|
|
1529
|
+
: `${ctx.policy.profile}-legacy-v1`,
|
|
1530
|
+
toolCount: buildMcpToolDefinitions(ctx.policy, {
|
|
1531
|
+
enableChatgptBrowser: ctx.enableChatgptBrowser === true,
|
|
1532
|
+
}).length,
|
|
1533
|
+
repositoryRead:
|
|
1534
|
+
ctx.policy.profile === "controller"
|
|
1535
|
+
? "ordinary repository source and document files are readable; immutable secret and runtime paths remain denied"
|
|
1536
|
+
: "workflow-scoped",
|
|
1537
|
+
deniedPaths: ctx.policy.denyGlobs.length,
|
|
1538
|
+
runner: {
|
|
1539
|
+
enabled: ctx.policy.execution.agentRunner,
|
|
1540
|
+
defaultTimeoutMs: ctx.policy.execution.runnerTimeoutMs,
|
|
1541
|
+
maxTimeoutMs: ctx.policy.execution.runnerMaxTimeoutMs,
|
|
1542
|
+
},
|
|
1543
|
+
},
|
|
1544
|
+
codex: {
|
|
1545
|
+
configured: codexConfig,
|
|
1546
|
+
fix: codexConfig
|
|
1547
|
+
? null
|
|
1548
|
+
: "forge mcp setup codex --repo . --scope project",
|
|
1549
|
+
},
|
|
1550
|
+
chatgpt: {
|
|
1551
|
+
localEndpoint: "http://127.0.0.1:8765/mcp",
|
|
1552
|
+
manualStepsRequired: true,
|
|
1553
|
+
guide: "docs/forge-chatgpt-mcp-setup.md",
|
|
1554
|
+
},
|
|
3719
1555
|
});
|
|
3720
1556
|
}
|
|
3721
|
-
case "
|
|
3722
|
-
if (ctx.policy.profile !== "controller")
|
|
3723
|
-
return errorResult(
|
|
3724
|
-
"TOOL_DISABLED",
|
|
3725
|
-
"close_github_issue requires the controller profile",
|
|
3726
|
-
);
|
|
3727
|
-
const issue = closeGitHubIssue(
|
|
3728
|
-
ctx.repoRoot,
|
|
3729
|
-
String(args.issue_id ?? ""),
|
|
3730
|
-
);
|
|
3731
|
-
audit(ctx, name, "ok", args, issue.github?.url);
|
|
3732
|
-
return textResult(projectIssueEffectiveView(ctx.repoRoot, issue));
|
|
3733
|
-
}
|
|
3734
|
-
case "inspect_issue_readiness": {
|
|
1557
|
+
case "controller_capabilities": {
|
|
3735
1558
|
if (ctx.policy.profile !== "controller")
|
|
3736
1559
|
return errorResult(
|
|
3737
1560
|
"TOOL_DISABLED",
|
|
3738
|
-
"
|
|
1561
|
+
"controller_capabilities requires the controller profile",
|
|
3739
1562
|
);
|
|
3740
|
-
const
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
audit(
|
|
3745
|
-
ctx,
|
|
3746
|
-
name,
|
|
3747
|
-
readiness.ready ? "ok" : "blocked",
|
|
3748
|
-
args,
|
|
3749
|
-
`tasks/issues/${readiness.issueId}`,
|
|
3750
|
-
[...readiness.blockers, ...readiness.taskBlockers].map((item) => item.message).join("; "),
|
|
1563
|
+
const expectedTools = ctx.publishedToolNames;
|
|
1564
|
+
if (!expectedTools) return errorResult(
|
|
1565
|
+
'MCP_TOOL_SURFACE_UNAVAILABLE',
|
|
1566
|
+
'Controller capability diagnostics require the authoritative MCP registry projection.',
|
|
3751
1567
|
);
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
1568
|
+
const preferredTools: string[] = [...PREFERRED_FACADE_TOOL_NAMES];
|
|
1569
|
+
const capabilityDescriptors = listCapabilityDescriptors();
|
|
1570
|
+
const connectorSnapshot = Array.isArray(args.connector_tool_names)
|
|
1571
|
+
? args.connector_tool_names.map(String)
|
|
1572
|
+
: Array.isArray(args.connectorToolNames)
|
|
1573
|
+
? args.connectorToolNames.map(String)
|
|
1574
|
+
: undefined;
|
|
1575
|
+
const connectorFreshness = await buildLocalConnectorStatusForRepo({
|
|
1576
|
+
repoRoot: ctx.repoRoot,
|
|
1577
|
+
expectedTools,
|
|
1578
|
+
connectorToolNames: connectorSnapshot,
|
|
1579
|
+
});
|
|
1580
|
+
// staleConnector only when ChatGPT snapshot is supplied and missing rh_*.
|
|
1581
|
+
const missingFacadeTools = connectorFreshness.missingConnectorTools;
|
|
1582
|
+
const staleConnector = connectorFreshness.status === "chatgpt_snapshot_missing_facade";
|
|
1583
|
+
const payload = {
|
|
1584
|
+
schemaVersion: FORGE_MCP_SCHEMA_VERSION,
|
|
1585
|
+
toolSurface: FORGE_TOOL_SURFACE,
|
|
1586
|
+
version: FORGE_VERSION,
|
|
1587
|
+
toolSurfaceFingerprint: forgeToolSurfaceFingerprint(expectedTools),
|
|
1588
|
+
executionModel: "chatgpt-controller-execution-bridge",
|
|
1589
|
+
profile: ctx.policy.profile,
|
|
1590
|
+
capabilities: {
|
|
1591
|
+
repositoryInspection: true,
|
|
1592
|
+
issueLauncher: true,
|
|
1593
|
+
githubIssuesAndProjects: true,
|
|
1594
|
+
localAgentRuns: ctx.policy.execution.agentRunner,
|
|
1595
|
+
githubCopilotSessions: true,
|
|
1596
|
+
dynamicTaskGraph: true,
|
|
1597
|
+
runtimeAgentSelection: true,
|
|
1598
|
+
taskAgentBinding: false,
|
|
1599
|
+
structuredRunEvents: true,
|
|
1600
|
+
boundedDirectEdits: true,
|
|
1601
|
+
multiRevisionDirectEdits: true,
|
|
1602
|
+
editSavepoints: true,
|
|
1603
|
+
partialEditRollback: true,
|
|
1604
|
+
directEditFirstRouting: true,
|
|
1605
|
+
persistedEditDiffs: true,
|
|
1606
|
+
verifiedEditFinalization: true,
|
|
1607
|
+
verificationGate: true,
|
|
1608
|
+
localRunWatch: true,
|
|
1609
|
+
localVisualController: true,
|
|
1610
|
+
hierarchicalControllerUI: true,
|
|
1611
|
+
localApprovalQueue: false,
|
|
1612
|
+
localRiskApprovalGate: false,
|
|
1613
|
+
quickAgentSessions: true,
|
|
1614
|
+
persistentTimeouts: true,
|
|
1615
|
+
timeoutProgress: true,
|
|
1616
|
+
connectorSchemaDiagnostics: true,
|
|
1617
|
+
projectProgressAggregation: true,
|
|
1618
|
+
effectiveTaskStatus: true,
|
|
1619
|
+
unifiedWorklogTimeline: true,
|
|
1620
|
+
exportableWorklogReports: true,
|
|
1621
|
+
githubPluginConfiguration: true,
|
|
1622
|
+
serverSentEventDashboard: true,
|
|
1623
|
+
singleExecutionFocus: false,
|
|
1624
|
+
taskLocalReadiness: true,
|
|
1625
|
+
riskAdaptiveVerification: true,
|
|
1626
|
+
ephemeralQuickAgentSessions: true,
|
|
1627
|
+
automaticRunContinuation: true,
|
|
1628
|
+
reportedCommandEvidence: true,
|
|
1629
|
+
governanceDiagnostics: true,
|
|
1630
|
+
safeGovernanceReconciliation: true,
|
|
1631
|
+
evidenceGateProgress: true,
|
|
1632
|
+
directTaskActions: true,
|
|
1633
|
+
issueArchiving: true,
|
|
1634
|
+
retryableRunFailures: true,
|
|
1635
|
+
issueCreationGuardrails: true,
|
|
1636
|
+
persistedCheckEvidence: true,
|
|
1637
|
+
persistedCheckReuse: true,
|
|
1638
|
+
directVerification: true,
|
|
1639
|
+
controllerContextAggregation: true,
|
|
1640
|
+
taskLedgerProjection: true,
|
|
1641
|
+
assistantPluginRuntime: true,
|
|
1642
|
+
chatgptFacadeTools: true,
|
|
1643
|
+
goalWorkloop: true,
|
|
1644
|
+
handoffInbox: true,
|
|
1645
|
+
codexGrokDelegation: true,
|
|
1646
|
+
selfHealingRepair: true,
|
|
3767
1647
|
},
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
issue: {
|
|
3811
|
-
id: issue.id,
|
|
3812
|
-
title: issue.title,
|
|
3813
|
-
status: issue.status,
|
|
3814
|
-
github: issue.github,
|
|
1648
|
+
runner: {
|
|
1649
|
+
enabled: ctx.policy.execution.agentRunner,
|
|
1650
|
+
allowedAgents: ctx.policy.execution.allowedAgents,
|
|
1651
|
+
defaultTimeoutMs: ctx.policy.execution.runnerTimeoutMs,
|
|
1652
|
+
defaultTimeout: formatDurationMs(
|
|
1653
|
+
ctx.policy.execution.runnerTimeoutMs,
|
|
1654
|
+
),
|
|
1655
|
+
maxTimeoutMs: ctx.policy.execution.runnerMaxTimeoutMs,
|
|
1656
|
+
maxTimeout: formatDurationMs(
|
|
1657
|
+
ctx.policy.execution.runnerMaxTimeoutMs,
|
|
1658
|
+
),
|
|
1659
|
+
note: "Requested timeout values are validated explicitly and are never silently reduced to the default.",
|
|
1660
|
+
},
|
|
1661
|
+
preferredTools,
|
|
1662
|
+
capabilityGroups: summarizeCapabilityGroups(),
|
|
1663
|
+
toolArchitecture: {
|
|
1664
|
+
facadeTools: preferredTools,
|
|
1665
|
+
atomicTypedToolsRetained: true,
|
|
1666
|
+
internalHandlersRetained: true,
|
|
1667
|
+
domainSchemaLoading: 'static_stable_surface',
|
|
1668
|
+
dynamicDomainSchemaLoadingSupported: false,
|
|
1669
|
+
capabilityDescriptorCount: capabilityDescriptors.length,
|
|
1670
|
+
},
|
|
1671
|
+
toolExposure: {
|
|
1672
|
+
preferred: preferredTools,
|
|
1673
|
+
note: "Prefer the five rh_* workflow facades for orchestration. Typed repository, Git, Issue/Task, plugin, browser, iOS, artifact, and recovery tools remain available because the current MCP transport cannot load domain schemas per conversation.",
|
|
1674
|
+
exposedToolCount: expectedTools.length,
|
|
1675
|
+
},
|
|
1676
|
+
expectedTools,
|
|
1677
|
+
facadeToolsPresentInExpectedTools: preferredTools.every((tool: string) => expectedTools.includes(tool)),
|
|
1678
|
+
staleConnector,
|
|
1679
|
+
missingFacadeTools,
|
|
1680
|
+
connectorFreshness: {
|
|
1681
|
+
status: connectorFreshness.status,
|
|
1682
|
+
severity: connectorFreshness.severity,
|
|
1683
|
+
summary: connectorFreshness.summary,
|
|
1684
|
+
missingLocalTools: connectorFreshness.missingLocalTools,
|
|
1685
|
+
missingConnectorTools: connectorFreshness.missingConnectorTools,
|
|
1686
|
+
expectedFacadeTools: connectorFreshness.expectedFacadeTools,
|
|
1687
|
+
restartRecommended: connectorFreshness.restartRecommended,
|
|
1688
|
+
reconnectRecommended: connectorFreshness.reconnectRecommended,
|
|
1689
|
+
suggestedActions: connectorFreshness.suggestedActions,
|
|
3815
1690
|
},
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
1691
|
+
docs: [
|
|
1692
|
+
"docs/architecture/current/README.md",
|
|
1693
|
+
"docs/architecture/history.md",
|
|
1694
|
+
"docs/operations/controller-reliability-runbook.md",
|
|
1695
|
+
"docs/forge-github-issue-launcher.md",
|
|
1696
|
+
"docs/forge-chatgpt-mcp-setup.md",
|
|
1697
|
+
],
|
|
1698
|
+
staleConnectorHint: staleConnector
|
|
1699
|
+
? `Stale ChatGPT connector tool snapshot is missing facade tools: ${missingFacadeTools.join(", ")}. Refresh/reconnect MCP so tools/list reloads rh_status, rh_inbox, rh_context, and rh_work.`
|
|
1700
|
+
: connectorFreshness.status === "unable_to_verify_chatgpt_snapshot"
|
|
1701
|
+
? `Local MCP tool surface includes preferred facade tools. ChatGPT connector snapshot was not supplied, so freshness cannot be verified from this call. If ChatGPT tools/list is missing rh_status/rh_inbox/rh_context/rh_work, reconnect MCP. Pass connector_tool_names for an exact check.`
|
|
1702
|
+
: connectorFreshness.status === "stale_fingerprint"
|
|
1703
|
+
? `Local MCP process fingerprint/version may be stale. Restart controller/MCP, then reconnect ChatGPT if rh_* are still missing.`
|
|
1704
|
+
: connectorFreshness.status === "local_mcp_missing_facade"
|
|
1705
|
+
? `Local MCP tool surface is missing facade tools: ${connectorFreshness.missingLocalTools.join(", ")}. Restart controller/MCP.`
|
|
1706
|
+
: `Connector clients must match ${FORGE_TOOL_SURFACE} version ${FORGE_VERSION} / schema ${FORGE_MCP_SCHEMA_VERSION}. Prefer rh_status/rh_inbox/rh_context/rh_work. Pass connector_tool_names to detect a stale ChatGPT tool snapshot precisely.`,
|
|
3819
1707
|
};
|
|
3820
|
-
audit(
|
|
3821
|
-
ctx,
|
|
3822
|
-
name,
|
|
3823
|
-
readiness.queueable ? "ok" : "blocked",
|
|
3824
|
-
args,
|
|
3825
|
-
`tasks/issues/${issue.id}`,
|
|
3826
|
-
);
|
|
3827
|
-
return textResult(preview);
|
|
3828
|
-
}
|
|
3829
|
-
case "assess_work_request": {
|
|
3830
|
-
if (ctx.policy.profile !== "controller")
|
|
3831
|
-
return errorResult("TOOL_DISABLED", "assess_work_request requires the controller profile");
|
|
3832
|
-
const assessment = assessWorkMode({
|
|
3833
|
-
description: String(args.description ?? ""),
|
|
3834
|
-
knownPaths: stringList(args.known_paths),
|
|
3835
|
-
expectedFiles: typeof args.expected_files === "number" ? args.expected_files : undefined,
|
|
3836
|
-
expectedChangedLines: typeof args.expected_changed_lines === "number" ? args.expected_changed_lines : undefined,
|
|
3837
|
-
requiresInvestigation: args.requires_investigation === true,
|
|
3838
|
-
requiresParallelism: args.requires_parallelism === true,
|
|
3839
|
-
requiresLongRunningChecks: args.requires_long_running_checks === true,
|
|
3840
|
-
needsDependencies: args.needs_dependencies === true,
|
|
3841
|
-
risk: typeof args.risk === "string" ? args.risk as TaskRisk : undefined,
|
|
3842
|
-
explicitMode: parseExplicitTaskMode(args.mode),
|
|
3843
|
-
});
|
|
3844
1708
|
audit(ctx, name, "ok", args);
|
|
3845
|
-
return textResult(
|
|
3846
|
-
}
|
|
3847
|
-
case "create_issue": {
|
|
3848
|
-
if (ctx.policy.profile !== "controller")
|
|
3849
|
-
return errorResult(
|
|
3850
|
-
"TOOL_DISABLED",
|
|
3851
|
-
"create_issue requires the controller profile",
|
|
3852
|
-
);
|
|
3853
|
-
const issue = createIssue(ctx.repoRoot, {
|
|
3854
|
-
title: String(args.title ?? ""),
|
|
3855
|
-
kind: (args.kind ? String(args.kind) : "feature") as IssueKind,
|
|
3856
|
-
summary: typeof args.summary === "string" ? args.summary : undefined,
|
|
3857
|
-
goals: stringList(args.goals),
|
|
3858
|
-
nonGoals: stringList(args.non_goals),
|
|
3859
|
-
acceptanceCriteria: stringList(args.acceptance_criteria),
|
|
3860
|
-
relatedArtifacts: stringList(args.related_artifacts),
|
|
3861
|
-
tasks: controllerTaskDrafts(args.tasks),
|
|
3862
|
-
allowWhileFocused: args.allow_while_focused === true,
|
|
3863
|
-
allowDuplicate: args.allow_duplicate === true,
|
|
3864
|
-
allowWhenPaused: args.allow_when_paused === true,
|
|
3865
|
-
});
|
|
3866
|
-
audit(ctx, name, "ok", args, `tasks/issues/${issue.id}`);
|
|
3867
|
-
return textResult(projectIssueEffectiveView(ctx.repoRoot, issue));
|
|
1709
|
+
return textResult(payload);
|
|
3868
1710
|
}
|
|
3869
|
-
case "
|
|
1711
|
+
case "local_bridge_status": {
|
|
3870
1712
|
if (ctx.policy.profile !== "controller")
|
|
3871
1713
|
return errorResult(
|
|
3872
1714
|
"TOOL_DISABLED",
|
|
3873
|
-
"
|
|
1715
|
+
"local_bridge_status requires the controller profile",
|
|
3874
1716
|
);
|
|
3875
|
-
const
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
goals: Array.isArray(args.goals) ? stringList(args.goals) : undefined,
|
|
3884
|
-
nonGoals: Array.isArray(args.non_goals)
|
|
3885
|
-
? stringList(args.non_goals)
|
|
3886
|
-
: undefined,
|
|
3887
|
-
acceptanceCriteria: Array.isArray(args.acceptance_criteria)
|
|
3888
|
-
? stringList(args.acceptance_criteria)
|
|
3889
|
-
: undefined,
|
|
3890
|
-
relatedArtifacts: Array.isArray(args.related_artifacts)
|
|
3891
|
-
? stringList(args.related_artifacts)
|
|
3892
|
-
: undefined,
|
|
3893
|
-
};
|
|
3894
|
-
const migrated = applyMigratedIssueDecision(ctx.repoRoot, {
|
|
3895
|
-
issueId,
|
|
3896
|
-
...patch,
|
|
1717
|
+
const detailLevel = args.detail_level === "detail" || args.detail === true
|
|
1718
|
+
? "detail"
|
|
1719
|
+
: "summary";
|
|
1720
|
+
const controllerHome = resolveRepoPreferredControllerHome(ctx.repoRoot);
|
|
1721
|
+
const surface = resolveLocalBridgeSurface({
|
|
1722
|
+
controllerHome,
|
|
1723
|
+
repoRoot: ctx.repoRoot,
|
|
1724
|
+
allowProcessScan: detailLevel === "detail",
|
|
3897
1725
|
});
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
1726
|
+
const jobs = listLocalBridgeJobs(ctx.repoRoot, detailLevel === "detail" ? 12 : 20);
|
|
1727
|
+
const { activeJobCount, recentJobSummary } = summarizeRecentJobs(jobs);
|
|
1728
|
+
// Prefer authoritative surface; never invent a legacy 8766 endpoint.
|
|
1729
|
+
const endpoint = surface.endpoint ?? null;
|
|
1730
|
+
const running = surface.enabled
|
|
1731
|
+
&& (surface.processRunning === true
|
|
1732
|
+
|| (surface.endpointConfigured && surface.mode === "embedded"));
|
|
1733
|
+
if (detailLevel === "summary") {
|
|
1734
|
+
const payload = {
|
|
1735
|
+
detailLevel: "summary",
|
|
1736
|
+
repoId: ctx.repoId,
|
|
1737
|
+
running,
|
|
1738
|
+
ready: surface.enabled ? (surface.processRunning !== false) : true,
|
|
1739
|
+
health: surface.enabled
|
|
1740
|
+
? (surface.processRunning === true || surface.mode === "embedded" ? "ready" : "warning")
|
|
1741
|
+
: "disabled",
|
|
1742
|
+
mode: surface.mode,
|
|
1743
|
+
endpoint,
|
|
1744
|
+
endpointConfigured: surface.endpointConfigured,
|
|
1745
|
+
endpointReachable: null as boolean | null,
|
|
1746
|
+
processRunning: surface.processRunning ?? null,
|
|
1747
|
+
expectedSurface: surface.expectedSurface,
|
|
1748
|
+
requiredForReadiness: surface.requiredForReadiness,
|
|
1749
|
+
warnings: surface.error && surface.requiredForReadiness
|
|
1750
|
+
? [{ code: "LOCAL_BRIDGE_ERROR", message: surface.error.slice(0, 300) }]
|
|
1751
|
+
: [],
|
|
1752
|
+
activeJobCount,
|
|
1753
|
+
recentJobSummary,
|
|
1754
|
+
statusSource: surface.source,
|
|
1755
|
+
nonBlocking: !surface.requiredForReadiness,
|
|
1756
|
+
approvalQueue: false,
|
|
1757
|
+
};
|
|
1758
|
+
audit(ctx, name, "ok", args);
|
|
1759
|
+
return textResult(payload);
|
|
3901
1760
|
}
|
|
3902
|
-
const
|
|
3903
|
-
|
|
3904
|
-
|
|
1761
|
+
const reconciliation = reconcileLocalBridgeJobs(ctx.repoRoot);
|
|
1762
|
+
const payload = {
|
|
1763
|
+
detailLevel: "detail",
|
|
1764
|
+
endpoint,
|
|
1765
|
+
endpointConfigured: surface.endpointConfigured,
|
|
1766
|
+
running,
|
|
1767
|
+
error: surface.error,
|
|
1768
|
+
mode: surface.mode,
|
|
1769
|
+
requiredForReadiness: surface.requiredForReadiness,
|
|
1770
|
+
statusSource: surface.source,
|
|
1771
|
+
counts: recentJobSummary,
|
|
1772
|
+
activeJobCount,
|
|
1773
|
+
recentJobSummary,
|
|
1774
|
+
approvalQueue: false,
|
|
1775
|
+
reconciliation,
|
|
1776
|
+
recentJobs: jobs.map((job) => ({
|
|
1777
|
+
jobId: job.jobId,
|
|
1778
|
+
action: job.action,
|
|
1779
|
+
status: job.status,
|
|
1780
|
+
checkId: job.action === "run-check" ? (job.payload as { checkId?: string }).checkId : undefined,
|
|
1781
|
+
runId: job.runId,
|
|
1782
|
+
issueId: job.issueId,
|
|
1783
|
+
taskId: job.taskId,
|
|
1784
|
+
createdAt: job.createdAt,
|
|
1785
|
+
updatedAt: job.updatedAt,
|
|
1786
|
+
finishedAt: job.finishedAt,
|
|
1787
|
+
revision: job.revision,
|
|
1788
|
+
deadlineAt: job.deadlineAt,
|
|
1789
|
+
error: job.error?.slice(0, 300),
|
|
1790
|
+
})),
|
|
1791
|
+
nonBlocking: !surface.requiredForReadiness,
|
|
1792
|
+
fallback:
|
|
1793
|
+
"Open the localhost Local Controller to launch work or inspect execution when a ChatGPT write action is unavailable.",
|
|
1794
|
+
};
|
|
1795
|
+
audit(ctx, name, "ok", args);
|
|
1796
|
+
return textResult(payload);
|
|
3905
1797
|
}
|
|
3906
|
-
case "
|
|
1798
|
+
case "controller_context": {
|
|
3907
1799
|
if (ctx.policy.profile !== "controller")
|
|
3908
1800
|
return errorResult(
|
|
3909
1801
|
"TOOL_DISABLED",
|
|
3910
|
-
"
|
|
1802
|
+
"controller_context requires the controller profile",
|
|
3911
1803
|
);
|
|
3912
|
-
const
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
1804
|
+
const controllerHome = resolveRepoPreferredControllerHome(ctx.repoRoot);
|
|
1805
|
+
const requirementBoard = buildRequirementBoard({ controllerHome, repoId: ctx.repoId });
|
|
1806
|
+
const executionDiagnostics = buildExecutionDiagnostics({
|
|
1807
|
+
controllerHome,
|
|
1808
|
+
repoId: ctx.repoId,
|
|
1809
|
+
detailLevel: "detail",
|
|
1810
|
+
});
|
|
1811
|
+
const runs = listAgentJobs(ctx.repoRoot, 8);
|
|
1812
|
+
const reconciliation = reconcileLocalBridgeJobs(ctx.repoRoot);
|
|
1813
|
+
const jobs = listLocalBridgeJobs(ctx.repoRoot, 8);
|
|
1814
|
+
const checks = listControllerChecks(ctx.repoRoot).map((check) => ({
|
|
1815
|
+
id: check.id,
|
|
1816
|
+
description: check.description,
|
|
1817
|
+
timeoutMs: check.timeoutMs,
|
|
1818
|
+
source: check.source,
|
|
1819
|
+
}));
|
|
1820
|
+
const payload = {
|
|
1821
|
+
git: gitSnapshot(ctx.repoRoot),
|
|
1822
|
+
requirementBoard,
|
|
1823
|
+
executionDiagnostics,
|
|
1824
|
+
legacyCompatibility: {
|
|
1825
|
+
currentIssue: "deprecated_frozen",
|
|
1826
|
+
issueTaskBoard: "deprecated_frozen",
|
|
1827
|
+
authority: "controller-home-sqlite",
|
|
1828
|
+
},
|
|
1829
|
+
activeRuns: runs.map((run) => ({
|
|
1830
|
+
runId: run.runId,
|
|
1831
|
+
issueId: run.issueId,
|
|
1832
|
+
taskId: run.taskId,
|
|
1833
|
+
status: run.status,
|
|
1834
|
+
agent: run.agent,
|
|
1835
|
+
provider: run.provider,
|
|
1836
|
+
executionMode: run.executionMode,
|
|
1837
|
+
progress: run.progress,
|
|
1838
|
+
lastHeartbeatAt: run.lastHeartbeatAt,
|
|
1839
|
+
error: run.error?.slice(0, 300),
|
|
1840
|
+
})),
|
|
1841
|
+
localBridge: {
|
|
1842
|
+
reconciliation,
|
|
1843
|
+
recentJobs: jobs.map((job) => ({
|
|
1844
|
+
jobId: job.jobId,
|
|
1845
|
+
action: job.action,
|
|
1846
|
+
status: job.status,
|
|
1847
|
+
checkId: job.action === "run-check" ? (job.payload as { checkId?: string }).checkId : undefined,
|
|
1848
|
+
issueId: job.issueId,
|
|
1849
|
+
taskId: job.taskId,
|
|
1850
|
+
updatedAt: job.updatedAt,
|
|
1851
|
+
})),
|
|
1852
|
+
},
|
|
1853
|
+
checks,
|
|
1854
|
+
};
|
|
1855
|
+
audit(ctx, name, "ok", args);
|
|
1856
|
+
return textResult(payload);
|
|
3919
1857
|
}
|
|
3920
|
-
case "
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
"INVALID_TASK",
|
|
3930
|
-
"append_task requires one valid task",
|
|
3931
|
-
);
|
|
3932
|
-
const issue = appendTask(
|
|
3933
|
-
ctx.repoRoot,
|
|
3934
|
-
String(args.issue_id ?? ""),
|
|
3935
|
-
drafts[0],
|
|
1858
|
+
case "quick_agent_session":
|
|
1859
|
+
case "submit_local_job": {
|
|
1860
|
+
if (ctx.policy.profile !== "controller") {
|
|
1861
|
+
return errorResult("TOOL_DISABLED", `${name} requires the controller profile`);
|
|
1862
|
+
}
|
|
1863
|
+
audit(ctx, name, "blocked", args);
|
|
1864
|
+
return errorResult(
|
|
1865
|
+
name === "quick_agent_session" ? "AGENT_RUN_DEPRECATED" : "LOCAL_BRIDGE_JOB_RETIRED",
|
|
1866
|
+
"Kernel-managed Agent and Local Bridge Jobs are retired. Create or claim WorkContract and use Process Runtime or the Thin Launcher.",
|
|
3936
1867
|
);
|
|
3937
|
-
audit(ctx, name, "ok", args, `tasks/issues/${issue.id}`);
|
|
3938
|
-
return textResult(projectIssueEffectiveView(ctx.repoRoot, issue));
|
|
3939
1868
|
}
|
|
3940
|
-
case "
|
|
1869
|
+
case "list_local_jobs": {
|
|
3941
1870
|
if (ctx.policy.profile !== "controller")
|
|
3942
1871
|
return errorResult(
|
|
3943
1872
|
"TOOL_DISABLED",
|
|
3944
|
-
"
|
|
1873
|
+
"list_local_jobs requires the controller profile",
|
|
3945
1874
|
);
|
|
3946
|
-
const
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
controllerTaskDrafts(args.tasks),
|
|
3951
|
-
);
|
|
3952
|
-
audit(ctx, name, "ok", args, `tasks/issues/${issue.id}`);
|
|
3953
|
-
return textResult(projectIssueEffectiveView(ctx.repoRoot, issue));
|
|
1875
|
+
const limit = typeof args.limit === "number" ? args.limit : 50;
|
|
1876
|
+
const jobs = listLocalBridgeJobs(ctx.repoRoot, limit);
|
|
1877
|
+
audit(ctx, name, "ok", args);
|
|
1878
|
+
return textResult({ jobs });
|
|
3954
1879
|
}
|
|
3955
|
-
case "
|
|
1880
|
+
case "get_local_job": {
|
|
3956
1881
|
if (ctx.policy.profile !== "controller")
|
|
3957
1882
|
return errorResult(
|
|
3958
1883
|
"TOOL_DISABLED",
|
|
3959
|
-
"
|
|
1884
|
+
"get_local_job requires the controller profile",
|
|
3960
1885
|
);
|
|
3961
|
-
const
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
1886
|
+
const jobId = String(args.job_id ?? "").trim();
|
|
1887
|
+
const includeEvents = args.include_events === true;
|
|
1888
|
+
const includeOutput = args.include_output === true;
|
|
1889
|
+
const snapshot = getLocalBridgeJobSnapshot(ctx.repoRoot, jobId);
|
|
1890
|
+
const payload = {
|
|
1891
|
+
job: snapshot.job,
|
|
1892
|
+
...(snapshot.status !== "ok" ? { lookup: snapshot } : {}),
|
|
1893
|
+
...(includeEvents && snapshot.status === "ok" ? { events: getLocalBridgeJobEvents(ctx.repoRoot, jobId) } : {}),
|
|
1894
|
+
...(includeOutput
|
|
1895
|
+
? {
|
|
1896
|
+
output: readLocalBridgeJobOutput(ctx.repoRoot, jobId, {
|
|
1897
|
+
stream: args.stream === "stderr" ? "stderr" : "stdout",
|
|
1898
|
+
maxBytes: typeof args.max_bytes === "number" ? args.max_bytes : undefined,
|
|
1899
|
+
}),
|
|
1900
|
+
}
|
|
1901
|
+
: {}),
|
|
1902
|
+
};
|
|
1903
|
+
audit(ctx, name, "ok", args);
|
|
1904
|
+
return textResult(payload);
|
|
3969
1905
|
}
|
|
3970
|
-
case "
|
|
1906
|
+
case "get_local_job_output": {
|
|
3971
1907
|
if (ctx.policy.profile !== "controller")
|
|
3972
1908
|
return errorResult(
|
|
3973
1909
|
"TOOL_DISABLED",
|
|
3974
|
-
"
|
|
1910
|
+
"get_local_job_output requires the controller profile",
|
|
3975
1911
|
);
|
|
3976
|
-
const
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
);
|
|
3982
|
-
|
|
3983
|
-
return textResult(projectIssueEffectiveView(ctx.repoRoot, issue));
|
|
1912
|
+
const jobId = String(args.job_id ?? "").trim();
|
|
1913
|
+
const payload = readLocalBridgeJobOutput(ctx.repoRoot, jobId, {
|
|
1914
|
+
stream: args.stream === "stderr" ? "stderr" : "stdout",
|
|
1915
|
+
maxBytes: typeof args.max_bytes === "number" ? args.max_bytes : undefined,
|
|
1916
|
+
});
|
|
1917
|
+
audit(ctx, name, "ok", args);
|
|
1918
|
+
return textResult(payload);
|
|
3984
1919
|
}
|
|
3985
|
-
case "
|
|
3986
|
-
if (ctx.policy.profile !== "controller")
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
const
|
|
3994
|
-
ctx.repoRoot,
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
{
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
1920
|
+
case "project_snapshot": {
|
|
1921
|
+
if (ctx.policy.profile !== "controller") return errorResult("TOOL_DISABLED", "project_snapshot requires the controller profile");
|
|
1922
|
+
const markerPaths = [
|
|
1923
|
+
".ai/harness/active-plan",
|
|
1924
|
+
".ai/harness/active-sprint",
|
|
1925
|
+
".ai/harness/active-worktree",
|
|
1926
|
+
"tasks/current.md",
|
|
1927
|
+
];
|
|
1928
|
+
const markers = markerPaths.map((path) => {
|
|
1929
|
+
const absolute = join(ctx.repoRoot, path);
|
|
1930
|
+
if (!existsSync(absolute)) return { path, exists: false };
|
|
1931
|
+
const raw = readFileSync(absolute, "utf-8");
|
|
1932
|
+
return {
|
|
1933
|
+
path,
|
|
1934
|
+
exists: true,
|
|
1935
|
+
bytes: Buffer.byteLength(raw),
|
|
1936
|
+
lines: raw.split(/\r?\n/).length,
|
|
1937
|
+
sha256: createHash("sha256").update(raw).digest("hex").slice(0, 16),
|
|
1938
|
+
preview: redactMcpText(raw).text.slice(0, 400),
|
|
1939
|
+
};
|
|
1940
|
+
});
|
|
1941
|
+
const controllerHome = resolveRepoPreferredControllerHome(ctx.repoRoot);
|
|
1942
|
+
const requirementBoard = buildRequirementBoard({ controllerHome, repoId: ctx.repoId });
|
|
1943
|
+
const executionDiagnostics = buildExecutionDiagnostics({
|
|
1944
|
+
controllerHome,
|
|
1945
|
+
repoId: ctx.repoId,
|
|
1946
|
+
detailLevel: "detail",
|
|
1947
|
+
});
|
|
1948
|
+
const snapshotRuns = listAgentJobs(ctx.repoRoot, 11);
|
|
1949
|
+
const runs = snapshotRuns.slice(0, 10).map((run) => ({
|
|
1950
|
+
runId: run.runId,
|
|
1951
|
+
issueId: run.issueId,
|
|
1952
|
+
taskId: run.taskId,
|
|
1953
|
+
agent: run.agent,
|
|
1954
|
+
provider: run.provider,
|
|
1955
|
+
executionMode: run.executionMode,
|
|
1956
|
+
status: run.status,
|
|
1957
|
+
progress: run.progress,
|
|
1958
|
+
createdAt: run.createdAt,
|
|
1959
|
+
finishedAt: run.finishedAt,
|
|
1960
|
+
error: run.error?.slice(0, 300),
|
|
1961
|
+
}));
|
|
4008
1962
|
const payload = {
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
1963
|
+
git: gitSnapshot(ctx.repoRoot),
|
|
1964
|
+
requirementBoard,
|
|
1965
|
+
executionDiagnostics,
|
|
1966
|
+
legacyCompatibility: {
|
|
1967
|
+
currentIssue: "deprecated_frozen",
|
|
1968
|
+
issueTaskBoard: "deprecated_frozen",
|
|
1969
|
+
authority: "controller-home-sqlite",
|
|
1970
|
+
},
|
|
1971
|
+
runs,
|
|
1972
|
+
markers,
|
|
1973
|
+
truncated: {
|
|
1974
|
+
runs: snapshotRuns.length > 10,
|
|
4013
1975
|
},
|
|
4014
1976
|
};
|
|
4015
|
-
|
|
1977
|
+
audit(ctx, name, "ok", args);
|
|
4016
1978
|
return textResult(payload);
|
|
4017
1979
|
}
|
|
4018
|
-
case "
|
|
4019
|
-
if (ctx.policy.profile !== "controller") return errorResult("TOOL_DISABLED", "dispatch_task requires the controller profile");
|
|
4020
|
-
audit(ctx, name, "blocked", args);
|
|
4021
|
-
return errorResult(
|
|
4022
|
-
"AGENT_RUN_DEPRECATED",
|
|
4023
|
-
"Kernel-managed Agent Runs are retired. Create or claim a WorkContract through rh_work, then start an external SuperController session through the Thin Launcher.",
|
|
4024
|
-
);
|
|
4025
|
-
}
|
|
4026
|
-
case "launch_issue": {
|
|
4027
|
-
if (ctx.policy.profile !== "controller") return errorResult("TOOL_DISABLED", "launch_issue requires the controller profile");
|
|
4028
|
-
audit(ctx, name, "blocked", args);
|
|
4029
|
-
return errorResult(
|
|
4030
|
-
"AGENT_RUN_DEPRECATED",
|
|
4031
|
-
"Kernel-managed Agent Runs are retired. Convert the Issue tasks to WorkContracts and claim them through rh_work.",
|
|
4032
|
-
);
|
|
4033
|
-
}
|
|
4034
|
-
case "dispatch_ready_tasks": {
|
|
4035
|
-
if (ctx.policy.profile !== "controller") return errorResult("TOOL_DISABLED", "dispatch_ready_tasks requires the controller profile");
|
|
4036
|
-
audit(ctx, name, "blocked", args);
|
|
4037
|
-
return errorResult(
|
|
4038
|
-
"AGENT_RUN_DEPRECATED",
|
|
4039
|
-
"Kernel-managed batch dispatch is retired. Convert ready Tasks into WorkContracts, claim them explicitly, and launch peer external Controllers through the Thin Launcher.",
|
|
4040
|
-
{
|
|
4041
|
-
requestedIssue: typeof args.issue_id === "string" && args.issue_id.trim() ? args.issue_id.trim() : undefined,
|
|
4042
|
-
currentFocus: loadControllerProjectState(ctx.repoRoot).currentIssueId,
|
|
4043
|
-
focusIsInformational: true,
|
|
4044
|
-
},
|
|
4045
|
-
);
|
|
4046
|
-
}
|
|
4047
|
-
case "get_task_run": {
|
|
4048
|
-
if (ctx.policy.profile !== "controller")
|
|
4049
|
-
return errorResult(
|
|
4050
|
-
"TOOL_DISABLED",
|
|
4051
|
-
"get_task_run requires the controller profile",
|
|
4052
|
-
);
|
|
4053
|
-
const run = getAgentJob(ctx.repoRoot, String(args.run_id ?? ""));
|
|
4054
|
-
audit(ctx, name, "ok", args, run.promptPath);
|
|
4055
|
-
return textResult(summarizeAgentRun(ctx.repoRoot, run as unknown as Record<string, unknown>, {
|
|
4056
|
-
includePaths: args.include_paths === true,
|
|
4057
|
-
includeOutput: args.include_output !== false,
|
|
4058
|
-
tailChars: typeof args.tail_chars === "number" ? Math.trunc(args.tail_chars) : undefined,
|
|
4059
|
-
}));
|
|
4060
|
-
}
|
|
4061
|
-
case "get_task_run_events": {
|
|
1980
|
+
case "search_repository": {
|
|
4062
1981
|
if (ctx.policy.profile !== "controller")
|
|
4063
1982
|
return errorResult(
|
|
4064
1983
|
"TOOL_DISABLED",
|
|
4065
|
-
"
|
|
1984
|
+
"search_repository requires the controller profile",
|
|
4066
1985
|
);
|
|
4067
|
-
const
|
|
4068
|
-
?
|
|
1986
|
+
const session = ctx.sessionId && ctx.repoId
|
|
1987
|
+
? {
|
|
1988
|
+
sessionId: ctx.sessionId,
|
|
1989
|
+
repoId: ctx.repoId,
|
|
1990
|
+
checkoutId: ctx.checkoutId ?? ctx.repoId,
|
|
1991
|
+
}
|
|
4069
1992
|
: undefined;
|
|
4070
|
-
const
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
return textResult({
|
|
4081
|
-
events,
|
|
4082
|
-
// Keep an existing cursor stable when no new event is available. New events
|
|
4083
|
-
// that race with a read are returned on the next call instead of being lost.
|
|
4084
|
-
nextSinceEventIndex: events.at(-1)?.data?.eventIndex ?? sinceEventIndex,
|
|
4085
|
-
heartbeatsCollapsed: args.include_heartbeats !== true,
|
|
1993
|
+
const result = searchRepository(ctx.repoRoot, ctx.policy, {
|
|
1994
|
+
query: String(args.query ?? ""),
|
|
1995
|
+
includeGlobs: stringList(args.include_globs),
|
|
1996
|
+
excludeGlobs: stringList(args.exclude_globs),
|
|
1997
|
+
maxResults:
|
|
1998
|
+
typeof args.max_results === "number" ? args.max_results : undefined,
|
|
1999
|
+
maxFiles:
|
|
2000
|
+
typeof args.max_files === "number" ? args.max_files : undefined,
|
|
2001
|
+
caseSensitive: args.case_sensitive === true,
|
|
2002
|
+
session,
|
|
4086
2003
|
});
|
|
2004
|
+
audit(ctx, name, "ok", args);
|
|
2005
|
+
return textResult(result);
|
|
4087
2006
|
}
|
|
4088
|
-
case "
|
|
2007
|
+
case "get_git_diff": {
|
|
4089
2008
|
if (ctx.policy.profile !== "controller")
|
|
4090
2009
|
return errorResult(
|
|
4091
2010
|
"TOOL_DISABLED",
|
|
4092
|
-
"
|
|
2011
|
+
"get_git_diff requires the controller profile",
|
|
4093
2012
|
);
|
|
4094
|
-
const
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
);
|
|
2013
|
+
const path =
|
|
2014
|
+
typeof args.path === "string" && args.path.trim()
|
|
2015
|
+
? args.path.trim()
|
|
2016
|
+
: undefined;
|
|
2017
|
+
if (path) {
|
|
2018
|
+
const decision = resolveMcpPath(
|
|
2019
|
+
ctx.repoRoot,
|
|
2020
|
+
path,
|
|
2021
|
+
ctx.policy,
|
|
2022
|
+
"read",
|
|
2023
|
+
);
|
|
2024
|
+
if (!decision.ok)
|
|
2025
|
+
return errorResult(
|
|
2026
|
+
"POLICY_DENIED",
|
|
2027
|
+
decision.reason ?? "path denied",
|
|
2028
|
+
{ path },
|
|
2029
|
+
);
|
|
2030
|
+
}
|
|
2031
|
+
const maxBytes =
|
|
2032
|
+
typeof args.max_bytes === "number"
|
|
2033
|
+
? Math.min(Math.max(Math.trunc(args.max_bytes), 1024), 512 * 1024)
|
|
2034
|
+
: 128 * 1024;
|
|
2035
|
+
const result = gitDiff(ctx.repoRoot, path, maxBytes);
|
|
2036
|
+
const redacted = redactMcpText(result.diff);
|
|
2037
|
+
audit(ctx, name, "ok", args, path);
|
|
4118
2038
|
return textResult({
|
|
4119
|
-
...
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
redactions: bounded.redactions,
|
|
4123
|
-
next: bounded.truncated
|
|
4124
|
-
? "Call get_task_run_log with a larger max_bytes value for more retained tail."
|
|
4125
|
-
: undefined,
|
|
2039
|
+
...result,
|
|
2040
|
+
diff: redacted.text,
|
|
2041
|
+
redactions: redacted.redactions,
|
|
4126
2042
|
});
|
|
4127
2043
|
}
|
|
4128
|
-
case "
|
|
2044
|
+
case "list_checks": {
|
|
4129
2045
|
if (ctx.policy.profile !== "controller")
|
|
4130
2046
|
return errorResult(
|
|
4131
2047
|
"TOOL_DISABLED",
|
|
4132
|
-
"
|
|
2048
|
+
"list_checks requires the controller profile",
|
|
4133
2049
|
);
|
|
4134
|
-
const
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
typeof args.max_bytes === "number"
|
|
4138
|
-
? Math.min(Math.max(Math.trunc(args.max_bytes), 1024), 1024 * 1024)
|
|
4139
|
-
: undefined,
|
|
4140
|
-
);
|
|
4141
|
-
audit(ctx, name, "ok", args, diff.worktree);
|
|
4142
|
-
return textResult(diff);
|
|
2050
|
+
const checks = listControllerChecks(ctx.repoRoot);
|
|
2051
|
+
audit(ctx, name, "ok", args);
|
|
2052
|
+
return textResult({ checks });
|
|
4143
2053
|
}
|
|
4144
|
-
case "
|
|
2054
|
+
case "get_worklog_timeline": {
|
|
4145
2055
|
if (ctx.policy.profile !== "controller")
|
|
4146
|
-
return errorResult(
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
args,
|
|
4160
|
-
`controller-home://repositories/${editExecutionIdentity(ctx).repoId}/edit-sessions/${integrated.session.sessionId}`,
|
|
4161
|
-
);
|
|
4162
|
-
return textResult(integrated);
|
|
2056
|
+
return errorResult("TOOL_DISABLED", "get_worklog_timeline requires the controller profile");
|
|
2057
|
+
const events = listControllerWorklogEvents(ctx.repoRoot, {
|
|
2058
|
+
category: parseWorklogCategory(args.category),
|
|
2059
|
+
issueId: typeof args.issue_id === "string" ? args.issue_id : undefined,
|
|
2060
|
+
taskId: typeof args.task_id === "string" ? args.task_id : undefined,
|
|
2061
|
+
runId: typeof args.run_id === "string" ? args.run_id : undefined,
|
|
2062
|
+
editSessionId: typeof args.edit_session_id === "string" ? args.edit_session_id : undefined,
|
|
2063
|
+
since: typeof args.since === "string" ? args.since : undefined,
|
|
2064
|
+
until: typeof args.until === "string" ? args.until : undefined,
|
|
2065
|
+
limit: typeof args.limit === "number" ? Math.trunc(args.limit) : undefined,
|
|
2066
|
+
});
|
|
2067
|
+
audit(ctx, name, "ok", args);
|
|
2068
|
+
return textResult({ events });
|
|
4163
2069
|
}
|
|
4164
|
-
case "
|
|
2070
|
+
case "export_worklog": {
|
|
4165
2071
|
if (ctx.policy.profile !== "controller")
|
|
4166
|
-
return errorResult(
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
runs: summarizeRunList(
|
|
4177
|
-
ctx.repoRoot,
|
|
4178
|
-
runs as unknown as Array<Record<string, unknown>>,
|
|
4179
|
-
args.include_paths === true,
|
|
4180
|
-
),
|
|
2072
|
+
return errorResult("TOOL_DISABLED", "export_worklog requires the controller profile");
|
|
2073
|
+
const result = exportControllerWorklog(ctx.repoRoot, {
|
|
2074
|
+
format: args.format === "json" ? "json" : "markdown",
|
|
2075
|
+
outputPath: typeof args.output_path === "string" ? args.output_path : undefined,
|
|
2076
|
+
filter: {
|
|
2077
|
+
issueId: typeof args.issue_id === "string" ? args.issue_id : undefined,
|
|
2078
|
+
taskId: typeof args.task_id === "string" ? args.task_id : undefined,
|
|
2079
|
+
runId: typeof args.run_id === "string" ? args.run_id : undefined,
|
|
2080
|
+
editSessionId: typeof args.edit_session_id === "string" ? args.edit_session_id : undefined,
|
|
2081
|
+
},
|
|
4181
2082
|
});
|
|
2083
|
+
audit(ctx, name, "ok", args, result.path);
|
|
2084
|
+
return textResult(result);
|
|
4182
2085
|
}
|
|
4183
|
-
case "
|
|
2086
|
+
case "get_github_plugin_status": {
|
|
4184
2087
|
if (ctx.policy.profile !== "controller")
|
|
4185
|
-
return errorResult(
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
const run = cancelAgentJob(ctx.repoRoot, String(args.run_id ?? ""));
|
|
4190
|
-
audit(ctx, name, "ok", args, run.promptPath);
|
|
4191
|
-
return textResult(run);
|
|
2088
|
+
return errorResult("TOOL_DISABLED", "get_github_plugin_status requires the controller profile");
|
|
2089
|
+
const status = getGitHubPluginStatus(ctx.repoRoot);
|
|
2090
|
+
audit(ctx, name, "ok", args, status.repository);
|
|
2091
|
+
return textResult(status);
|
|
4192
2092
|
}
|
|
4193
|
-
case "
|
|
2093
|
+
case "configure_github_plugin": {
|
|
4194
2094
|
if (ctx.policy.profile !== "controller")
|
|
4195
|
-
return errorResult(
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
"
|
|
4203
|
-
"Kernel-managed Agent Run retry is disabled. Create or claim a WorkContract and start an external SuperController through Thin Launcher.",
|
|
4204
|
-
);
|
|
4205
|
-
}
|
|
4206
|
-
case "finish_task_run": {
|
|
4207
|
-
if (ctx.policy.profile !== "controller") return errorResult("TOOL_DISABLED", "finish_task_run requires the controller profile");
|
|
4208
|
-
const runId = String(args.run_id ?? "").trim();
|
|
4209
|
-
if (!runId) return errorResult("RUN_ID_REQUIRED", "finish_task_run requires run_id");
|
|
4210
|
-
const decision = typeof args.decision === "string" ? args.decision : "auto";
|
|
4211
|
-
if (!["auto", "approve_and_finish", "request_changes", "discard"].includes(decision)) {
|
|
4212
|
-
return errorResult("INVALID_DECISION", "decision must be auto, approve_and_finish, request_changes, or discard");
|
|
4213
|
-
}
|
|
4214
|
-
const finished = finishTaskRun(ctx.repoRoot, {
|
|
4215
|
-
runId,
|
|
4216
|
-
decision: decision as "auto" | "approve_and_finish" | "request_changes" | "discard",
|
|
4217
|
-
reviewer: typeof args.reviewer === "string" ? args.reviewer : undefined,
|
|
4218
|
-
note: typeof args.note === "string" ? args.note : undefined,
|
|
4219
|
-
cleanup: typeof args.cleanup === "boolean" ? args.cleanup : undefined,
|
|
4220
|
-
commit: typeof args.commit === "boolean" ? args.commit : undefined,
|
|
4221
|
-
});
|
|
4222
|
-
audit(ctx, name, ["blocked", "needs_decision"].includes(finished.action) ? "failed" : "ok", args, `tasks/issues/${finished.issueId}`, finished.reason);
|
|
4223
|
-
return textResult(finished);
|
|
4224
|
-
}
|
|
4225
|
-
case "verify_task": {
|
|
4226
|
-
if (ctx.policy.profile !== "controller") return errorResult("TOOL_DISABLED", "verify_task requires the controller profile");
|
|
4227
|
-
const issueId = String(args.issue_id ?? "");
|
|
4228
|
-
const taskId = String(args.task_id ?? "");
|
|
4229
|
-
const current = getIssue(ctx.repoRoot, issueId);
|
|
4230
|
-
const task = current.tasks.find((entry) => entry.id === taskId);
|
|
4231
|
-
if (!task) return errorResult("TASK_NOT_FOUND", `task not found: ${issueId}/${taskId}`);
|
|
4232
|
-
const policy = taskExecutionPolicy(task);
|
|
4233
|
-
const evidenceRunId = typeof args.run_id === "string" ? args.run_id : task.runIds.at(-1);
|
|
4234
|
-
let evidenceRun: ReturnType<typeof getAgentJob> | undefined;
|
|
4235
|
-
if (evidenceRunId) {
|
|
4236
|
-
evidenceRun = getAgentJob(ctx.repoRoot, evidenceRunId);
|
|
4237
|
-
if (evidenceRun.issueId !== issueId || evidenceRun.taskId !== taskId) return errorResult("RUN_TASK_MISMATCH", `Run ${evidenceRunId} does not belong to ${issueId}/${taskId}`);
|
|
4238
|
-
if (evidenceRun.status !== "succeeded") return errorResult("RUN_NOT_SUCCEEDED", `verification requires a succeeded Run (current: ${evidenceRun.status})`);
|
|
4239
|
-
if (evidenceRun.provider === "local" && evidenceRun.worktree !== ctx.repoRoot && !evidenceRun.integratedSessionId) return errorResult("RUN_NOT_INTEGRATED", "integrate the isolated local Run before recording verification");
|
|
4240
|
-
if (evidenceRun.provider === "github" && evidenceRun.github?.createPullRequest !== false && !evidenceRun.github?.pullRequestUrl) return errorResult("GITHUB_PR_NOT_READY", "GitHub cloud verification requires the linked pull request to be available");
|
|
4241
|
-
}
|
|
4242
|
-
|
|
4243
|
-
const requestedCheckInputs = taskObjects(args.check_results).map((entry) => ({
|
|
4244
|
-
checkId: String(entry.check_id ?? "").trim(),
|
|
4245
|
-
requestedSummary: typeof entry.summary === "string" ? entry.summary : undefined,
|
|
4246
|
-
})).filter((entry) => entry.checkId);
|
|
4247
|
-
const registryChecks = listControllerChecks(ctx.repoRoot);
|
|
4248
|
-
const requestedCheckIds = task.checks.length > 0 ? task.checks : requestedCheckInputs.map((entry) => entry.checkId);
|
|
4249
|
-
const normalizedChecks = normalizeCheckIds(requestedCheckIds, registryChecks);
|
|
4250
|
-
const checkIds = normalizedChecks.validCheckIds;
|
|
4251
|
-
const checkResults: TaskVerification['checkResults'] = [];
|
|
4252
|
-
if (checkIds.length > 0) {
|
|
4253
|
-
const controllerHome = resolveRepoPreferredControllerHome(ctx.repoRoot);
|
|
4254
|
-
const repository = resolveRepositorySelection({
|
|
4255
|
-
explicitPath: ctx.repoRoot,
|
|
4256
|
-
controllerHome,
|
|
4257
|
-
allowSoleRepository: true,
|
|
4258
|
-
});
|
|
4259
|
-
if (!repository) return errorResult('TASK_CHECK_REPOSITORY_UNRESOLVED', 'verify_task could not resolve the repository checkout');
|
|
4260
|
-
const taskCheckRequestBase = typeof args.request_id === 'string' && args.request_id.trim()
|
|
4261
|
-
? args.request_id.trim()
|
|
4262
|
-
: `verify-task:${issueId}:${taskId}:${createHash('sha256').update(JSON.stringify({ checkIds, revision: args.integrated_revision ?? evidenceRun?.integratedSessionId ?? 'current' })).digest('hex').slice(0, 16)}`;
|
|
4263
|
-
for (const [index, checkId] of checkIds.entries()) {
|
|
4264
|
-
const processRequestId = `${taskCheckRequestBase}:check:${index + 1}:${createHash('sha256').update(checkId).digest('hex').slice(0, 12)}`;
|
|
4265
|
-
const facade = await runPersistedCheckViaProcessRuntime({
|
|
4266
|
-
controllerHome,
|
|
4267
|
-
repoId: repository.repoId,
|
|
4268
|
-
checkoutId: repository.activeCheckoutId,
|
|
4269
|
-
repoRoot: repository.canonicalRoot,
|
|
4270
|
-
executionIdentity: executionIdentityForRepository(repository),
|
|
4271
|
-
checkId,
|
|
4272
|
-
requestId: processRequestId,
|
|
4273
|
-
commandId: processRequestId,
|
|
4274
|
-
verificationBinding: { issueId, taskId },
|
|
4275
|
-
});
|
|
4276
|
-
if (facade.mode === 'durable' || !facade.process) {
|
|
4277
|
-
return errorResult('TASK_CHECK_DURABLE_REQUIRED', facade.durable?.reason ?? `check requires durable workflow: ${checkId}`);
|
|
4278
|
-
}
|
|
4279
|
-
if (!facade.process.completed) {
|
|
4280
|
-
return textResult({
|
|
4281
|
-
accepted: true,
|
|
4282
|
-
status: 'verification_running',
|
|
4283
|
-
issueId,
|
|
4284
|
-
taskId,
|
|
4285
|
-
checkId,
|
|
4286
|
-
requestId: taskCheckRequestBase,
|
|
4287
|
-
processId: facade.process.processId,
|
|
4288
|
-
next: `Retry verify_task with request_id=${taskCheckRequestBase}; the original Process will be reused.`,
|
|
4289
|
-
durableSideEffects: { executionJobCount: 0, localJobCount: 0, workerSpawnCount: 0, projectionUpdateCount: 0 },
|
|
4290
|
-
});
|
|
4291
|
-
}
|
|
4292
|
-
const record = getProcessRecord(controllerHome, repository.repoId, facade.process.processId);
|
|
4293
|
-
if (!record) return errorResult('TASK_CHECK_PROCESS_MISSING', `process record not found: ${facade.process.processId}`);
|
|
4294
|
-
const leaseConflict = taskVerificationLeaseConflict(record);
|
|
4295
|
-
if (leaseConflict) {
|
|
4296
|
-
const retryRequestId = taskVerificationRetryRequestId(
|
|
4297
|
-
taskCheckRequestBase,
|
|
4298
|
-
checkId,
|
|
4299
|
-
facade.process.processId,
|
|
4300
|
-
);
|
|
4301
|
-
return textResult({
|
|
4302
|
-
accepted: true,
|
|
4303
|
-
status: 'verification_deferred',
|
|
4304
|
-
reason: 'repository_resource_busy',
|
|
4305
|
-
issueId,
|
|
4306
|
-
taskId,
|
|
4307
|
-
checkId,
|
|
4308
|
-
requestId: taskCheckRequestBase,
|
|
4309
|
-
processId: facade.process.processId,
|
|
4310
|
-
conflict: {
|
|
4311
|
-
code: 'PROCESS_LEASE_CONFLICT',
|
|
4312
|
-
resourceKey: leaseConflict.resourceKey,
|
|
4313
|
-
blockingProcessId: leaseConflict.blockingProcessId,
|
|
4314
|
-
},
|
|
4315
|
-
retryRequestId,
|
|
4316
|
-
next: `Retry verify_task with request_id=${retryRequestId} after the conflicting repository process settles.`,
|
|
4317
|
-
durableSideEffects: { executionJobCount: 0, localJobCount: 0, workerSpawnCount: 0, projectionUpdateCount: 0 },
|
|
4318
|
-
});
|
|
4319
|
-
}
|
|
4320
|
-
const receipt = processCheckCompletionReceipt(record, {
|
|
4321
|
-
repoId: repository.repoId,
|
|
4322
|
-
checkoutId: repository.activeCheckoutId,
|
|
4323
|
-
issueId,
|
|
4324
|
-
taskId,
|
|
4325
|
-
checkId,
|
|
4326
|
-
processId: facade.process.processId,
|
|
4327
|
-
});
|
|
4328
|
-
checkResults.push({
|
|
4329
|
-
checkId,
|
|
4330
|
-
ok: receipt.ok,
|
|
4331
|
-
summary: receipt.summary,
|
|
4332
|
-
receipt,
|
|
4333
|
-
});
|
|
4334
|
-
}
|
|
4335
|
-
}
|
|
4336
|
-
|
|
4337
|
-
const commandEvidence: TaskCommandEvidence[] = [];
|
|
4338
|
-
for (const entry of taskObjects(args.reported_commands)) {
|
|
4339
|
-
const command = Array.isArray(entry.command) ? entry.command.map(String).map((part) => part.trim()).filter(Boolean) : [];
|
|
4340
|
-
if (command.length === 0) return errorResult("INVALID_COMMAND_EVIDENCE", "reported command evidence requires a non-empty command argv");
|
|
4341
|
-
const cwdInput = typeof entry.cwd === "string" && entry.cwd.trim() ? entry.cwd.trim() : undefined;
|
|
4342
|
-
if (cwdInput && cwdInput !== "." && cwdInput !== "./") {
|
|
4343
|
-
const cwdDecision = resolveMcpPath(ctx.repoRoot, cwdInput, ctx.policy, "read");
|
|
4344
|
-
if (!cwdDecision.ok) {
|
|
4345
|
-
const normalizedCwd = normalizeMcpRelativePath(cwdInput);
|
|
4346
|
-
const missingHarnessEvidence = normalizedCwd.ok &&
|
|
4347
|
-
normalizedCwd.relativePath?.startsWith(".ai/harness/") &&
|
|
4348
|
-
cwdDecision.reason?.startsWith("path does not exist:");
|
|
4349
|
-
if (!missingHarnessEvidence) return errorResult("COMMAND_EVIDENCE_PATH_DENIED", cwdDecision.reason ?? "reported command cwd is denied");
|
|
4350
|
-
}
|
|
4351
|
-
}
|
|
4352
|
-
const artifactInput = typeof entry.artifact_path === "string" && entry.artifact_path.trim() ? entry.artifact_path.trim() : undefined;
|
|
4353
|
-
if (artifactInput) {
|
|
4354
|
-
const artifactDecision = resolveMcpPath(ctx.repoRoot, artifactInput, ctx.policy, "read");
|
|
4355
|
-
if (!artifactDecision.ok) {
|
|
4356
|
-
const normalizedArtifact = normalizeMcpRelativePath(artifactInput);
|
|
4357
|
-
const missingHarnessEvidence = normalizedArtifact.ok &&
|
|
4358
|
-
normalizedArtifact.relativePath?.startsWith(".ai/harness/") &&
|
|
4359
|
-
artifactDecision.reason?.startsWith("path does not exist:");
|
|
4360
|
-
if (!missingHarnessEvidence) return errorResult("COMMAND_EVIDENCE_ARTIFACT_DENIED", artifactDecision.reason ?? "reported command artifact is denied");
|
|
4361
|
-
}
|
|
4362
|
-
}
|
|
4363
|
-
commandEvidence.push({
|
|
4364
|
-
command,
|
|
4365
|
-
cwd: cwdInput,
|
|
4366
|
-
ok: entry.ok === true,
|
|
4367
|
-
exitCode: typeof entry.exit_code === "number" ? Math.trunc(entry.exit_code) : undefined,
|
|
4368
|
-
stdout: typeof entry.stdout === "string" ? entry.stdout.slice(-32 * 1024) : undefined,
|
|
4369
|
-
stderr: typeof entry.stderr === "string" ? entry.stderr.slice(-32 * 1024) : undefined,
|
|
4370
|
-
artifactPath: artifactInput,
|
|
4371
|
-
reportedBy: String(args.reviewer ?? "").trim(),
|
|
4372
|
-
executedAt: typeof entry.executed_at === "string" ? entry.executed_at : new Date().toISOString(),
|
|
4373
|
-
source: "reported",
|
|
4374
|
-
});
|
|
4375
|
-
}
|
|
4376
|
-
|
|
4377
|
-
let acceptanceResults: TaskVerification["acceptanceResults"] = taskObjects(args.acceptance_results).map((entry) => ({
|
|
4378
|
-
criterion: String(entry.criterion ?? ""),
|
|
4379
|
-
ok: entry.ok === true,
|
|
4380
|
-
outcome: entry.ok === true ? "passed" as const : "failed" as const,
|
|
4381
|
-
source: "reported" as const,
|
|
4382
|
-
evidence: typeof entry.evidence === "string" ? entry.evidence : undefined,
|
|
4383
|
-
}));
|
|
4384
|
-
if (acceptanceResults.length === 0 && evidenceRun && task.acceptanceCriteria.length > 0) {
|
|
4385
|
-
acceptanceResults = task.acceptanceCriteria.map((criterion) => ({
|
|
4386
|
-
criterion,
|
|
4387
|
-
ok: false,
|
|
4388
|
-
outcome: "not_evaluated" as const,
|
|
4389
|
-
source: "run_completion" as const,
|
|
4390
|
-
evidence: `Successful Run ${evidenceRun!.runId}; acceptance was not independently evaluated.`,
|
|
4391
|
-
}));
|
|
4392
|
-
}
|
|
4393
|
-
const verification: TaskVerification = {
|
|
4394
|
-
runId: evidenceRunId,
|
|
4395
|
-
integratedRevision: typeof args.integrated_revision === "string" ? args.integrated_revision : evidenceRun?.integratedSessionId,
|
|
4396
|
-
reviewedDiffHash: typeof args.reviewed_diff_hash === "string" ? args.reviewed_diff_hash : undefined,
|
|
4397
|
-
reviewer: String(args.reviewer ?? ""),
|
|
4398
|
-
checkResults,
|
|
4399
|
-
commandEvidence,
|
|
4400
|
-
acceptanceResults,
|
|
4401
|
-
verifiedAt: new Date().toISOString(),
|
|
4402
|
-
};
|
|
4403
|
-
const issue = recordTaskVerification(ctx.repoRoot, issueId, taskId, verification);
|
|
4404
|
-
const issueView = projectIssueEffectiveView(ctx.repoRoot, issue);
|
|
4405
|
-
const verifiedTask = issueView.tasks.find((entry) => entry.id === taskId);
|
|
4406
|
-
audit(ctx, name, ["verified", "done"].includes(verifiedTask?.status ?? "") ? "ok" : "failed", args, `tasks/issues/${issue.id}`);
|
|
4407
|
-
return textResult({
|
|
4408
|
-
issueId,
|
|
4409
|
-
taskId,
|
|
4410
|
-
policy,
|
|
4411
|
-
checkNormalization: {
|
|
4412
|
-
validCheckIds: normalizedChecks.validCheckIds,
|
|
4413
|
-
invalidCheckIds: normalizedChecks.invalidCheckIds,
|
|
4414
|
-
warnings: normalizedChecks.warnings,
|
|
4415
|
-
},
|
|
4416
|
-
task: verifiedTask ? compactTaskView(verifiedTask as unknown as Record<string, unknown>) : undefined,
|
|
4417
|
-
tasks: issueView.tasks.map((entry) => compactTaskView(entry as unknown as Record<string, unknown>)),
|
|
4418
|
-
issue: compactIssueView(issueView as unknown as Record<string, unknown>),
|
|
2095
|
+
return errorResult("TOOL_DISABLED", "configure_github_plugin requires the controller profile");
|
|
2096
|
+
const config = saveGitHubPluginConfig(ctx.repoRoot, {
|
|
2097
|
+
enabled: typeof args.enabled === "boolean" ? args.enabled : undefined,
|
|
2098
|
+
repository: args.clear_repository === true ? "" : typeof args.repository === "string" ? args.repository : undefined,
|
|
2099
|
+
syncMode: args.sync_mode === "checkpoint" ? "checkpoint" : args.sync_mode === "manual" ? "manual" : undefined,
|
|
2100
|
+
includeTasks: typeof args.include_tasks === "boolean" ? args.include_tasks : undefined,
|
|
2101
|
+
projectOwner: args.clear_project === true ? "" : typeof args.project_owner === "string" ? args.project_owner : undefined,
|
|
2102
|
+
projectNumber: args.clear_project === true ? null : typeof args.project_number === "number" ? args.project_number : undefined,
|
|
4419
2103
|
});
|
|
2104
|
+
audit(ctx, name, "ok", args, "repository-registry:github");
|
|
2105
|
+
return textResult(config);
|
|
4420
2106
|
}
|
|
4421
|
-
case "
|
|
4422
|
-
if (ctx.policy.profile !== "controller") return errorResult("TOOL_DISABLED", "accept_task requires the controller profile");
|
|
4423
|
-
const issueId = String(args.issue_id ?? "");
|
|
4424
|
-
const taskId = String(args.task_id ?? "");
|
|
4425
|
-
const current = getIssue(ctx.repoRoot, issueId);
|
|
4426
|
-
const task = current.tasks.find((entry) => entry.id === taskId);
|
|
4427
|
-
if (!task) return errorResult("TASK_NOT_FOUND", `task not found: ${issueId}/${taskId}`);
|
|
4428
|
-
if (task.status === "done") return textResult(projectIssueEffectiveView(ctx.repoRoot, current));
|
|
4429
|
-
if (task.status !== "verified" || !task.verification) return errorResult("TASK_NOT_VERIFIED", `task has not passed its risk-adaptive verification requirements (current: ${task.status})`);
|
|
4430
|
-
const workId = typeof args.work_id === "string" ? args.work_id.trim() : "";
|
|
4431
|
-
const issue = workId
|
|
4432
|
-
? acceptVerifiedTaskFromControllerWork({
|
|
4433
|
-
controllerHome: resolveRepoPreferredControllerHome(ctx.repoRoot),
|
|
4434
|
-
repoId: ctx.repoId ?? String(args.repo_id ?? "").trim(),
|
|
4435
|
-
repoRoot: ctx.repoRoot,
|
|
4436
|
-
issueId,
|
|
4437
|
-
taskId,
|
|
4438
|
-
workId,
|
|
4439
|
-
note: typeof args.note === "string" ? args.note : undefined,
|
|
4440
|
-
}).issue
|
|
4441
|
-
: acceptVerifiedTask(ctx.repoRoot, issueId, taskId, typeof args.note === "string" ? args.note : "Accepted after required verification evidence.");
|
|
4442
|
-
audit(ctx, name, "ok", args, `tasks/issues/${issue.id}`);
|
|
4443
|
-
return textResult(projectIssueEffectiveView(ctx.repoRoot, issue));
|
|
4444
|
-
}
|
|
4445
|
-
case "request_task_changes": {
|
|
2107
|
+
case "github_status": {
|
|
4446
2108
|
if (ctx.policy.profile !== "controller")
|
|
4447
2109
|
return errorResult(
|
|
4448
2110
|
"TOOL_DISABLED",
|
|
4449
|
-
"
|
|
4450
|
-
);
|
|
4451
|
-
const issueId = String(args.issue_id ?? "");
|
|
4452
|
-
const taskId = String(args.task_id ?? "");
|
|
4453
|
-
const current = getIssue(ctx.repoRoot, issueId);
|
|
4454
|
-
const task = current.tasks.find((entry) => entry.id === taskId);
|
|
4455
|
-
if (!task)
|
|
4456
|
-
return errorResult(
|
|
4457
|
-
"TASK_NOT_FOUND",
|
|
4458
|
-
`task not found: ${issueId}/${taskId}`,
|
|
4459
|
-
);
|
|
4460
|
-
if (
|
|
4461
|
-
!["review", "integrated", "verifying", "verified"].includes(
|
|
4462
|
-
task.status,
|
|
4463
|
-
)
|
|
4464
|
-
)
|
|
4465
|
-
return errorResult(
|
|
4466
|
-
"TASK_NOT_REVIEWABLE",
|
|
4467
|
-
`task must be in review, integrated, verifying, or verified before requesting changes (current: ${task.status})`,
|
|
2111
|
+
"github_status requires the controller profile",
|
|
4468
2112
|
);
|
|
4469
|
-
const
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
audit(
|
|
4474
|
-
|
|
2113
|
+
const status = getGitHubStatus(
|
|
2114
|
+
ctx.repoRoot,
|
|
2115
|
+
typeof args.repo === "string" ? args.repo : undefined,
|
|
2116
|
+
);
|
|
2117
|
+
audit(
|
|
2118
|
+
ctx,
|
|
2119
|
+
name,
|
|
2120
|
+
status.available && status.authenticated ? "ok" : "failed",
|
|
2121
|
+
args,
|
|
2122
|
+
status.repository?.nameWithOwner,
|
|
2123
|
+
status.errors.join("; "),
|
|
2124
|
+
);
|
|
2125
|
+
return textResult(status);
|
|
4475
2126
|
}
|
|
4476
2127
|
case "begin_edit_session": {
|
|
4477
2128
|
if (ctx.policy.profile !== "controller")
|
|
@@ -4487,19 +2138,6 @@ export async function callMcpTool(
|
|
|
4487
2138
|
const checks = stringList(args.checks);
|
|
4488
2139
|
const git = gitSnapshot(ctx.repoRoot);
|
|
4489
2140
|
const workspaceIdentity = createHash("sha256").update(JSON.stringify(git)).digest("hex");
|
|
4490
|
-
const routeDecision = decideRoute({
|
|
4491
|
-
intent: {
|
|
4492
|
-
objective: purpose,
|
|
4493
|
-
scopeClear: allowedPaths.length > 0,
|
|
4494
|
-
mutation: true,
|
|
4495
|
-
expectedFiles: typeof args.max_files === "number" ? args.max_files : allowedPaths.length,
|
|
4496
|
-
expectedChangedLines: typeof args.max_changed_lines === "number" ? args.max_changed_lines : undefined,
|
|
4497
|
-
},
|
|
4498
|
-
workspace: { knownPaths: allowedPaths, checkoutId: identity.checkoutId, fingerprint: workspaceIdentity },
|
|
4499
|
-
policy: { risk: "local_repo_write", approvalConfirmed: true },
|
|
4500
|
-
capabilities: {},
|
|
4501
|
-
recovery: {},
|
|
4502
|
-
});
|
|
4503
2141
|
const requestedWorkId = typeof args.work_id === "string" ? args.work_id.trim() : "";
|
|
4504
2142
|
const workId = requestedWorkId || `work-direct-${createHash("sha256").update(`${repoId}\0${purpose}\0${Date.now()}`).digest("hex").slice(0, 16)}`;
|
|
4505
2143
|
const workStore = { controllerHome, repoId };
|
|
@@ -4514,7 +2152,6 @@ export async function callMcpTool(
|
|
|
4514
2152
|
controllerInstanceId: identity.controllerInstanceId,
|
|
4515
2153
|
baseRevision: git.head ?? undefined,
|
|
4516
2154
|
workspaceFingerprint: workspaceIdentity,
|
|
4517
|
-
routeDecision,
|
|
4518
2155
|
objective: purpose,
|
|
4519
2156
|
issueId: typeof args.issue_id === "string" ? args.issue_id : undefined,
|
|
4520
2157
|
taskId: typeof args.task_id === "string" ? args.task_id : undefined,
|
|
@@ -4546,7 +2183,6 @@ export async function callMcpTool(
|
|
|
4546
2183
|
checkoutId: identity.checkoutId,
|
|
4547
2184
|
principalId: identity.principalId,
|
|
4548
2185
|
controllerInstanceId: identity.controllerInstanceId,
|
|
4549
|
-
routeDecisionFingerprint: routeDecision.inputFingerprint,
|
|
4550
2186
|
},
|
|
4551
2187
|
});
|
|
4552
2188
|
audit(
|
|
@@ -4585,7 +2221,6 @@ export async function callMcpTool(
|
|
|
4585
2221
|
checkoutId: identity.checkoutId,
|
|
4586
2222
|
principalId: identity.principalId,
|
|
4587
2223
|
controllerInstanceId: identity.controllerInstanceId,
|
|
4588
|
-
routeDecisionFingerprint: current.routeDecisionFingerprint,
|
|
4589
2224
|
},
|
|
4590
2225
|
},
|
|
4591
2226
|
);
|
|
@@ -4705,7 +2340,6 @@ export async function callMcpTool(
|
|
|
4705
2340
|
checkoutId: identity.checkoutId,
|
|
4706
2341
|
principalId: identity.principalId,
|
|
4707
2342
|
controllerInstanceId: identity.controllerInstanceId,
|
|
4708
|
-
routeDecisionFingerprint: current.routeDecisionFingerprint,
|
|
4709
2343
|
},
|
|
4710
2344
|
},
|
|
4711
2345
|
);
|
|
@@ -4718,29 +2352,6 @@ export async function callMcpTool(
|
|
|
4718
2352
|
);
|
|
4719
2353
|
return textResult(session);
|
|
4720
2354
|
}
|
|
4721
|
-
case "finish_edit_session": {
|
|
4722
|
-
if (ctx.policy.profile !== "controller")
|
|
4723
|
-
return errorResult(
|
|
4724
|
-
"TOOL_DISABLED",
|
|
4725
|
-
"finish_edit_session requires the controller profile",
|
|
4726
|
-
);
|
|
4727
|
-
const sessionId = String(args.session_id ?? "").trim();
|
|
4728
|
-
if (!sessionId) return errorResult("SESSION_ID_REQUIRED", "finish_edit_session requires session_id");
|
|
4729
|
-
const decision = typeof args.decision === "string" ? args.decision : "auto";
|
|
4730
|
-
if (!["auto", "approve_and_finish", "request_changes", "discard"].includes(decision)) {
|
|
4731
|
-
return errorResult("INVALID_DECISION", "decision must be auto, approve_and_finish, request_changes, or discard");
|
|
4732
|
-
}
|
|
4733
|
-
const finished = finishEditSession(ctx.repoRoot, {
|
|
4734
|
-
sessionId,
|
|
4735
|
-
decision: decision as "auto" | "approve_and_finish" | "request_changes" | "discard",
|
|
4736
|
-
reviewer: typeof args.reviewer === "string" ? args.reviewer : undefined,
|
|
4737
|
-
note: typeof args.note === "string" ? args.note : undefined,
|
|
4738
|
-
checkIds: Array.isArray(args.check_ids) ? args.check_ids.map(String) : undefined,
|
|
4739
|
-
commit: typeof args.commit === "boolean" ? args.commit : undefined,
|
|
4740
|
-
});
|
|
4741
|
-
audit(ctx, name, ["blocked", "needs_decision"].includes(finished.action) ? "failed" : "ok", args, `tasks/issues/${finished.issueId}`, finished.reason);
|
|
4742
|
-
return textResult(finished);
|
|
4743
|
-
}
|
|
4744
2355
|
case "list_workflow_files": {
|
|
4745
2356
|
const files = workflowFileCandidates(ctx.repoRoot)
|
|
4746
2357
|
.filter(
|