@moretea-labs/forge 1.5.0-rc.1 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -11
- package/CHANGELOG.md +27 -1
- package/CLAUDE.md +8 -10
- package/DESIGN.md +278 -0
- package/README.md +70 -90
- package/README.zh-CN.md +52 -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/skill-version.json +2 -2
- 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 +67 -176
- 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 +58 -35
- package/docs/tutorials/01-install-and-start.zh-CN.md +58 -35
- package/docs/tutorials/02-connect-chatgpt.md +118 -46
- package/docs/tutorials/02-connect-chatgpt.zh-CN.md +119 -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 +213 -70
- package/src/cli/commands/init.ts +5 -6
- package/src/cli/commands/mcp.ts +31 -5
- package/src/cli/commands/runtime.ts +61 -8
- package/src/cli/commands/setup-profile.ts +472 -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-assets.ts +17 -0
- 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 +45 -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/auth.ts +2 -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 +220 -276
- 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 +51 -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-connector-service.ts +136 -0
- package/src/runtime/root/package-runtime-release.ts +161 -0
- package/src/runtime/root/package-runtime-service.ts +185 -0
- package/src/runtime/root/release-materialize.ts +19 -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,146 @@ 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;
|
|
306
|
+
connectorPort?: string;
|
|
439
307
|
}): McpSetupResult {
|
|
440
308
|
const repoRoot = resolveMcpRepoRoot(opts.repo ?? ".");
|
|
441
|
-
const controllerHome =
|
|
309
|
+
const controllerHome = opts.userLevel
|
|
310
|
+
? ensureControllerHome(opts.controllerHome)
|
|
311
|
+
: ensureRepoPreferredControllerHome(repoRoot, opts.controllerHome);
|
|
442
312
|
const changed: string[] = [];
|
|
443
313
|
const existingConfig = loadMcpServiceLocalConfig(controllerHome, repoRoot);
|
|
444
314
|
const host = opts.host ?? existingConfig?.server?.host ?? "127.0.0.1";
|
|
445
315
|
const port = opts.port ?? String(existingConfig?.server?.port ?? 8765);
|
|
316
|
+
const parsedPort = Number(port);
|
|
317
|
+
if (!Number.isInteger(parsedPort) || parsedPort < 1 || parsedPort > 65_535) throw new Error(`forge mcp setup chatgpt: invalid port ${port}`);
|
|
318
|
+
const localControllerPort = opts.localControllerPort !== undefined
|
|
319
|
+
? Number(opts.localControllerPort)
|
|
320
|
+
: existingConfig?.localController?.port ?? (parsedPort < 65_535 ? parsedPort + 1 : 8766);
|
|
321
|
+
if (!Number.isInteger(localControllerPort) || localControllerPort < 1 || localControllerPort > 65_535) throw new Error(`forge mcp setup chatgpt: invalid Local Controller port ${opts.localControllerPort}`);
|
|
322
|
+
if (localControllerPort === parsedPort) throw new Error('forge mcp setup chatgpt: Local Controller port must differ from MCP port');
|
|
323
|
+
const connectorPort = opts.connectorPort !== undefined
|
|
324
|
+
? Number(opts.connectorPort)
|
|
325
|
+
: parsedPort <= 65_533 ? parsedPort + 2 : 8767;
|
|
326
|
+
if (!Number.isInteger(connectorPort) || connectorPort < 1 || connectorPort > 65_535) throw new Error(`forge mcp setup chatgpt: invalid connector port ${opts.connectorPort}`);
|
|
327
|
+
if (connectorPort === parsedPort || connectorPort === localControllerPort) throw new Error('forge mcp setup chatgpt: connector port must differ from Runtime and Local Controller ports');
|
|
446
328
|
const existingServerName = existingConfig?.chatgpt?.serverName;
|
|
447
329
|
const migratedServerName =
|
|
448
330
|
existingServerName && !LEGACY_DEFAULT_SERVER_NAMES.has(existingServerName)
|
|
@@ -455,7 +337,7 @@ export function runMcpSetupChatgpt(opts: {
|
|
|
455
337
|
opts.endpoint ?? existingConfig?.chatgpt?.endpoint,
|
|
456
338
|
);
|
|
457
339
|
const configPath = mcpControllerHomeLocalConfigPath(controllerHome);
|
|
458
|
-
const guidePath = join(repoRoot, "docs", "forge-chatgpt-mcp-setup.md");
|
|
340
|
+
const guidePath = opts.userLevel ? undefined : join(repoRoot, "docs", "forge-chatgpt-mcp-setup.md");
|
|
459
341
|
const token = ensureMcpControllerHomeBearerToken(controllerHome);
|
|
460
342
|
const oauth = ensureMcpControllerHomeOAuthPassphrase(controllerHome);
|
|
461
343
|
if (token.changed) changed.push(token.path);
|
|
@@ -464,11 +346,11 @@ export function runMcpSetupChatgpt(opts: {
|
|
|
464
346
|
const toolset = migratedToolset.toolset;
|
|
465
347
|
const config = {
|
|
466
348
|
version: Math.max(existingConfig?.version ?? 1, 2),
|
|
467
|
-
repo: repoRoot,
|
|
349
|
+
...(opts.userLevel ? (existingConfig?.repo ? { repo: existingConfig.repo } : {}) : { repo: repoRoot }),
|
|
468
350
|
server: {
|
|
469
351
|
...existingConfig?.server,
|
|
470
352
|
host,
|
|
471
|
-
port:
|
|
353
|
+
port: parsedPort,
|
|
472
354
|
transport: existingConfig?.server?.transport ?? "http",
|
|
473
355
|
},
|
|
474
356
|
auth: existingConfig?.auth ?? {
|
|
@@ -480,6 +362,7 @@ export function runMcpSetupChatgpt(opts: {
|
|
|
480
362
|
...existingConfig?.chatgpt,
|
|
481
363
|
serverName,
|
|
482
364
|
...(endpoint ? { endpoint } : {}),
|
|
365
|
+
localEndpoint: `http://127.0.0.1:${connectorPort}/mcp`,
|
|
483
366
|
},
|
|
484
367
|
profile: existingConfig?.profile ?? "controller",
|
|
485
368
|
toolset,
|
|
@@ -488,16 +371,22 @@ export function runMcpSetupChatgpt(opts: {
|
|
|
488
371
|
?? accessModeForLegacyToolset(existingConfig?.toolset ?? toolset),
|
|
489
372
|
accessModeUpdatedAt: existingConfig?.accessModeUpdatedAt,
|
|
490
373
|
accessModeRevision: existingConfig?.accessModeRevision ?? 0,
|
|
491
|
-
localController: existingConfig?.
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
374
|
+
localController: opts.userLevel && !existingConfig?.repo
|
|
375
|
+
? {
|
|
376
|
+
enabled: false,
|
|
377
|
+
host: existingConfig?.localController?.host ?? "127.0.0.1",
|
|
378
|
+
port: localControllerPort,
|
|
379
|
+
autoOpen: false,
|
|
380
|
+
mode: "disabled",
|
|
381
|
+
}
|
|
382
|
+
: {
|
|
383
|
+
...(existingConfig?.localController ?? { enabled: true, host: "127.0.0.1", autoOpen: false }),
|
|
384
|
+
port: localControllerPort,
|
|
385
|
+
},
|
|
497
386
|
devMode: {
|
|
498
387
|
...existingConfig?.devMode,
|
|
499
|
-
agentRunner: existingConfig?.devMode?.agentRunner ??
|
|
500
|
-
allowedAgents: existingConfig?.devMode?.allowedAgents ??
|
|
388
|
+
agentRunner: existingConfig?.devMode?.agentRunner ?? false,
|
|
389
|
+
allowedAgents: existingConfig?.devMode?.allowedAgents ?? [],
|
|
501
390
|
timeoutMs:
|
|
502
391
|
!existingConfig?.devMode?.timeoutMs ||
|
|
503
392
|
existingConfig.devMode.timeoutMs === 120_000
|
|
@@ -512,105 +401,117 @@ export function runMcpSetupChatgpt(opts: {
|
|
|
512
401
|
`${JSON.stringify(config, null, 2)}\n`,
|
|
513
402
|
changed,
|
|
514
403
|
);
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
404
|
+
if (guidePath) {
|
|
405
|
+
writeFileIfChanged(guidePath, chatgptGuideMarkdown(), changed);
|
|
406
|
+
ensureGitignoreEntries(
|
|
407
|
+
repoRoot,
|
|
408
|
+
[
|
|
409
|
+
".forge/mcp.local.json",
|
|
410
|
+
".forge/mcp.tokens.json",
|
|
411
|
+
".forge/mcp.oauth.json",
|
|
412
|
+
".forge/mcp.oauth-tokens.json",
|
|
413
|
+
".forge/mcp.runtime.json",
|
|
414
|
+
".ai/harness/mcp/audit.log",
|
|
415
|
+
".ai/harness/local-jobs/",
|
|
416
|
+
".ai/harness/controller/",
|
|
417
|
+
],
|
|
418
|
+
changed,
|
|
419
|
+
);
|
|
420
|
+
}
|
|
530
421
|
|
|
531
422
|
return {
|
|
532
423
|
status: "ok",
|
|
533
424
|
repoRoot,
|
|
534
425
|
changed,
|
|
535
426
|
lines: [
|
|
536
|
-
`[forge mcp] Repo: ${repoRoot}`,
|
|
427
|
+
opts.userLevel ? `[forge mcp] Scope: user (${controllerHome})` : `[forge mcp] Repo: ${repoRoot}`,
|
|
537
428
|
"[forge mcp] Profile: controller",
|
|
538
429
|
`[forge mcp] Toolset: ${config.toolset}`,
|
|
539
430
|
`[forge mcp] ChatGPT MCP server name: ${serverName}`,
|
|
540
|
-
`[forge mcp]
|
|
431
|
+
`[forge mcp] Internal Runtime endpoint: http://${host}:${port}/mcp`,
|
|
432
|
+
`[forge mcp] ChatGPT local OAuth endpoint: http://127.0.0.1:${connectorPort}/mcp`,
|
|
541
433
|
`[forge mcp] Local Controller: http://${config.localController.host}:${config.localController.port}/`,
|
|
542
|
-
`[forge mcp]
|
|
434
|
+
`[forge mcp] Optional external delegation: ${config.devMode.agentRunner ? `enabled (${config.devMode.allowedAgents.join(',') || 'none'})` : 'disabled'}`,
|
|
543
435
|
endpoint
|
|
544
436
|
? `[forge mcp] ChatGPT endpoint: ${endpoint}`
|
|
545
437
|
: "[forge mcp] ChatGPT endpoint: requires stable HTTPS tunnel",
|
|
546
438
|
`[forge mcp] Auth: OAuth passphrase (${relative(repoRoot, oauth.path)})`,
|
|
547
439
|
`[forge mcp] Bearer fallback token: ${relative(repoRoot, token.path)}`,
|
|
548
440
|
`[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
|
-
|
|
441
|
+
...(guidePath ? [`[forge mcp] Guide: ${relative(repoRoot, guidePath)} (generic; endpoint stays in ignored local config)`] : []),
|
|
442
|
+
`[forge mcp] Runtime state: ${mcpControllerHomeRuntimeStatePath(controllerHome)}`,
|
|
443
|
+
opts.userLevel
|
|
444
|
+
? 'Next: forge setup next'
|
|
445
|
+
: `Next: forge runtime service install-package --controller-home ${controllerHome} --host ${host} --port ${port}`,
|
|
552
446
|
],
|
|
553
447
|
};
|
|
554
448
|
}
|
|
555
449
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
"
|
|
572
|
-
"
|
|
573
|
-
"
|
|
574
|
-
"
|
|
575
|
-
"
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
450
|
+
type LocalControllerProfile = 'controller' | 'executor';
|
|
451
|
+
|
|
452
|
+
function localControllerProfile(value: string | undefined, label: string, fallback: LocalControllerProfile): LocalControllerProfile {
|
|
453
|
+
const normalized = (value ?? fallback).trim().toLowerCase();
|
|
454
|
+
if (normalized !== 'controller' && normalized !== 'executor') {
|
|
455
|
+
throw new Error(`${label}: expected controller|executor`);
|
|
456
|
+
}
|
|
457
|
+
return normalized;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export function codexMcpBlock(profile: LocalControllerProfile = 'executor'): string {
|
|
461
|
+
const lines = [
|
|
462
|
+
'[mcp_servers.forge]',
|
|
463
|
+
'command = "forge"',
|
|
464
|
+
'args = [',
|
|
465
|
+
' "mcp",',
|
|
466
|
+
' "serve",',
|
|
467
|
+
' "--repo",',
|
|
468
|
+
' ".",',
|
|
469
|
+
' "--transport",',
|
|
470
|
+
' "stdio",',
|
|
471
|
+
' "--profile",',
|
|
472
|
+
` "${profile}"`,
|
|
473
|
+
']',
|
|
474
|
+
];
|
|
475
|
+
if (profile === 'executor') {
|
|
476
|
+
lines.push(
|
|
477
|
+
'enabled_tools = [',
|
|
478
|
+
...REQUIRED_CODEX_TOOLS.map((tool) => ` "${tool}",`),
|
|
479
|
+
']',
|
|
480
|
+
'default_tools_approval_mode = "prompt"',
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
return `${lines.join('\n')}\n`;
|
|
484
|
+
}
|
|
579
485
|
|
|
580
|
-
export function patchCodexConfigToml(current: string): string {
|
|
486
|
+
export function patchCodexConfigToml(current: string, profile: LocalControllerProfile = 'executor'): string {
|
|
487
|
+
const block = codexMcpBlock(profile);
|
|
581
488
|
const normalized = current.trimEnd();
|
|
582
489
|
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${
|
|
490
|
+
const prefix = normalized.length > 0 ? `${normalized}\n\n` : '';
|
|
491
|
+
if (!blockPattern.test(normalized)) return `${prefix}${block}`;
|
|
492
|
+
return `${normalized.replace(blockPattern, `\n${block}`.trimEnd())}\n`;
|
|
586
493
|
}
|
|
587
494
|
|
|
588
495
|
export function runMcpSetupCodex(opts: {
|
|
589
496
|
repo?: string;
|
|
590
497
|
scope?: string;
|
|
498
|
+
profile?: string;
|
|
591
499
|
dryRun?: boolean;
|
|
592
500
|
}): McpSetupResult {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
);
|
|
501
|
+
const scope = (opts.scope ?? 'project').trim().toLowerCase();
|
|
502
|
+
if (scope !== 'project' && scope !== 'user') {
|
|
503
|
+
throw new Error('forge mcp setup codex --scope: expected project|user');
|
|
597
504
|
}
|
|
598
|
-
const
|
|
599
|
-
const
|
|
505
|
+
const profile = localControllerProfile(opts.profile, 'forge mcp setup codex --profile', 'executor');
|
|
506
|
+
const repoRoot = resolveMcpRepoRoot(opts.repo ?? '.');
|
|
507
|
+
const configPath = scope === 'user' ? join(homedir(), '.codex', 'config.toml') : join(repoRoot, '.codex', 'config.toml');
|
|
600
508
|
const changed: string[] = [];
|
|
601
|
-
const current = existsSync(configPath)
|
|
602
|
-
|
|
603
|
-
: "";
|
|
604
|
-
const next = patchCodexConfigToml(current);
|
|
509
|
+
const current = existsSync(configPath) ? readFileSync(configPath, 'utf-8') : '';
|
|
510
|
+
const next = patchCodexConfigToml(current, profile);
|
|
605
511
|
if (opts.dryRun === true) {
|
|
606
512
|
return {
|
|
607
|
-
status:
|
|
608
|
-
repoRoot,
|
|
609
|
-
changed: [],
|
|
610
|
-
lines: [
|
|
611
|
-
`[forge mcp] Dry run: would patch ${relative(repoRoot, configPath)}`,
|
|
612
|
-
next,
|
|
613
|
-
],
|
|
513
|
+
status: 'ok', repoRoot, changed: [],
|
|
514
|
+
lines: [`[forge mcp] Dry run: would patch ${scope === 'user' ? configPath : relative(repoRoot, configPath)}`, next],
|
|
614
515
|
};
|
|
615
516
|
}
|
|
616
517
|
if (existsSync(configPath) && current !== next) {
|
|
@@ -619,13 +520,56 @@ export function runMcpSetupCodex(opts: {
|
|
|
619
520
|
}
|
|
620
521
|
writeFileIfChanged(configPath, next, changed);
|
|
621
522
|
return {
|
|
622
|
-
status:
|
|
623
|
-
|
|
624
|
-
|
|
523
|
+
status: 'ok', repoRoot, changed,
|
|
524
|
+
lines: [
|
|
525
|
+
`[forge mcp] Codex config: ${scope === 'user' ? configPath : relative(repoRoot, configPath)}`,
|
|
526
|
+
'[forge mcp] Server: forge',
|
|
527
|
+
'[forge mcp] Transport: stdio',
|
|
528
|
+
`[forge mcp] Role: external ${profile === 'controller' ? 'primary controller' : 'executor/delegate'}`,
|
|
529
|
+
],
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
export function claudeMcpSetupCommand(repoRoot: string, profile: LocalControllerProfile = 'controller', scope = 'user'): string[] {
|
|
534
|
+
return [
|
|
535
|
+
'claude', 'mcp', 'add', 'forge', '--scope', scope, '--',
|
|
536
|
+
'forge', 'mcp', 'serve', '--repo', repoRoot, '--transport', 'stdio', '--profile', profile,
|
|
537
|
+
];
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export function runMcpSetupClaude(opts: {
|
|
541
|
+
repo?: string;
|
|
542
|
+
scope?: string;
|
|
543
|
+
profile?: string;
|
|
544
|
+
dryRun?: boolean;
|
|
545
|
+
}): McpSetupResult {
|
|
546
|
+
const repoRoot = resolveMcpRepoRoot(opts.repo ?? '.');
|
|
547
|
+
const scope = (opts.scope ?? 'user').trim().toLowerCase();
|
|
548
|
+
if (!['local', 'project', 'user'].includes(scope)) {
|
|
549
|
+
throw new Error('forge mcp setup claude --scope: expected local|project|user');
|
|
550
|
+
}
|
|
551
|
+
const profile = localControllerProfile(opts.profile, 'forge mcp setup claude --profile', 'controller');
|
|
552
|
+
const command = claudeMcpSetupCommand(scope === 'user' ? '.' : repoRoot, profile, scope);
|
|
553
|
+
if (opts.dryRun === true) {
|
|
554
|
+
return {
|
|
555
|
+
status: 'ok', repoRoot, changed: [],
|
|
556
|
+
lines: [`[forge mcp] Dry run: ${command.join(' ')}`],
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
const result = spawnSync(command[0], command.slice(1), { cwd: repoRoot, encoding: 'utf8', timeout: 30_000 });
|
|
560
|
+
if (result.error && (result.error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
561
|
+
throw new Error('Claude Code CLI is not installed. Install/authenticate Claude only if you selected it as a Forge controller.');
|
|
562
|
+
}
|
|
563
|
+
if (result.status !== 0) {
|
|
564
|
+
throw new Error(`Claude MCP configuration failed (${result.status ?? 'unknown'}): ${(result.stderr || result.stdout || result.error?.message || '').trim()}`);
|
|
565
|
+
}
|
|
566
|
+
return {
|
|
567
|
+
status: 'ok', repoRoot, changed: [],
|
|
625
568
|
lines: [
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
569
|
+
'[forge mcp] Claude Code MCP server configured through the Claude CLI.',
|
|
570
|
+
`[forge mcp] Scope: ${scope}`,
|
|
571
|
+
`[forge mcp] Role: external ${profile === 'controller' ? 'primary controller' : 'executor/delegate'}`,
|
|
572
|
+
'[forge mcp] Verify: claude mcp get forge',
|
|
629
573
|
],
|
|
630
574
|
};
|
|
631
575
|
}
|
|
@@ -709,7 +653,7 @@ export function runMcpDoctor(opts: {
|
|
|
709
653
|
},
|
|
710
654
|
devMode: {
|
|
711
655
|
agentRunner: localConfig?.devMode?.agentRunner === true,
|
|
712
|
-
allowedAgents: localConfig?.devMode?.allowedAgents ??
|
|
656
|
+
allowedAgents: localConfig?.devMode?.allowedAgents ?? [],
|
|
713
657
|
timeoutMs: localConfig?.devMode?.timeoutMs ?? DEFAULT_AGENT_TIMEOUT_MS,
|
|
714
658
|
maxTimeoutMs:
|
|
715
659
|
localConfig?.devMode?.maxTimeoutMs ?? MAX_AGENT_TIMEOUT_MS,
|