@moretea-labs/forge 1.5.0-rc.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -11
- package/CHANGELOG.md +19 -0
- package/CLAUDE.md +8 -10
- package/DESIGN.md +278 -0
- package/README.md +70 -90
- package/README.zh-CN.md +50 -55
- package/SKILL.md +8 -11
- package/THIRD_PARTY_NOTICES.md +9 -3
- package/assets/branding/README.md +4 -2
- package/assets/hooks/lib/workflow-state.sh +19 -18
- package/assets/hooks/post-edit-guard.sh +6 -75
- package/assets/hooks/prompt-guard.sh +24 -12
- package/assets/hooks/session-start-context.sh +17 -17
- package/assets/hooks/stop-orchestrator.sh +2 -2
- package/assets/partials/04-project-structure.partial.md +6 -6
- package/assets/partials/05-workflow.partial.md +6 -6
- package/assets/partials/07-footer.partial.md +1 -1
- package/assets/partials/08-orchestration.partial.md +2 -2
- package/assets/partials-agents/02-operating-mode.partial.md +5 -5
- package/assets/partials-agents/03-orchestration.partial.md +3 -3
- package/assets/partials-agents/04-task-protocol.partial.md +3 -3
- package/assets/partials-agents/08-deep-docs.partial.md +1 -1
- package/assets/reference-configs/agentic-development-flow.md +49 -86
- package/assets/reference-configs/external-tooling.md +21 -61
- package/assets/reference-configs/handoff-protocol.md +25 -20
- package/assets/reference-configs/harness-overview.md +8 -8
- package/assets/templates/helpers/archive-workflow.sh +0 -1
- package/assets/templates/helpers/capture-plan.sh +3 -3
- package/assets/templates/helpers/check-task-workflow.sh +2 -2
- package/assets/templates/helpers/codex-handoff-resume.sh +5 -5
- package/assets/templates/helpers/ensure-task-workflow.sh +37 -35
- package/assets/templates/helpers/new-plan.sh +1 -1
- package/assets/templates/helpers/plan-to-todo.sh +2 -2
- package/assets/templates/helpers/prepare-codex-handoff.sh +2 -2
- package/assets/templates/helpers/prepare-handoff.sh +9 -9
- package/assets/templates/helpers/refresh-current-status.sh +2 -2
- package/assets/templates/helpers/ship-worktrees.sh +1 -1
- package/assets/templates/helpers/sprint-backlog.sh +1 -1
- package/assets/templates/helpers/verify-sprint.sh +7 -7
- package/assets/templates/helpers/workstream-sync.sh +1 -1
- package/assets/templates/plan.template.md +1 -1
- package/assets/workflow-contract.v1.json +6 -3
- package/docs/architecture/current/README.md +10 -9
- package/docs/architecture/current/approved-target-architecture.zh-CN.md +2 -2
- package/docs/architecture/current/architecture-invariants.md +2 -2
- package/docs/architecture/current/automation-and-schedule-engine.md +15 -15
- package/docs/architecture/current/codegraph-context-provider.md +2 -2
- package/docs/architecture/current/control-plane-authority-inventory.md +12 -0
- package/docs/architecture/current/dispatch-and-agent-strategy.md +11 -11
- package/docs/architecture/current/entity-model.md +0 -27
- package/docs/architecture/current/failure-recovery.md +0 -24
- package/docs/architecture/current/governance.md +1 -1
- package/docs/architecture/current/implementation-status.md +1 -1
- package/docs/architecture/current/legacy-governance.md +58 -0
- package/docs/architecture/current/multi-repository-execution.md +1 -1
- package/docs/architecture/current/peer-supercontroller-runtime.md +1 -1
- package/docs/architecture/current/personal-assistant-plugin-baseline.md +4 -5
- package/docs/architecture/current/scheduler-and-resource-claims.md +0 -10
- package/docs/architecture/current/target-requirements-traceability.md +2 -2
- package/docs/architecture/current/thin-harness-governance-policy.md +1 -1
- package/docs/architecture/current/thin-harness-v1.md +9 -11
- package/docs/architecture/domains/runtime-harness.md +1 -1
- package/docs/forge-autonomous-goal-loop.md +3 -1
- package/docs/forge-chatgpt-mcp-setup.md +51 -184
- package/docs/images/forge-banner-cn.svg +26 -1
- package/docs/images/forge-banner.svg +26 -1
- package/docs/operations/features.md +1 -1
- package/docs/operations/homebrew.md +3 -3
- package/docs/operations/mcp-tool-exposure.md +5 -5
- package/docs/operations/platform-support.md +45 -37
- package/docs/operations/platform-support.zh-CN.md +40 -38
- package/docs/operations/releasing.md +3 -3
- package/docs/operations/releasing.zh-CN.md +3 -3
- package/docs/operations/troubleshooting.md +11 -6
- package/docs/operations/troubleshooting.zh-CN.md +11 -6
- package/docs/public-usage-guide.md +28 -21
- package/docs/public-usage-guide.zh-CN.md +28 -21
- package/docs/tutorials/01-install-and-start.md +56 -35
- package/docs/tutorials/01-install-and-start.zh-CN.md +56 -35
- package/docs/tutorials/02-connect-chatgpt.md +112 -46
- package/docs/tutorials/02-connect-chatgpt.zh-CN.md +113 -45
- package/docs/wiki/Architecture.md +1 -1
- package/docs/wiki/Installation.md +2 -2
- package/docs/wiki/Quick-Start.md +1 -1
- package/docs/wiki/Work-Lifecycle.md +1 -1
- package/install.ps1 +4 -5
- package/install.sh +4 -6
- package/package.json +15 -5
- package/scripts/archive-workflow.sh +0 -1
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +27 -14
- package/scripts/build-controller-ui.ts +28 -0
- package/scripts/capture-plan.sh +4 -4
- package/scripts/check-agent-tooling.sh +12 -1
- package/scripts/check-platform-support.mjs +2 -2
- package/scripts/check-public-docs.sh +16 -5
- package/scripts/check-release-readiness.sh +5 -11
- package/scripts/check-runtime-architecture.mjs +14 -22
- package/scripts/check-tarball-install-smoke.sh +3 -2
- package/scripts/check-task-workflow.sh +2 -2
- package/scripts/codex-handoff-resume.sh +5 -5
- package/scripts/create-project-dirs.sh +3 -3
- package/scripts/ensure-task-workflow.sh +45 -35
- package/scripts/init-project.sh +4 -4
- package/scripts/install-desktop-operator-registration.ts +2 -2
- package/scripts/lib/project-init-lib.sh +46 -44
- package/scripts/migrate-project-template.sh +7 -4
- package/scripts/new-plan.sh +1 -1
- package/scripts/plan-to-todo.sh +2 -2
- package/scripts/prepare-codex-handoff.sh +2 -2
- package/scripts/prepare-handoff.sh +9 -9
- package/scripts/refresh-current-status.sh +2 -2
- package/scripts/setup-plugins.sh +3 -3
- package/scripts/ship-worktrees.sh +1 -1
- package/scripts/sprint-backlog.sh +5 -5
- package/scripts/sync-codex-installed-copies.sh +2 -3
- package/scripts/verify-sprint.sh +7 -7
- package/scripts/workstream-sync.sh +1 -1
- package/src/cli/chatgpt-browser/bridge-extension.ts +1 -1
- package/src/cli/chatgpt-browser/bridge-provider.ts +29 -0
- package/src/cli/chatgpt-browser/file-policy.ts +3 -1
- package/src/cli/commands/chatgpt.ts +51 -0
- package/src/cli/commands/doctor.ts +1 -1
- package/src/cli/commands/init-hook.ts +211 -70
- package/src/cli/commands/init.ts +5 -6
- package/src/cli/commands/mcp.ts +29 -5
- package/src/cli/commands/runtime.ts +60 -8
- package/src/cli/commands/setup-profile.ts +441 -0
- package/src/cli/controller/check-runner.ts +20 -3
- package/src/cli/controller/codex-continuation.ts +4 -7
- package/src/cli/controller/context-pack.ts +118 -14
- package/src/cli/controller/operational-plan.ts +4 -4
- package/src/cli/controller/task-ledger.ts +10 -10
- package/src/cli/controller/work-mode.ts +6 -13
- package/src/cli/index.ts +14 -35
- package/src/cli/local-bridge/connector-freshness.ts +1 -1
- package/src/cli/local-bridge/console-automations.ts +160 -0
- package/src/cli/local-bridge/dashboard.ts +8 -1303
- package/src/cli/local-bridge/facade-api.ts +16 -7
- package/src/cli/local-bridge/frontend/src/App.tsx +10 -0
- package/src/cli/local-bridge/frontend/src/components/Button.tsx +1 -0
- package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +3 -0
- package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +1 -0
- package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +1 -0
- package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +1 -0
- package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +3 -0
- package/src/cli/local-bridge/frontend/src/design/icons.tsx +11 -0
- package/src/cli/local-bridge/frontend/src/design/tokens.css +8 -0
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +3 -0
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +4 -0
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +3 -0
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +2 -0
- package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +2 -0
- package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +2 -0
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +3 -0
- package/src/cli/local-bridge/frontend/src/lib/api.ts +23 -0
- package/src/cli/local-bridge/frontend/src/lib/format.ts +4 -0
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +7 -0
- package/src/cli/local-bridge/frontend/src/main.tsx +1 -0
- package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +1 -0
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +2 -0
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +3 -0
- package/src/cli/local-bridge/frontend/src/styles.css +12 -0
- package/src/cli/local-bridge/frontend/src/types.ts +14 -0
- package/src/cli/local-bridge/frontend/src/vite-env.d.ts +1 -0
- package/src/cli/local-bridge/frontend/vite.config.ts +27 -0
- package/src/cli/local-bridge/server.ts +44 -0
- package/src/cli/local-bridge/ui-dist/app.css +1 -0
- package/src/cli/local-bridge/ui-dist/app.js +11094 -0
- package/src/cli/mcp/instructions.ts +3 -3
- package/src/cli/mcp/legacy-tool-service.ts +27 -23
- package/src/cli/mcp/multi-repository.ts +2 -0
- package/src/cli/mcp/policy.ts +7 -5
- package/src/cli/mcp/repository-tools.ts +53 -14
- package/src/cli/mcp/server.ts +5 -10
- package/src/cli/mcp/setup.ts +211 -275
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/toolset-names.ts +1 -1
- package/src/cli/mcp/toolset.ts +0 -1
- package/src/cli/mcp/transports/http.ts +24 -4
- package/src/cli/repositories/branch-name-policy.ts +0 -7
- package/src/cli/repositories/controller-home.ts +110 -3
- package/src/cli/repositories/safe-patch.ts +1 -1
- package/src/cli/repositories/selected-path-actions.ts +26 -24
- package/src/core/adoption/gitignore-plan.ts +2 -3
- package/src/core/adoption/plan.ts +4 -1
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +556 -0
- package/src/runtime/control-plane/execution/work-handle-store.ts +128 -1
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +277 -0
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +169 -0
- package/src/runtime/control-plane/facade/capability-registry.ts +0 -10
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +44 -25
- package/src/runtime/control-plane/facade/suggested-actions.ts +7 -1
- package/src/runtime/control-plane/facade/types.ts +0 -1
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +30 -8
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +114 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +175 -0
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +161 -0
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +64 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +117 -24
- package/src/runtime/control-plane/routing/route-policy.ts +14 -14
- package/src/runtime/control-plane/runtime-cleanup.ts +0 -1
- package/src/runtime/evidence/event-ledger.ts +1 -1
- package/src/runtime/{workflow/campaigns/workspace.ts → execution/managed-workspace.ts} +41 -43
- package/src/runtime/execution/process-runtime/check-facade.ts +6 -0
- package/src/runtime/execution/process-runtime/check-result.ts +45 -0
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +42 -16
- package/src/runtime/execution/process-runtime/command-facade.ts +4 -2
- package/src/runtime/execution/process-runtime/gc.ts +1 -1
- package/src/runtime/execution/process-runtime/index.ts +3 -0
- package/src/runtime/execution/process-runtime/interactive-admission.ts +14 -5
- package/src/runtime/execution/process-runtime/persisted-check.ts +285 -0
- package/src/runtime/execution/process-runtime/resource-claims.ts +30 -0
- package/src/runtime/execution/process-runtime/runtime.ts +18 -1
- package/src/runtime/execution/process-runtime/store.ts +1 -19
- package/src/runtime/execution/process-runtime/types.ts +4 -0
- package/src/runtime/execution/thin-harness/execution-router.ts +0 -1
- package/src/runtime/execution/thin-harness/fast-executor.ts +1 -1
- package/src/runtime/execution/thin-harness/lightweight-lanes.ts +1 -2
- package/src/runtime/execution/thin-harness/types.ts +0 -1
- package/src/runtime/execution/workers/executor.ts +1 -1
- package/src/runtime/gateway/mcp/execution-tools.ts +1 -1
- package/src/runtime/gateway/mcp/persisted-check-process.ts +3 -255
- package/src/runtime/gateway/mcp/process-tools.ts +16 -3
- package/src/runtime/gateway/mcp/resource-policy.ts +0 -9
- package/src/runtime/gateway/mcp/router.ts +117 -182
- package/src/runtime/gateway/mcp/runtime-tools.ts +331 -409
- package/src/runtime/gateway/mcp/work-validation-reconciler.ts +1 -219
- package/src/runtime/plugins/browser-adapter.ts +5 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +1 -1
- package/src/runtime/plugins/store.ts +14 -6
- package/src/runtime/plugins/types.ts +1 -1
- package/src/runtime/projections/materialized-view.ts +1 -23
- package/src/runtime/recovery/maintenance-executor.ts +9 -0
- package/src/runtime/resources/ownership.ts +0 -1
- package/src/runtime/root/gateway-adapter.ts +2 -0
- package/src/runtime/root/mcp-transport.ts +10 -2
- package/src/runtime/root/package-runtime-release.ts +161 -0
- package/src/runtime/root/package-runtime-service.ts +172 -0
- package/src/runtime/root/runtime.ts +2 -1
- package/src/runtime/root/scheduler.ts +5 -0
- package/src/runtime/root/service.ts +18 -5
- package/src/runtime/standalone-recovery/core.ts +65 -16
- package/src/runtime/workflow/findings/store.ts +145 -106
- package/src/runtime/workflow/findings/types.ts +22 -0
- package/src/runtime/workflow/schedules/engine.ts +132 -2
- package/src/runtime/workflow/schedules/pending-activation.ts +139 -0
- package/src/runtime/workflow/schedules/work-continuation.ts +218 -0
- package/docs/CHANGELOG.md +0 -978
- package/docs/README.zh-CN.md +0 -58
- package/scripts/smoke-chatgpt-supervised-automation.ts +0 -208
- package/src/cli/commands/controller.ts +0 -680
- package/src/runtime/workflow/campaigns/cleanup.ts +0 -263
- package/src/runtime/workflow/campaigns/engine.ts +0 -112
- package/src/runtime/workflow/campaigns/normalize.ts +0 -100
- package/src/runtime/workflow/campaigns/review.ts +0 -315
- package/src/runtime/workflow/campaigns/store.ts +0 -526
- package/src/runtime/workflow/campaigns/supervisor.ts +0 -112
- package/src/runtime/workflow/campaigns/types.ts +0 -290
- /package/src/runtime/{workflow/campaigns → execution}/workspace-agent.ts +0 -0
package/src/cli/mcp/setup.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { spawnSync } from "child_process";
|
|
1
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
2
3
|
import { isIP } from "net";
|
|
3
|
-
import {
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { dirname, join, relative, resolve } from "path";
|
|
4
6
|
import {
|
|
5
7
|
ensureMcpControllerHomeBearerToken,
|
|
6
8
|
ensureMcpControllerHomeOAuthPassphrase,
|
|
@@ -18,7 +20,6 @@ import { resolveMcpRepoRoot } from "./repo";
|
|
|
18
20
|
import {
|
|
19
21
|
FORGE_TOOL_SURFACE,
|
|
20
22
|
DEFAULT_AGENT_TIMEOUT_MS,
|
|
21
|
-
defaultLocalAgentRunners,
|
|
22
23
|
MAX_AGENT_TIMEOUT_MS,
|
|
23
24
|
} from "../controller/runtime-config";
|
|
24
25
|
import { ensureControllerHome, ensureRepoPreferredControllerHome } from "../repositories/controller-home";
|
|
@@ -35,7 +36,7 @@ export interface McpSetupResult {
|
|
|
35
36
|
const REQUIRED_CODEX_TOOLS = [
|
|
36
37
|
"harness_status",
|
|
37
38
|
"read_workflow_file",
|
|
38
|
-
"
|
|
39
|
+
"latest_session_context",
|
|
39
40
|
"latest_checks",
|
|
40
41
|
"prepare_codex_goal_from_sprint",
|
|
41
42
|
"write_codex_goal",
|
|
@@ -184,265 +185,140 @@ function normalizeChatgptMcpServerName(value: string | undefined): string {
|
|
|
184
185
|
export function chatgptGuideMarkdown(
|
|
185
186
|
endpoint = CHATGPT_MCP_ENDPOINT_PLACEHOLDER,
|
|
186
187
|
): string {
|
|
187
|
-
return `#
|
|
188
|
+
return `# Forge ChatGPT Controller — Low-level Reference
|
|
188
189
|
|
|
189
|
-
|
|
190
|
+
> For normal onboarding, start with \`forge setup\` and [Tutorial 2](tutorials/02-connect-chatgpt.md). This file is the lower-level MCP reference and may also be regenerated by repository-scoped compatibility setup.
|
|
190
191
|
|
|
191
|
-
|
|
192
|
+
## Product model
|
|
192
193
|
|
|
193
|
-
|
|
194
|
+
Forge has no internal AI brain. ChatGPT is one external controller option: ChatGPT decides semantic next steps, while Forge owns bounded execution, durable state, authorization, Runtime lifecycle, and evidence. Codex/Claude are optional and are not enabled merely because they are installed.
|
|
194
195
|
|
|
195
|
-
|
|
196
|
-
- Bun and the \`forge\` CLI on PATH.
|
|
197
|
-
- Codex and/or Claude CLI installed for delegated local execution.
|
|
198
|
-
- GitHub CLI \`gh\` authenticated when GitHub Issues, Projects, or Copilot cloud sessions are used.
|
|
199
|
-
- ChatGPT workspace access to Developer Mode and custom MCP Connectors.
|
|
200
|
-
- A public HTTPS \`/mcp\` endpoint for ChatGPT.
|
|
196
|
+
## Normal package path
|
|
201
197
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
## One-time setup
|
|
205
|
-
|
|
206
|
-
\`\`\`bash
|
|
207
|
-
forge mcp setup chatgpt --repo .
|
|
208
|
-
forge runtime service install \
|
|
209
|
-
--controller-home <absolute-controller-home> \
|
|
210
|
-
--repo <absolute-repo-root> \
|
|
211
|
-
--host 127.0.0.1 \
|
|
212
|
-
--port 8765
|
|
213
|
-
\`\`\`
|
|
214
|
-
|
|
215
|
-
The \`controller\` profile writes the service-level MCP configuration consumed by the single \`forge-runtime\`. The macOS launchd service starts and restarts that one root process; Gateway, Controller Services, Scheduler, and MCP Transport share the same Runtime lifecycle owner. There is no MCP KeepAlive wrapper or component-level lifecycle command.
|
|
216
|
-
|
|
217
|
-
The Runtime endpoint is loopback-only at \`http://127.0.0.1:8765/\`. The local visual controller surface is part of the same Runtime configuration; do not expose it directly.
|
|
218
|
-
|
|
219
|
-
Health check:
|
|
198
|
+
A repository is not required for the user-level ChatGPT connection:
|
|
220
199
|
|
|
221
200
|
\`\`\`bash
|
|
222
|
-
|
|
223
|
-
forge
|
|
224
|
-
forge mcp doctor --repo .
|
|
201
|
+
forge setup configure --controller chatgpt --tunnel auto
|
|
202
|
+
forge setup next
|
|
225
203
|
\`\`\`
|
|
226
204
|
|
|
227
|
-
|
|
205
|
+
The corresponding low-level commands are:
|
|
228
206
|
|
|
229
207
|
\`\`\`bash
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
HTTPS_PROXY= HTTP_PROXY= ALL_PROXY= curl -v https://${CHATGPT_NAMED_TUNNEL_HOST_PLACEHOLDER}/mcp
|
|
208
|
+
forge mcp setup chatgpt --user-level
|
|
209
|
+
forge runtime service install-package
|
|
210
|
+
forge runtime status --json
|
|
234
211
|
\`\`\`
|
|
235
212
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
The controller profile stores service-level MCP config under \`controllerHome/mcp/mcp.local.json\`, including allowed local agents, timeout, endpoint, and \`chatgpt.serverName\`. OAuth credentials live in \`controllerHome/mcp/mcp.oauth.json\`; the bearer fallback lives in \`controllerHome/mcp/mcp.tokens.json\`. Existing repo-local \`.forge/mcp.*\` files remain a legacy fallback.
|
|
213
|
+
The Package Runtime does not require a Forge Git checkout, Bun compilation, CodeGraph, or Standalone Recovery. The older \`forge runtime service install --repo ...\` command is an advanced source/immutable-release path.
|
|
239
214
|
|
|
240
|
-
|
|
215
|
+
## Local boundaries
|
|
241
216
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
Use this Connector URL:
|
|
217
|
+
Forge MCP remains loopback-only, normally at:
|
|
245
218
|
|
|
246
219
|
\`\`\`text
|
|
247
|
-
|
|
220
|
+
http://127.0.0.1:8765/mcp
|
|
248
221
|
\`\`\`
|
|
249
222
|
|
|
250
|
-
|
|
223
|
+
The local Utility Console uses a separate loopback port (normally 8766). Never expose the Utility Console to the internet.
|
|
251
224
|
|
|
252
|
-
|
|
253
|
-
cloudflared tunnel login
|
|
254
|
-
cloudflared tunnel create forge-mcp
|
|
255
|
-
cloudflared tunnel route dns forge-mcp ${CHATGPT_NAMED_TUNNEL_HOST_PLACEHOLDER}
|
|
256
|
-
cloudflared tunnel run forge-mcp
|
|
257
|
-
\`\`\`
|
|
225
|
+
Service-level MCP configuration lives below \`Controller Home/mcp/\`. OAuth credentials and bearer fallback tokens are local secrets and must not be pasted into chat or committed. Repository-specific \`.forge/mcp.policy.json\` can narrow access when a repository is later adopted.
|
|
258
226
|
|
|
259
|
-
|
|
227
|
+
## Remote controller connection
|
|
260
228
|
|
|
261
|
-
|
|
262
|
-
forge mcp setup chatgpt --repo . --endpoint https://${CHATGPT_NAMED_TUNNEL_HOST_PLACEHOLDER}/mcp
|
|
263
|
-
forge runtime service install --controller-home <absolute-controller-home> --repo <absolute-repo-root> --host 127.0.0.1 --port 8765
|
|
264
|
-
\`\`\`
|
|
229
|
+
The setup profile owns the connection choice. Supported paths are:
|
|
265
230
|
|
|
266
|
-
|
|
231
|
+
1. **OpenAI Secure MCP Tunnel** — preferred when the OpenAI organization/workspace has tunnel permission; no public inbound Forge endpoint is required. Forge stores only the non-secret \`tunnel_id\`. The runtime API key remains an \`env:\`/file reference owned by the official \`tunnel-client\`.
|
|
232
|
+
2. **Cloudflare Tunnel** — stable public/internet-reachable HTTPS endpoint.
|
|
233
|
+
3. **Tailscale Funnel** — HTTPS endpoint for compatible Tailscale environments.
|
|
234
|
+
4. **Existing HTTPS** — user-managed reverse proxy/tunnel ending in \`/mcp\`.
|
|
235
|
+
5. **None** — local setup only; remote connectivity can be configured later.
|
|
267
236
|
|
|
268
|
-
|
|
269
|
-
forge mcp setup chatgpt --repo . --endpoint <https-url>/mcp
|
|
270
|
-
\`\`\`
|
|
271
|
-
|
|
272
|
-
The real endpoint stays in ignored local config; the tracked guide stays placeholder-only. The OAuth discovery endpoint includes \`oauth-protected-resource\` metadata.
|
|
273
|
-
|
|
274
|
-
## Create the ChatGPT Connector
|
|
275
|
-
|
|
276
|
-
1. Open ChatGPT Settings and enable Developer Mode.
|
|
277
|
-
2. Create a custom Connector using the server name from \`controllerHome/mcp/mcp.local.json\` under \`chatgpt.serverName\`.
|
|
278
|
-
3. Paste the public HTTPS URL ending in \`/mcp\`.
|
|
279
|
-
4. Configure Connector authentication as OAuth. ChatGPT must use the \`/mcp\` OAuth URL; do not point ChatGPT at \`/mcp-bearer\`.
|
|
280
|
-
5. Scan tools and authorize with the passphrase from \`controllerHome/mcp/mcp.oauth.json\`.
|
|
281
|
-
6. Keep write confirmations enabled.
|
|
282
|
-
7. Re-scan tools after updating forge tool schemas.
|
|
283
|
-
|
|
284
|
-
### Grok and other OAuth MCP clients
|
|
285
|
-
|
|
286
|
-
Current Grok custom connectors support OAuth dynamic client registration + PKCE. Use the same canonical endpoint as ChatGPT:
|
|
287
|
-
|
|
288
|
-
\`\`\`text
|
|
289
|
-
<https-tunnel-url>/mcp
|
|
290
|
-
\`\`\`
|
|
291
|
-
|
|
292
|
-
Do not use the legacy \/mcp-grok route for new connectors. Grok's current OAuth callback is \/connectors-oauth-exchange-code\/ on grok.com; forge accepts that callback through dynamic registration or its public-client fallback.
|
|
293
|
-
|
|
294
|
-
### Non-OAuth MCP clients
|
|
237
|
+
For OpenAI Secure MCP Tunnel, setup uses the official supervised runtime surface and considers it ready only when \`tunnel-client runtimes status forge --json\` reports the runtime running, healthy, and ready.
|
|
295
238
|
|
|
296
|
-
|
|
239
|
+
For public HTTPS paths, the configured connector URL is:
|
|
297
240
|
|
|
298
241
|
\`\`\`text
|
|
299
|
-
|
|
242
|
+
${endpoint}
|
|
300
243
|
\`\`\`
|
|
301
244
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
## Verify the loaded tool surface
|
|
305
|
-
|
|
306
|
-
Default \`--toolset core\` and \`--toolset advanced\` expose the same bounded 20-tool ChatGPT surface: the five \`rh_*\` facades (with code retrieval routed through \`rh_context.search\`) plus repository selection, \`repository_command_execute\`, exact source read, safe patch, \`run_check\`, one typed \`plugin_action_execute\` dispatcher (action schemas via \`rh_context\`), managed process lifecycle, result retrieval, and approval resolution. Use \`--toolset full\` for exhaustive legacy compatibility, which keeps every atomic handler (including Git) registered. Confirm all five \`rh_*\` tools appear after connect. If only legacy planning tools are visible, refresh or recreate the Connector so ChatGPT reloads the MCP tool schema.
|
|
307
|
-
|
|
308
|
-
## Refresh newly added repository tools
|
|
309
|
-
|
|
310
|
-
For the current repository only, prefer a bounded local restart:
|
|
245
|
+
Record a stable endpoint with:
|
|
311
246
|
|
|
312
247
|
\`\`\`bash
|
|
313
|
-
|
|
248
|
+
forge setup configure --controller chatgpt --tunnel existing --endpoint https://forge.example.com/mcp
|
|
314
249
|
\`\`\`
|
|
315
250
|
|
|
316
|
-
|
|
251
|
+
Forge synchronizes an explicitly recorded endpoint into the user-level ChatGPT MCP configuration. A configured URL is not proof of live end-to-end connectivity; verify from ChatGPT with a real tool call.
|
|
317
252
|
|
|
318
|
-
|
|
253
|
+
## ChatGPT-side setup
|
|
319
254
|
|
|
320
|
-
|
|
255
|
+
ChatGPT developer-mode/MCP availability is controlled by the current ChatGPT plan and workspace policy. Follow OpenAI's current developer-mode documentation; Forge cannot bypass plan, administrator, RBAC, or tool-action restrictions.
|
|
321
256
|
|
|
322
|
-
|
|
257
|
+
- With **Secure MCP Tunnel**, create the ChatGPT app/connector using the Tunnel connection and the tunnel ID.
|
|
258
|
+
- With **HTTPS**, use the stable URL ending in \`/mcp\` and Forge's OAuth flow.
|
|
259
|
+
- Refresh/scan tools after Forge tool definitions change.
|
|
323
260
|
|
|
324
|
-
|
|
325
|
-
Use forge as the project controller. Read project_snapshot, current Issues, active Runs, and relevant code before deciding the next action. Keep work in small dependency-aware Tasks. Do not dispatch one large Issue as one agent run.
|
|
326
|
-
\`\`\`
|
|
327
|
-
|
|
328
|
-
Typical requests:
|
|
329
|
-
|
|
330
|
-
\`\`\`text
|
|
331
|
-
Analyze this requirement and the current implementation. Create or update an Issue and split it into executable Tasks. Do not execute yet.
|
|
332
|
-
\`\`\`
|
|
261
|
+
The bounded default surface intentionally exposes the preferred \`rh_*\` facade plus repository/source/check/process/plugin escape hatches. Do not switch to exhaustive compatibility mode merely to see more tool names.
|
|
333
262
|
|
|
334
|
-
|
|
335
|
-
Inspect readiness for this Issue, publish it to GitHub when collaboration is useful, and launch at most two independent Tasks. Review every local diff or GitHub pull request and record verification evidence before accepting it.
|
|
336
|
-
\`\`\`
|
|
263
|
+
## Verify
|
|
337
264
|
|
|
338
|
-
|
|
339
|
-
Read the project board and failed Runs. Retry only the smallest failed Task, or re-plan the Issue when the original split is wrong.
|
|
340
|
-
\`\`\`
|
|
265
|
+
Local Runtime:
|
|
341
266
|
|
|
342
|
-
\`\`\`
|
|
343
|
-
|
|
267
|
+
\`\`\`bash
|
|
268
|
+
forge runtime status --json
|
|
269
|
+
forge mcp doctor
|
|
344
270
|
\`\`\`
|
|
345
271
|
|
|
346
|
-
|
|
272
|
+
Then verify from the selected external controller:
|
|
347
273
|
|
|
348
274
|
\`\`\`text
|
|
349
|
-
|
|
350
|
-
-> Task T1
|
|
351
|
-
-> Run 1
|
|
352
|
-
-> Run 2 (retry)
|
|
353
|
-
-> Task T2
|
|
354
|
-
-> Task T3
|
|
355
|
-
\`\`\`
|
|
356
|
-
|
|
357
|
-
- Issues and Tasks are stored under \`tasks/issues/\` as JSON plus readable Markdown.
|
|
358
|
-
- Agent jobs, logs, edit backups, and worktrees are stored under ignored \`.ai/harness/\` runtime directories.
|
|
359
|
-
- A completed isolated agent Run moves its Task to review. ChatGPT must inspect it with \`get_task_diff\`, integrate it with \`integrate_task_run\`, record named-check and criterion evidence through \`verify_task\`, then explicitly accept it or request changes.
|
|
360
|
-
- Dependency completion unlocks later Tasks automatically.
|
|
361
|
-
- Any new ChatGPT conversation can recover state through \`project_snapshot\` and \`get_project_board\`.
|
|
362
|
-
|
|
363
|
-
## Capability boundaries
|
|
364
|
-
|
|
365
|
-
- \`observe\`: inspect repository state, search code, and read bounded file ranges.
|
|
366
|
-
- \`manage\`: create Issues, dynamically split Tasks, inspect launch readiness, publish to GitHub Issues/Projects, update status, and maintain project documents.
|
|
367
|
-
- \`edit\`: use a bounded edit session with allowed paths, SHA preconditions, change limits, backups, and rollback.
|
|
368
|
-
- \`execute\`: dispatch a ready Task to an allowed local agent in an isolated worktree or to a visible GitHub Copilot cloud session.
|
|
369
|
-
- Protected operations such as secrets, Git internals, package lockfiles, CI workflow changes, commits, merges, and pushes are not default controller actions.
|
|
370
|
-
|
|
371
|
-
Kernel-managed Agent goals and persistent Task Runs are retired. New work uses
|
|
372
|
-
\`rh_work\` to create or continue a WorkContract, \`rh_work.controller_claim\` to
|
|
373
|
-
establish ownership, and \`rh_work.launcher_start\` to begin an external
|
|
374
|
-
SuperController session.
|
|
375
|
-
|
|
376
|
-
## Dev Mode Agent Runner
|
|
377
|
-
|
|
378
|
-
Local Agent execution is opt-in. GitHub cloud sessions use authenticated \`gh\` and do not require the local dev runner:
|
|
379
|
-
|
|
380
|
-
The runner is enabled through the service-level MCP configuration written by \`forge mcp setup chatgpt\` (\`devMode.agentRunner\` and \`devMode.allowedAgents\`). It executes inside the single Forge Runtime's bounded worker processes; there is no separate \`forge mcp serve\` lifecycle to supervise.
|
|
381
|
-
|
|
382
|
-
The runner defaults to 60 minutes per local Task and supports explicit values up to 12 hours. Requested values are validated and persisted unchanged; an invalid value fails instead of silently falling back to 120 seconds.
|
|
383
|
-
|
|
384
|
-
The runner:
|
|
385
|
-
|
|
386
|
-
- accepts only configured \`codex\` or \`claude\` agents;
|
|
387
|
-
- creates one persistent Run per Task;
|
|
388
|
-
- normally creates an isolated Git worktree;
|
|
389
|
-
- records prompt, process metadata, streaming stdout/stderr, structured events, and result under \`.ai/harness/jobs/\`;
|
|
390
|
-
- never exposes arbitrary shell input through MCP;
|
|
391
|
-
- does not commit, merge, or push automatically.
|
|
392
|
-
|
|
393
|
-
Watch local or GitHub execution from a terminal:
|
|
394
|
-
|
|
395
|
-
\`\`\`bash
|
|
396
|
-
forge controller runs --repo .
|
|
397
|
-
forge controller watch <RUN-ID> --repo . --log
|
|
275
|
+
Use Forge. Call rh_status and report whether the Runtime is ready. Do not modify anything yet.
|
|
398
276
|
\`\`\`
|
|
399
277
|
|
|
400
|
-
|
|
278
|
+
A successful controller-to-Forge tool call is the meaningful end-to-end setup milestone.
|
|
401
279
|
|
|
402
|
-
##
|
|
280
|
+
## Optional controller entries
|
|
403
281
|
|
|
404
|
-
|
|
282
|
+
Codex and Claude are configured only when explicitly selected:
|
|
405
283
|
|
|
406
284
|
\`\`\`bash
|
|
407
|
-
forge mcp setup codex --
|
|
285
|
+
forge mcp setup codex --scope user --profile controller
|
|
286
|
+
forge mcp setup claude --scope user --profile controller
|
|
408
287
|
\`\`\`
|
|
409
288
|
|
|
410
|
-
|
|
289
|
+
Multiple controller entries may coexist, while one external controller remains the semantic owner at a time.
|
|
411
290
|
|
|
412
|
-
##
|
|
291
|
+
## Advanced source/Recovery path
|
|
413
292
|
|
|
414
|
-
|
|
415
|
-
- Keep the MCP server bound to loopback; expose it only through the authenticated tunnel.
|
|
416
|
-
- Do not remove immutable hard-deny patterns in order to make a Task pass.
|
|
417
|
-
- Review every completed local diff or GitHub pull request and record passing Verification Gate evidence before accepting a Task.
|
|
418
|
-
- Use the smallest allowed path set and focused checks for direct edits.
|
|
419
|
-
|
|
420
|
-
## Troubleshooting
|
|
421
|
-
|
|
422
|
-
- ChatGPT cannot connect: verify the HTTPS tunnel ends in \`/mcp\` and local \`/ready\` responds.
|
|
423
|
-
- Grok cannot connect: recreate it with the canonical \`…/mcp\` URL. The legacy \`…/mcp-grok\` URL is compatibility-only.
|
|
424
|
-
- A genuinely non-OAuth client loops on \`/authorize\`: use \`…/mcp-bearer\` with a bearer token from \`controllerHome/mcp/mcp.tokens.json\`.
|
|
425
|
-
- ChatGPT auth loops: retry authorization and inspect \`controllerHome/mcp/mcp.oauth.json\` first, then legacy \`.forge/mcp.oauth.json\` only when using fallback; do not paste the passphrase into chat.
|
|
426
|
-
- Tool scan misses tools: restart the Forge Runtime service with \`launchctl kickstart -k gui/$(id -u)/com.moretea.forge.runtime.<controller-home-suffix>\`, then rescan or recreate the versioned Connector and verify \`controller_capabilities.expectedTools\` includes \`repository_latest_source_diagnose\` and \`repository_bootstrap_local_project\`.
|
|
427
|
-
- Codex cannot see the MCP server: rerun \`forge mcp setup codex --repo . --scope project\`.
|
|
428
|
-
- A quick tunnel URL changed: update the Connector URL or switch to a named tunnel.
|
|
429
|
-
- A Task is blocked: inspect \`get_task_run\`, shrink or re-plan the Task, then retry that Task rather than redispatching the full Issue.
|
|
293
|
+
Maintainers who intentionally need immutable Git/source releases and independent disaster recovery may use the source Runtime and Standalone Recovery documentation. Those mechanisms are not required by ordinary npm/package users and are deliberately excluded from normal setup.
|
|
430
294
|
`;
|
|
431
295
|
}
|
|
432
296
|
|
|
433
297
|
export function runMcpSetupChatgpt(opts: {
|
|
434
298
|
repo?: string;
|
|
299
|
+
controllerHome?: string;
|
|
300
|
+
userLevel?: boolean;
|
|
435
301
|
host?: string;
|
|
436
302
|
port?: string;
|
|
437
303
|
endpoint?: string;
|
|
438
304
|
serverName?: string;
|
|
305
|
+
localControllerPort?: string;
|
|
439
306
|
}): McpSetupResult {
|
|
440
307
|
const repoRoot = resolveMcpRepoRoot(opts.repo ?? ".");
|
|
441
|
-
const controllerHome =
|
|
308
|
+
const controllerHome = opts.userLevel
|
|
309
|
+
? ensureControllerHome(opts.controllerHome)
|
|
310
|
+
: ensureRepoPreferredControllerHome(repoRoot, opts.controllerHome);
|
|
442
311
|
const changed: string[] = [];
|
|
443
312
|
const existingConfig = loadMcpServiceLocalConfig(controllerHome, repoRoot);
|
|
444
313
|
const host = opts.host ?? existingConfig?.server?.host ?? "127.0.0.1";
|
|
445
314
|
const port = opts.port ?? String(existingConfig?.server?.port ?? 8765);
|
|
315
|
+
const parsedPort = Number(port);
|
|
316
|
+
if (!Number.isInteger(parsedPort) || parsedPort < 1 || parsedPort > 65_535) throw new Error(`forge mcp setup chatgpt: invalid port ${port}`);
|
|
317
|
+
const localControllerPort = opts.localControllerPort !== undefined
|
|
318
|
+
? Number(opts.localControllerPort)
|
|
319
|
+
: existingConfig?.localController?.port ?? (parsedPort < 65_535 ? parsedPort + 1 : 8766);
|
|
320
|
+
if (!Number.isInteger(localControllerPort) || localControllerPort < 1 || localControllerPort > 65_535) throw new Error(`forge mcp setup chatgpt: invalid Local Controller port ${opts.localControllerPort}`);
|
|
321
|
+
if (localControllerPort === parsedPort) throw new Error('forge mcp setup chatgpt: Local Controller port must differ from MCP port');
|
|
446
322
|
const existingServerName = existingConfig?.chatgpt?.serverName;
|
|
447
323
|
const migratedServerName =
|
|
448
324
|
existingServerName && !LEGACY_DEFAULT_SERVER_NAMES.has(existingServerName)
|
|
@@ -455,7 +331,7 @@ export function runMcpSetupChatgpt(opts: {
|
|
|
455
331
|
opts.endpoint ?? existingConfig?.chatgpt?.endpoint,
|
|
456
332
|
);
|
|
457
333
|
const configPath = mcpControllerHomeLocalConfigPath(controllerHome);
|
|
458
|
-
const guidePath = join(repoRoot, "docs", "forge-chatgpt-mcp-setup.md");
|
|
334
|
+
const guidePath = opts.userLevel ? undefined : join(repoRoot, "docs", "forge-chatgpt-mcp-setup.md");
|
|
459
335
|
const token = ensureMcpControllerHomeBearerToken(controllerHome);
|
|
460
336
|
const oauth = ensureMcpControllerHomeOAuthPassphrase(controllerHome);
|
|
461
337
|
if (token.changed) changed.push(token.path);
|
|
@@ -464,11 +340,11 @@ export function runMcpSetupChatgpt(opts: {
|
|
|
464
340
|
const toolset = migratedToolset.toolset;
|
|
465
341
|
const config = {
|
|
466
342
|
version: Math.max(existingConfig?.version ?? 1, 2),
|
|
467
|
-
repo: repoRoot,
|
|
343
|
+
...(opts.userLevel ? (existingConfig?.repo ? { repo: existingConfig.repo } : {}) : { repo: repoRoot }),
|
|
468
344
|
server: {
|
|
469
345
|
...existingConfig?.server,
|
|
470
346
|
host,
|
|
471
|
-
port:
|
|
347
|
+
port: parsedPort,
|
|
472
348
|
transport: existingConfig?.server?.transport ?? "http",
|
|
473
349
|
},
|
|
474
350
|
auth: existingConfig?.auth ?? {
|
|
@@ -488,16 +364,22 @@ export function runMcpSetupChatgpt(opts: {
|
|
|
488
364
|
?? accessModeForLegacyToolset(existingConfig?.toolset ?? toolset),
|
|
489
365
|
accessModeUpdatedAt: existingConfig?.accessModeUpdatedAt,
|
|
490
366
|
accessModeRevision: existingConfig?.accessModeRevision ?? 0,
|
|
491
|
-
localController: existingConfig?.
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
367
|
+
localController: opts.userLevel && !existingConfig?.repo
|
|
368
|
+
? {
|
|
369
|
+
enabled: false,
|
|
370
|
+
host: existingConfig?.localController?.host ?? "127.0.0.1",
|
|
371
|
+
port: localControllerPort,
|
|
372
|
+
autoOpen: false,
|
|
373
|
+
mode: "disabled",
|
|
374
|
+
}
|
|
375
|
+
: {
|
|
376
|
+
...(existingConfig?.localController ?? { enabled: true, host: "127.0.0.1", autoOpen: false }),
|
|
377
|
+
port: localControllerPort,
|
|
378
|
+
},
|
|
497
379
|
devMode: {
|
|
498
380
|
...existingConfig?.devMode,
|
|
499
|
-
agentRunner: existingConfig?.devMode?.agentRunner ??
|
|
500
|
-
allowedAgents: existingConfig?.devMode?.allowedAgents ??
|
|
381
|
+
agentRunner: existingConfig?.devMode?.agentRunner ?? false,
|
|
382
|
+
allowedAgents: existingConfig?.devMode?.allowedAgents ?? [],
|
|
501
383
|
timeoutMs:
|
|
502
384
|
!existingConfig?.devMode?.timeoutMs ||
|
|
503
385
|
existingConfig.devMode.timeoutMs === 120_000
|
|
@@ -512,105 +394,116 @@ export function runMcpSetupChatgpt(opts: {
|
|
|
512
394
|
`${JSON.stringify(config, null, 2)}\n`,
|
|
513
395
|
changed,
|
|
514
396
|
);
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
397
|
+
if (guidePath) {
|
|
398
|
+
writeFileIfChanged(guidePath, chatgptGuideMarkdown(), changed);
|
|
399
|
+
ensureGitignoreEntries(
|
|
400
|
+
repoRoot,
|
|
401
|
+
[
|
|
402
|
+
".forge/mcp.local.json",
|
|
403
|
+
".forge/mcp.tokens.json",
|
|
404
|
+
".forge/mcp.oauth.json",
|
|
405
|
+
".forge/mcp.oauth-tokens.json",
|
|
406
|
+
".forge/mcp.runtime.json",
|
|
407
|
+
".ai/harness/mcp/audit.log",
|
|
408
|
+
".ai/harness/local-jobs/",
|
|
409
|
+
".ai/harness/controller/",
|
|
410
|
+
],
|
|
411
|
+
changed,
|
|
412
|
+
);
|
|
413
|
+
}
|
|
530
414
|
|
|
531
415
|
return {
|
|
532
416
|
status: "ok",
|
|
533
417
|
repoRoot,
|
|
534
418
|
changed,
|
|
535
419
|
lines: [
|
|
536
|
-
`[forge mcp] Repo: ${repoRoot}`,
|
|
420
|
+
opts.userLevel ? `[forge mcp] Scope: user (${controllerHome})` : `[forge mcp] Repo: ${repoRoot}`,
|
|
537
421
|
"[forge mcp] Profile: controller",
|
|
538
422
|
`[forge mcp] Toolset: ${config.toolset}`,
|
|
539
423
|
`[forge mcp] ChatGPT MCP server name: ${serverName}`,
|
|
540
424
|
`[forge mcp] Local endpoint: http://${host}:${port}/mcp`,
|
|
541
425
|
`[forge mcp] Local Controller: http://${config.localController.host}:${config.localController.port}/`,
|
|
542
|
-
`[forge mcp]
|
|
426
|
+
`[forge mcp] Optional external delegation: ${config.devMode.agentRunner ? `enabled (${config.devMode.allowedAgents.join(',') || 'none'})` : 'disabled'}`,
|
|
543
427
|
endpoint
|
|
544
428
|
? `[forge mcp] ChatGPT endpoint: ${endpoint}`
|
|
545
429
|
: "[forge mcp] ChatGPT endpoint: requires stable HTTPS tunnel",
|
|
546
430
|
`[forge mcp] Auth: OAuth passphrase (${relative(repoRoot, oauth.path)})`,
|
|
547
431
|
`[forge mcp] Bearer fallback token: ${relative(repoRoot, token.path)}`,
|
|
548
432
|
`[forge mcp] Config: ${relative(repoRoot, configPath)}`,
|
|
549
|
-
`[forge mcp] Guide: ${relative(repoRoot, guidePath)} (generic; endpoint stays in ignored local config)
|
|
550
|
-
`[forge mcp] Runtime state: ${
|
|
551
|
-
|
|
433
|
+
...(guidePath ? [`[forge mcp] Guide: ${relative(repoRoot, guidePath)} (generic; endpoint stays in ignored local config)`] : []),
|
|
434
|
+
`[forge mcp] Runtime state: ${mcpControllerHomeRuntimeStatePath(controllerHome)}`,
|
|
435
|
+
opts.userLevel
|
|
436
|
+
? 'Next: forge setup next'
|
|
437
|
+
: `Next: forge runtime service install-package --controller-home ${controllerHome} --host ${host} --port ${port}`,
|
|
552
438
|
],
|
|
553
439
|
};
|
|
554
440
|
}
|
|
555
441
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
"
|
|
572
|
-
"
|
|
573
|
-
"
|
|
574
|
-
"
|
|
575
|
-
"
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
442
|
+
type LocalControllerProfile = 'controller' | 'executor';
|
|
443
|
+
|
|
444
|
+
function localControllerProfile(value: string | undefined, label: string, fallback: LocalControllerProfile): LocalControllerProfile {
|
|
445
|
+
const normalized = (value ?? fallback).trim().toLowerCase();
|
|
446
|
+
if (normalized !== 'controller' && normalized !== 'executor') {
|
|
447
|
+
throw new Error(`${label}: expected controller|executor`);
|
|
448
|
+
}
|
|
449
|
+
return normalized;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export function codexMcpBlock(profile: LocalControllerProfile = 'executor'): string {
|
|
453
|
+
const lines = [
|
|
454
|
+
'[mcp_servers.forge]',
|
|
455
|
+
'command = "forge"',
|
|
456
|
+
'args = [',
|
|
457
|
+
' "mcp",',
|
|
458
|
+
' "serve",',
|
|
459
|
+
' "--repo",',
|
|
460
|
+
' ".",',
|
|
461
|
+
' "--transport",',
|
|
462
|
+
' "stdio",',
|
|
463
|
+
' "--profile",',
|
|
464
|
+
` "${profile}"`,
|
|
465
|
+
']',
|
|
466
|
+
];
|
|
467
|
+
if (profile === 'executor') {
|
|
468
|
+
lines.push(
|
|
469
|
+
'enabled_tools = [',
|
|
470
|
+
...REQUIRED_CODEX_TOOLS.map((tool) => ` "${tool}",`),
|
|
471
|
+
']',
|
|
472
|
+
'default_tools_approval_mode = "prompt"',
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
return `${lines.join('\n')}\n`;
|
|
476
|
+
}
|
|
579
477
|
|
|
580
|
-
export function patchCodexConfigToml(current: string): string {
|
|
478
|
+
export function patchCodexConfigToml(current: string, profile: LocalControllerProfile = 'executor'): string {
|
|
479
|
+
const block = codexMcpBlock(profile);
|
|
581
480
|
const normalized = current.trimEnd();
|
|
582
481
|
const blockPattern = /\n?\[mcp_servers\.forge\][\s\S]*?(?=\n\[|$)/;
|
|
583
|
-
const prefix = normalized.length > 0 ? `${normalized}\n\n` :
|
|
584
|
-
if (!blockPattern.test(normalized)) return `${prefix}${
|
|
585
|
-
return `${normalized.replace(blockPattern, `\n${
|
|
482
|
+
const prefix = normalized.length > 0 ? `${normalized}\n\n` : '';
|
|
483
|
+
if (!blockPattern.test(normalized)) return `${prefix}${block}`;
|
|
484
|
+
return `${normalized.replace(blockPattern, `\n${block}`.trimEnd())}\n`;
|
|
586
485
|
}
|
|
587
486
|
|
|
588
487
|
export function runMcpSetupCodex(opts: {
|
|
589
488
|
repo?: string;
|
|
590
489
|
scope?: string;
|
|
490
|
+
profile?: string;
|
|
591
491
|
dryRun?: boolean;
|
|
592
492
|
}): McpSetupResult {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
);
|
|
493
|
+
const scope = (opts.scope ?? 'project').trim().toLowerCase();
|
|
494
|
+
if (scope !== 'project' && scope !== 'user') {
|
|
495
|
+
throw new Error('forge mcp setup codex --scope: expected project|user');
|
|
597
496
|
}
|
|
598
|
-
const
|
|
599
|
-
const
|
|
497
|
+
const profile = localControllerProfile(opts.profile, 'forge mcp setup codex --profile', 'executor');
|
|
498
|
+
const repoRoot = resolveMcpRepoRoot(opts.repo ?? '.');
|
|
499
|
+
const configPath = scope === 'user' ? join(homedir(), '.codex', 'config.toml') : join(repoRoot, '.codex', 'config.toml');
|
|
600
500
|
const changed: string[] = [];
|
|
601
|
-
const current = existsSync(configPath)
|
|
602
|
-
|
|
603
|
-
: "";
|
|
604
|
-
const next = patchCodexConfigToml(current);
|
|
501
|
+
const current = existsSync(configPath) ? readFileSync(configPath, 'utf-8') : '';
|
|
502
|
+
const next = patchCodexConfigToml(current, profile);
|
|
605
503
|
if (opts.dryRun === true) {
|
|
606
504
|
return {
|
|
607
|
-
status:
|
|
608
|
-
repoRoot,
|
|
609
|
-
changed: [],
|
|
610
|
-
lines: [
|
|
611
|
-
`[forge mcp] Dry run: would patch ${relative(repoRoot, configPath)}`,
|
|
612
|
-
next,
|
|
613
|
-
],
|
|
505
|
+
status: 'ok', repoRoot, changed: [],
|
|
506
|
+
lines: [`[forge mcp] Dry run: would patch ${scope === 'user' ? configPath : relative(repoRoot, configPath)}`, next],
|
|
614
507
|
};
|
|
615
508
|
}
|
|
616
509
|
if (existsSync(configPath) && current !== next) {
|
|
@@ -619,13 +512,56 @@ export function runMcpSetupCodex(opts: {
|
|
|
619
512
|
}
|
|
620
513
|
writeFileIfChanged(configPath, next, changed);
|
|
621
514
|
return {
|
|
622
|
-
status:
|
|
623
|
-
|
|
624
|
-
|
|
515
|
+
status: 'ok', repoRoot, changed,
|
|
516
|
+
lines: [
|
|
517
|
+
`[forge mcp] Codex config: ${scope === 'user' ? configPath : relative(repoRoot, configPath)}`,
|
|
518
|
+
'[forge mcp] Server: forge',
|
|
519
|
+
'[forge mcp] Transport: stdio',
|
|
520
|
+
`[forge mcp] Role: external ${profile === 'controller' ? 'primary controller' : 'executor/delegate'}`,
|
|
521
|
+
],
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
export function claudeMcpSetupCommand(repoRoot: string, profile: LocalControllerProfile = 'controller', scope = 'user'): string[] {
|
|
526
|
+
return [
|
|
527
|
+
'claude', 'mcp', 'add', 'forge', '--scope', scope, '--',
|
|
528
|
+
'forge', 'mcp', 'serve', '--repo', repoRoot, '--transport', 'stdio', '--profile', profile,
|
|
529
|
+
];
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
export function runMcpSetupClaude(opts: {
|
|
533
|
+
repo?: string;
|
|
534
|
+
scope?: string;
|
|
535
|
+
profile?: string;
|
|
536
|
+
dryRun?: boolean;
|
|
537
|
+
}): McpSetupResult {
|
|
538
|
+
const repoRoot = resolveMcpRepoRoot(opts.repo ?? '.');
|
|
539
|
+
const scope = (opts.scope ?? 'user').trim().toLowerCase();
|
|
540
|
+
if (!['local', 'project', 'user'].includes(scope)) {
|
|
541
|
+
throw new Error('forge mcp setup claude --scope: expected local|project|user');
|
|
542
|
+
}
|
|
543
|
+
const profile = localControllerProfile(opts.profile, 'forge mcp setup claude --profile', 'controller');
|
|
544
|
+
const command = claudeMcpSetupCommand(scope === 'user' ? '.' : repoRoot, profile, scope);
|
|
545
|
+
if (opts.dryRun === true) {
|
|
546
|
+
return {
|
|
547
|
+
status: 'ok', repoRoot, changed: [],
|
|
548
|
+
lines: [`[forge mcp] Dry run: ${command.join(' ')}`],
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
const result = spawnSync(command[0], command.slice(1), { cwd: repoRoot, encoding: 'utf8', timeout: 30_000 });
|
|
552
|
+
if (result.error && (result.error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
553
|
+
throw new Error('Claude Code CLI is not installed. Install/authenticate Claude only if you selected it as a Forge controller.');
|
|
554
|
+
}
|
|
555
|
+
if (result.status !== 0) {
|
|
556
|
+
throw new Error(`Claude MCP configuration failed (${result.status ?? 'unknown'}): ${(result.stderr || result.stdout || result.error?.message || '').trim()}`);
|
|
557
|
+
}
|
|
558
|
+
return {
|
|
559
|
+
status: 'ok', repoRoot, changed: [],
|
|
625
560
|
lines: [
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
561
|
+
'[forge mcp] Claude Code MCP server configured through the Claude CLI.',
|
|
562
|
+
`[forge mcp] Scope: ${scope}`,
|
|
563
|
+
`[forge mcp] Role: external ${profile === 'controller' ? 'primary controller' : 'executor/delegate'}`,
|
|
564
|
+
'[forge mcp] Verify: claude mcp get forge',
|
|
629
565
|
],
|
|
630
566
|
};
|
|
631
567
|
}
|
|
@@ -709,7 +645,7 @@ export function runMcpDoctor(opts: {
|
|
|
709
645
|
},
|
|
710
646
|
devMode: {
|
|
711
647
|
agentRunner: localConfig?.devMode?.agentRunner === true,
|
|
712
|
-
allowedAgents: localConfig?.devMode?.allowedAgents ??
|
|
648
|
+
allowedAgents: localConfig?.devMode?.allowedAgents ?? [],
|
|
713
649
|
timeoutMs: localConfig?.devMode?.timeoutMs ?? DEFAULT_AGENT_TIMEOUT_MS,
|
|
714
650
|
maxTimeoutMs:
|
|
715
651
|
localConfig?.devMode?.maxTimeoutMs ?? MAX_AGENT_TIMEOUT_MS,
|