@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `forge
|
|
2
|
+
* Readiness model behind `forge setup check` and resumable `forge setup`.
|
|
3
3
|
*
|
|
4
4
|
* This command intentionally does not install hooks, write user-owned markdown,
|
|
5
5
|
* or mutate repo-local runtime files. It gathers the existing readiness probes
|
|
@@ -16,9 +16,23 @@ import { fileURLToPath } from 'url';
|
|
|
16
16
|
import { Command } from 'commander';
|
|
17
17
|
import { runDoctor, type CheckStatus, type DoctorReport } from './doctor';
|
|
18
18
|
import { runStatus, type StatusReport } from './status';
|
|
19
|
-
import
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
import { runMcpSetupChatgpt } from '../mcp/setup';
|
|
20
|
+
import { resolveRepoPreferredControllerHome } from '../repositories/controller-home';
|
|
21
|
+
import {
|
|
22
|
+
configureSetupProfile,
|
|
23
|
+
detectSetupPlatform,
|
|
24
|
+
formatSetupProfile,
|
|
25
|
+
readSetupProfile,
|
|
26
|
+
resolveControllerGuidance,
|
|
27
|
+
resolveRuntimeGuidance,
|
|
28
|
+
resolveTunnelGuidance,
|
|
29
|
+
setupHostTarget,
|
|
30
|
+
type SetupHostTarget,
|
|
31
|
+
type SetupPlatformSnapshot,
|
|
32
|
+
type SetupProfile,
|
|
33
|
+
} from './setup-profile';
|
|
34
|
+
|
|
35
|
+
export type InitHookTarget = SetupHostTarget;
|
|
22
36
|
export type InitHookStatus = 'ok' | 'attention' | 'blocked';
|
|
23
37
|
export type InitHookCheckStatus = CheckStatus | 'needs_agent';
|
|
24
38
|
export type InitHookCheckSource =
|
|
@@ -108,7 +122,7 @@ const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
|
|
|
108
122
|
const REPO_ROOT = resolve(SCRIPT_DIR, '..', '..', '..');
|
|
109
123
|
const UPDATE_CHECK_ENV = 'FORGE_CHECK_UPDATES';
|
|
110
124
|
const GLOBAL_RULES_BEGIN = '<!-- BEGIN: forge global-working-rules -->';
|
|
111
|
-
const VALID_TARGETS: readonly InitHookTarget[] = ['codex', 'claude', 'both'];
|
|
125
|
+
const VALID_TARGETS: readonly InitHookTarget[] = ['none', 'codex', 'claude', 'both'];
|
|
112
126
|
|
|
113
127
|
function withProcessEnv<T>(env: NodeJS.ProcessEnv | undefined, fn: () => T): T {
|
|
114
128
|
if (!env) return fn();
|
|
@@ -129,6 +143,7 @@ function withProcessEnv<T>(env: NodeJS.ProcessEnv | undefined, fn: () => T): T {
|
|
|
129
143
|
}
|
|
130
144
|
|
|
131
145
|
function selectedTargets(target: InitHookTarget): Array<'codex' | 'claude'> {
|
|
146
|
+
if (target === 'none') return [];
|
|
132
147
|
if (target === 'both') return ['codex', 'claude'];
|
|
133
148
|
return [target];
|
|
134
149
|
}
|
|
@@ -230,6 +245,19 @@ function parseActionCommand(detail: string): string | undefined {
|
|
|
230
245
|
return run?.[1]?.trim();
|
|
231
246
|
}
|
|
232
247
|
|
|
248
|
+
function doctorEntryRelevant(id: string, target: InitHookTarget): boolean {
|
|
249
|
+
if (id === 'cli-on-path' || id === 'cli-version' || id === 'cli-update' || id === 'security-config') return true;
|
|
250
|
+
if (target === 'none') return false;
|
|
251
|
+
if (id === 'repo-hook-scripts' || id === 'codegraph-readiness' || id === 'codegraph-index') return true;
|
|
252
|
+
if (target === 'codex' || target === 'both') {
|
|
253
|
+
if (id === 'codex-adapter' || id === 'codex-trust-state' || id === 'codex-codegraph-mcp') return true;
|
|
254
|
+
}
|
|
255
|
+
if (target === 'claude' || target === 'both') {
|
|
256
|
+
if (id === 'claude-adapter' || id === 'claude-codegraph-mcp') return true;
|
|
257
|
+
}
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
|
|
233
261
|
function doctorChecks(
|
|
234
262
|
report: DoctorReport,
|
|
235
263
|
target: InitHookTarget,
|
|
@@ -238,6 +266,7 @@ function doctorChecks(
|
|
|
238
266
|
): InitHookCheck[] {
|
|
239
267
|
const checks: InitHookCheck[] = [];
|
|
240
268
|
for (const entry of report.checks) {
|
|
269
|
+
if (!doctorEntryRelevant(entry.id, target)) continue;
|
|
241
270
|
const source: InitHookCheckSource = entry.id === 'security-config' ? 'security' : 'doctor';
|
|
242
271
|
let checkStatus: InitHookCheckStatus = entry.status;
|
|
243
272
|
|
|
@@ -425,7 +454,7 @@ function commandForToolGap(toolName: string, tool: ToolingTool, target: InitHook
|
|
|
425
454
|
return normalizeToolCommand(tool.install_command, target);
|
|
426
455
|
}
|
|
427
456
|
if (toolName === 'codex_automation_profile') {
|
|
428
|
-
return 'forge
|
|
457
|
+
return 'forge install --target codex --no-cli --no-hooks --no-codegraph';
|
|
429
458
|
}
|
|
430
459
|
return normalizeToolCommand(
|
|
431
460
|
tool.sync_command ?? tool.ensure_command ?? tool.mcp_install_command ?? tool.install_command ?? tool.upgrade_command,
|
|
@@ -579,24 +608,26 @@ function overallStatus(summary: InitHookReport['summary']): InitHookStatus {
|
|
|
579
608
|
export function runInitHook(opts: InitHookOptions = {}): InitHookReport {
|
|
580
609
|
const cwd = resolve(opts.cwd ?? process.cwd());
|
|
581
610
|
const sourceRoot = resolve(opts.sourceRoot ?? REPO_ROOT);
|
|
582
|
-
const target = opts.target ?? '
|
|
611
|
+
const target = opts.target ?? 'none';
|
|
583
612
|
const checkUpdates = opts.checkUpdates === true;
|
|
584
613
|
const actions: InitHookAction[] = [];
|
|
585
614
|
|
|
586
615
|
const statusReport = opts.statusReport ?? withProcessEnv(opts.env, () => runStatus(cwd));
|
|
587
616
|
const doctorEnv = { ...(opts.env ?? {}), [UPDATE_CHECK_ENV]: checkUpdates ? '1' : undefined };
|
|
588
617
|
const doctorReport = opts.doctorReport ?? withProcessEnv(doctorEnv, () => runDoctor(cwd));
|
|
589
|
-
const toolingProbe =
|
|
590
|
-
? { report:
|
|
591
|
-
:
|
|
618
|
+
const toolingProbe = target === 'none'
|
|
619
|
+
? { report: undefined, error: undefined }
|
|
620
|
+
: opts.toolingReport
|
|
621
|
+
? { report: opts.toolingReport, error: undefined }
|
|
622
|
+
: collectToolingReport(sourceRoot, cwd, target, checkUpdates, opts.env);
|
|
592
623
|
|
|
593
624
|
const checks: InitHookCheck[] = [
|
|
594
|
-
...statusChecks(statusReport, target, checkUpdates, actions),
|
|
625
|
+
...(target === 'none' ? [] : statusChecks(statusReport, target, checkUpdates, actions)),
|
|
595
626
|
...doctorChecks(doctorReport, target, checkUpdates, actions),
|
|
596
|
-
...globalRulesChecks(target, opts.env, checkUpdates, actions),
|
|
597
|
-
...runtimeCapabilityChecks(toolingProbe.report, target, checkUpdates, actions),
|
|
598
|
-
...toolingChecks(toolingProbe.report, target, checkUpdates, actions, toolingProbe.error),
|
|
599
|
-
...legacyChecks(cwd, target, checkUpdates, actions),
|
|
627
|
+
...(target === 'none' ? [] : globalRulesChecks(target, opts.env, checkUpdates, actions)),
|
|
628
|
+
...(target === 'none' ? [] : runtimeCapabilityChecks(toolingProbe.report, target, checkUpdates, actions)),
|
|
629
|
+
...(target === 'none' ? [] : toolingChecks(toolingProbe.report, target, checkUpdates, actions, toolingProbe.error)),
|
|
630
|
+
...(target === 'none' ? [] : legacyChecks(cwd, target, checkUpdates, actions)),
|
|
600
631
|
];
|
|
601
632
|
|
|
602
633
|
const summary = summarize(checks);
|
|
@@ -617,7 +648,7 @@ export function formatInitHook(report: InitHookReport, asJson = false): string {
|
|
|
617
648
|
lines.push(`forge setup check: ${report.status}`);
|
|
618
649
|
lines.push(`target=${report.target}; check-updates=${report.checkUpdates ? 'on' : 'off'}`);
|
|
619
650
|
lines.push(
|
|
620
|
-
`summary: ${report.summary.ok} ok, ${report.summary.warn} warn, ${report.summary.fail} fail, ${report.summary.na} n/a, ${report.summary.needs_agent} needs-
|
|
651
|
+
`summary: ${report.summary.ok} ok, ${report.summary.warn} warn, ${report.summary.fail} fail, ${report.summary.na} n/a, ${report.summary.needs_agent} needs-action`,
|
|
621
652
|
);
|
|
622
653
|
lines.push('');
|
|
623
654
|
lines.push('Checks:');
|
|
@@ -625,7 +656,7 @@ export function formatInitHook(report: InitHookReport, asJson = false): string {
|
|
|
625
656
|
lines.push(` [${check.status}] ${check.id}: ${check.detail}`);
|
|
626
657
|
}
|
|
627
658
|
lines.push('');
|
|
628
|
-
lines.push('
|
|
659
|
+
lines.push('Actions:');
|
|
629
660
|
if (report.agent_actions.length === 0) {
|
|
630
661
|
lines.push(' none');
|
|
631
662
|
} else {
|
|
@@ -640,30 +671,6 @@ export function formatInitHook(report: InitHookReport, asJson = false): string {
|
|
|
640
671
|
return lines.join('\n');
|
|
641
672
|
}
|
|
642
673
|
|
|
643
|
-
export function buildInitHookCommand(): Command {
|
|
644
|
-
const command = new Command('init-hook');
|
|
645
|
-
command
|
|
646
|
-
.description('Run a read-only Agent bootstrap checklist for user-level Forge readiness')
|
|
647
|
-
.option('--target <target>', `Host target to inspect: ${VALID_TARGETS.join('|')}`, 'both')
|
|
648
|
-
.option('--check-updates', 'Include network-backed version update advisories')
|
|
649
|
-
.option('--json', 'Output JSON instead of human-readable text')
|
|
650
|
-
.action((rawOpts: { target: string; checkUpdates?: boolean; json?: boolean }) => {
|
|
651
|
-
if (!VALID_TARGETS.includes(rawOpts.target as InitHookTarget)) {
|
|
652
|
-
console.error(
|
|
653
|
-
`forge init-hook: invalid --target "${rawOpts.target}" (expected: ${VALID_TARGETS.join(', ')})`,
|
|
654
|
-
);
|
|
655
|
-
process.exit(2);
|
|
656
|
-
}
|
|
657
|
-
const report = runInitHook({
|
|
658
|
-
target: rawOpts.target as InitHookTarget,
|
|
659
|
-
checkUpdates: rawOpts.checkUpdates === true,
|
|
660
|
-
});
|
|
661
|
-
console.log(formatInitHook(report, rawOpts.json === true));
|
|
662
|
-
process.exit(report.status === 'blocked' ? 1 : 0);
|
|
663
|
-
});
|
|
664
|
-
return command;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
674
|
export type SetupSessionStatus = 'open' | 'blocked' | 'ready' | 'closed';
|
|
668
675
|
|
|
669
676
|
export interface SetupSession {
|
|
@@ -672,6 +679,8 @@ export interface SetupSession {
|
|
|
672
679
|
status: SetupSessionStatus;
|
|
673
680
|
target: InitHookTarget;
|
|
674
681
|
checkUpdates: boolean;
|
|
682
|
+
profile?: SetupProfile;
|
|
683
|
+
platform?: SetupPlatformSnapshot;
|
|
675
684
|
createdAt: string;
|
|
676
685
|
updatedAt: string;
|
|
677
686
|
closedAt?: string;
|
|
@@ -681,6 +690,10 @@ export interface SetupSession {
|
|
|
681
690
|
|
|
682
691
|
export interface SetupSessionOptions extends InitHookOptions {
|
|
683
692
|
setupRoot?: string;
|
|
693
|
+
profile?: SetupProfile;
|
|
694
|
+
platform?: SetupPlatformSnapshot;
|
|
695
|
+
controllerHome?: string;
|
|
696
|
+
accountHome?: string;
|
|
684
697
|
report?: InitHookReport;
|
|
685
698
|
now?: () => Date;
|
|
686
699
|
uuid?: () => string;
|
|
@@ -714,28 +727,86 @@ export function readSetupSession(options: Pick<SetupSessionOptions, 'setupRoot'
|
|
|
714
727
|
return readSetupSessionAt(setupSessionPath(options));
|
|
715
728
|
}
|
|
716
729
|
|
|
717
|
-
function setupStatus(report: InitHookReport): SetupSessionStatus {
|
|
730
|
+
function setupStatus(report: InitHookReport, nextAction?: InitHookAction): SetupSessionStatus {
|
|
718
731
|
if (report.status === 'blocked') return 'blocked';
|
|
719
|
-
if (report.status === 'ok' && report.agent_actions.length === 0) return 'ready';
|
|
732
|
+
if (report.status === 'ok' && report.agent_actions.length === 0 && !nextAction) return 'ready';
|
|
720
733
|
return 'open';
|
|
721
734
|
}
|
|
722
735
|
|
|
736
|
+
function profileNextAction(profile: SetupProfile | undefined, platform: SetupPlatformSnapshot, options: { controllerHome?: string; accountHome?: string } = {}): InitHookAction | undefined {
|
|
737
|
+
if (!profile) {
|
|
738
|
+
return {
|
|
739
|
+
id: 'controller.select',
|
|
740
|
+
status: 'needs_agent',
|
|
741
|
+
reason: 'Choose the external controller that will act as Forge’s brain. ChatGPT is recommended; Codex, Claude, or another MCP client can be primary instead.',
|
|
742
|
+
requires_agent: true,
|
|
743
|
+
risk: 'Writes only the local Forge setup profile. It does not install or authenticate third-party software.',
|
|
744
|
+
command: 'forge setup configure --controller chatgpt',
|
|
745
|
+
verification: 'forge setup next',
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
const controller = resolveControllerGuidance(profile, { controllerHome: options.controllerHome, home: options.accountHome });
|
|
749
|
+
if (controller && !controller.ready) {
|
|
750
|
+
return {
|
|
751
|
+
id: `controller.${controller.controller}.configure`,
|
|
752
|
+
status: 'needs_agent',
|
|
753
|
+
reason: `${controller.title}: ${controller.detail}`,
|
|
754
|
+
requires_agent: true,
|
|
755
|
+
risk: 'Configures only the explicitly selected external controller entry. Unselected Codex/Claude providers remain untouched.',
|
|
756
|
+
...(controller.command ? { command: controller.command } : {}),
|
|
757
|
+
verification: 'forge setup next',
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
const runtime = resolveRuntimeGuidance(profile, { controllerHome: options.controllerHome });
|
|
761
|
+
if (runtime && !runtime.ready) {
|
|
762
|
+
return {
|
|
763
|
+
id: 'runtime.package.install',
|
|
764
|
+
status: 'needs_agent',
|
|
765
|
+
reason: `${runtime.title}: ${runtime.detail}`,
|
|
766
|
+
requires_agent: true,
|
|
767
|
+
risk: 'Installs or diagnoses the user-level Forge Runtime only. Standalone Recovery and source-release activation are not part of normal setup.',
|
|
768
|
+
...(runtime.command ? { command: runtime.command } : {}),
|
|
769
|
+
verification: 'forge setup next',
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
const tunnel = resolveTunnelGuidance(profile, platform, { controllerHome: options.controllerHome });
|
|
773
|
+
if (!tunnel.ready) {
|
|
774
|
+
return {
|
|
775
|
+
id: `tunnel.${tunnel.provider}.configure`,
|
|
776
|
+
status: 'needs_agent',
|
|
777
|
+
reason: `${tunnel.title}: ${tunnel.detail}`,
|
|
778
|
+
requires_agent: true,
|
|
779
|
+
risk: 'Remote connectivity is provider-owned. Forge keeps its MCP listener on loopback; credentials, authentication, and account changes remain explicit.',
|
|
780
|
+
...(tunnel.command ? { command: tunnel.command } : {}),
|
|
781
|
+
verification: 'forge setup next',
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
return undefined;
|
|
785
|
+
}
|
|
786
|
+
|
|
723
787
|
export function openSetupSession(options: SetupSessionOptions = {}): SetupSession {
|
|
724
788
|
const path = setupSessionPath(options);
|
|
725
789
|
const previous = readSetupSessionAt(path);
|
|
726
|
-
const
|
|
790
|
+
const profile = options.profile ?? readSetupProfile(options);
|
|
791
|
+
const platform = options.platform ?? detectSetupPlatform({ env: options.env });
|
|
792
|
+
const target = options.target ?? setupHostTarget(profile);
|
|
793
|
+
const report = options.report ?? runInitHook({ ...options, target });
|
|
794
|
+
const controllerHome = resolveRepoPreferredControllerHome(options.cwd ?? process.cwd(), options.controllerHome);
|
|
795
|
+
const nextAction = profileNextAction(profile, platform, { controllerHome, accountHome: options.accountHome }) ?? report.agent_actions[0];
|
|
727
796
|
const now = (options.now ?? (() => new Date()))().toISOString();
|
|
728
797
|
const reuse = previous && previous.status !== 'closed';
|
|
729
798
|
return writeSetupSessionAt(path, {
|
|
730
799
|
schemaVersion: 1,
|
|
731
800
|
sessionId: reuse ? previous.sessionId : (options.uuid ?? randomUUID)(),
|
|
732
|
-
status: setupStatus(report),
|
|
801
|
+
status: setupStatus(report, nextAction),
|
|
733
802
|
target: report.target,
|
|
734
803
|
checkUpdates: report.checkUpdates,
|
|
804
|
+
...(profile ? { profile } : {}),
|
|
805
|
+
platform,
|
|
735
806
|
createdAt: reuse ? previous.createdAt : now,
|
|
736
807
|
updatedAt: now,
|
|
737
808
|
lastReport: report,
|
|
738
|
-
...(
|
|
809
|
+
...(nextAction ? { nextAction } : {}),
|
|
739
810
|
});
|
|
740
811
|
}
|
|
741
812
|
|
|
@@ -756,8 +827,9 @@ export function formatSetupSession(session: SetupSession, asJson = false): strin
|
|
|
756
827
|
if (asJson) return JSON.stringify(session, null, 2);
|
|
757
828
|
const lines = [
|
|
758
829
|
`forge setup: ${session.status}`,
|
|
759
|
-
`session=${session.sessionId};
|
|
760
|
-
`summary: ${session.lastReport.summary.ok} ok, ${session.lastReport.summary.warn} warn, ${session.lastReport.summary.fail} fail, ${session.lastReport.summary.needs_agent} needs-
|
|
830
|
+
`session=${session.sessionId}; controller=${session.profile?.primaryController ?? 'not-selected'}; host-tooling=${session.target}; updated=${session.updatedAt}`,
|
|
831
|
+
`summary: ${session.lastReport.summary.ok} ok, ${session.lastReport.summary.warn} warn, ${session.lastReport.summary.fail} fail, ${session.lastReport.summary.needs_agent} needs-action`,
|
|
832
|
+
...(session.profile ? ['', formatSetupProfile(session.profile, session.platform)] : []),
|
|
761
833
|
];
|
|
762
834
|
if (session.nextAction) {
|
|
763
835
|
lines.push('', `Next: ${session.nextAction.reason}`);
|
|
@@ -771,17 +843,50 @@ export function formatSetupSession(session: SetupSession, asJson = false): strin
|
|
|
771
843
|
return lines.join('\n');
|
|
772
844
|
}
|
|
773
845
|
|
|
774
|
-
function setupTarget(value: string, surface: string): InitHookTarget {
|
|
846
|
+
function setupTarget(value: string | undefined, surface: string): InitHookTarget | undefined {
|
|
847
|
+
if (value === undefined) return undefined;
|
|
775
848
|
if (!VALID_TARGETS.includes(value as InitHookTarget)) {
|
|
776
849
|
throw new Error(`${surface}: invalid --target "${value}" (expected: ${VALID_TARGETS.join(', ')})`);
|
|
777
850
|
}
|
|
778
851
|
return value as InitHookTarget;
|
|
779
852
|
}
|
|
780
853
|
|
|
781
|
-
|
|
854
|
+
interface SetupCycleRawOptions {
|
|
855
|
+
target?: string;
|
|
856
|
+
controller?: string;
|
|
857
|
+
addController?: string[];
|
|
858
|
+
tunnel?: string;
|
|
859
|
+
endpoint?: string;
|
|
860
|
+
tunnelId?: string;
|
|
861
|
+
checkUpdates?: boolean;
|
|
862
|
+
json?: boolean;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
function collectOption(value: string, previous: string[] = []): string[] {
|
|
866
|
+
return [...previous, value];
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
function syncExplicitRemoteControllerEndpoint(profile: SetupProfile | undefined, endpoint: string | undefined): void {
|
|
870
|
+
if (!profile || !endpoint || !profile.controllers.some((controller) => controller === 'chatgpt' || controller === 'mcp')) return;
|
|
871
|
+
runMcpSetupChatgpt({ userLevel: true, endpoint });
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
function setupCycle(rawOpts: SetupCycleRawOptions, surface: string): void {
|
|
782
875
|
try {
|
|
876
|
+
let profile = readSetupProfile();
|
|
877
|
+
if (rawOpts.controller || rawOpts.addController?.length || rawOpts.tunnel || rawOpts.endpoint || rawOpts.tunnelId) {
|
|
878
|
+
profile = configureSetupProfile({
|
|
879
|
+
controller: rawOpts.controller,
|
|
880
|
+
addControllers: rawOpts.addController,
|
|
881
|
+
tunnel: rawOpts.tunnel,
|
|
882
|
+
endpoint: rawOpts.endpoint,
|
|
883
|
+
tunnelId: rawOpts.tunnelId,
|
|
884
|
+
});
|
|
885
|
+
syncExplicitRemoteControllerEndpoint(profile, rawOpts.endpoint);
|
|
886
|
+
}
|
|
783
887
|
const session = openSetupSession({
|
|
784
|
-
|
|
888
|
+
profile,
|
|
889
|
+
target: setupTarget(rawOpts.target, surface) ?? setupHostTarget(profile),
|
|
785
890
|
checkUpdates: rawOpts.checkUpdates === true,
|
|
786
891
|
});
|
|
787
892
|
console.log(formatSetupSession(session, rawOpts.json === true));
|
|
@@ -792,33 +897,69 @@ function setupCycle(rawOpts: { target: string; checkUpdates?: boolean; json?: bo
|
|
|
792
897
|
}
|
|
793
898
|
}
|
|
794
899
|
|
|
900
|
+
function addSetupSelectionOptions(command: Command): Command {
|
|
901
|
+
return command
|
|
902
|
+
.option('--controller <controller>', 'Primary external controller: chatgpt|codex|claude|mcp')
|
|
903
|
+
.option('--add-controller <controller>', 'Also configure another external controller entry (repeatable)', collectOption, [])
|
|
904
|
+
.option('--tunnel <provider>', 'Remote connection: auto|openai|cloudflare|tailscale|existing|none')
|
|
905
|
+
.option('--tunnel-id <id>', 'OpenAI Secure MCP Tunnel id (non-secret tunnel_...)')
|
|
906
|
+
.option('--endpoint <url>', 'Existing/stable public HTTPS URL ending in /mcp')
|
|
907
|
+
.option('--target <target>', `Deprecated host-tooling override: ${VALID_TARGETS.join('|')}`)
|
|
908
|
+
.option('--check-updates', 'Include network-backed version update advisories')
|
|
909
|
+
.option('--json', 'Output JSON instead of human-readable text');
|
|
910
|
+
}
|
|
911
|
+
|
|
795
912
|
export function buildSetupCommand(): Command {
|
|
796
913
|
const command = new Command('setup');
|
|
797
914
|
command
|
|
798
|
-
.description('
|
|
799
|
-
.option('--target <target>', `Host target to configure: ${VALID_TARGETS.join('|')}`, 'both')
|
|
915
|
+
.description('Configure Forge around one external controller brain and optional additional controller entries')
|
|
800
916
|
.option('--check-updates', 'Include network-backed version update advisories')
|
|
801
917
|
.option('--json', 'Output JSON instead of human-readable text')
|
|
802
|
-
.action((rawOpts:
|
|
918
|
+
.action((rawOpts: SetupCycleRawOptions) => setupCycle(rawOpts, 'forge setup'));
|
|
803
919
|
|
|
804
920
|
for (const name of ['open', 'next'] as const) {
|
|
805
|
-
command
|
|
921
|
+
addSetupSelectionOptions(command
|
|
806
922
|
.command(name)
|
|
807
|
-
.description(name === 'open' ? 'Start or resume the
|
|
808
|
-
.
|
|
809
|
-
.option('--check-updates', 'Include network-backed version update advisories')
|
|
810
|
-
.option('--json', 'Output JSON instead of human-readable text')
|
|
811
|
-
.action((rawOpts: { target: string; checkUpdates?: boolean; json?: boolean }) => setupCycle(rawOpts, `forge setup ${name}`));
|
|
923
|
+
.description(name === 'open' ? 'Start or resume the guided Forge setup session' : 'Re-check configuration and advance to the next action'))
|
|
924
|
+
.action((rawOpts: SetupCycleRawOptions) => setupCycle(rawOpts, `forge setup ${name}`));
|
|
812
925
|
}
|
|
813
926
|
|
|
927
|
+
command
|
|
928
|
+
.command('configure')
|
|
929
|
+
.description('Choose the primary external controller, optional additional controllers, and public access provider')
|
|
930
|
+
.requiredOption('--controller <controller>', 'Primary external controller: chatgpt|codex|claude|mcp')
|
|
931
|
+
.option('--add-controller <controller>', 'Also configure another external controller entry (repeatable)', collectOption, [])
|
|
932
|
+
.option('--tunnel <provider>', 'Remote connection: auto|openai|cloudflare|tailscale|existing|none')
|
|
933
|
+
.option('--tunnel-id <id>', 'OpenAI Secure MCP Tunnel id (non-secret tunnel_...)')
|
|
934
|
+
.option('--endpoint <url>', 'Existing/stable public HTTPS URL ending in /mcp')
|
|
935
|
+
.option('--json', 'Output JSON instead of human-readable text')
|
|
936
|
+
.action((rawOpts: { controller: string; addController?: string[]; tunnel?: string; tunnelId?: string; endpoint?: string; json?: boolean }) => {
|
|
937
|
+
try {
|
|
938
|
+
const profile = configureSetupProfile({
|
|
939
|
+
controller: rawOpts.controller,
|
|
940
|
+
addControllers: rawOpts.addController,
|
|
941
|
+
tunnel: rawOpts.tunnel,
|
|
942
|
+
endpoint: rawOpts.endpoint,
|
|
943
|
+
tunnelId: rawOpts.tunnelId,
|
|
944
|
+
});
|
|
945
|
+
syncExplicitRemoteControllerEndpoint(profile, rawOpts.endpoint);
|
|
946
|
+
console.log(rawOpts.json ? JSON.stringify(profile, null, 2) : `${formatSetupProfile(profile)}\n\nNext: forge setup next`);
|
|
947
|
+
} catch (error) {
|
|
948
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
949
|
+
process.exitCode = 2;
|
|
950
|
+
}
|
|
951
|
+
});
|
|
952
|
+
|
|
814
953
|
command
|
|
815
954
|
.command('status')
|
|
816
|
-
.description('Read the persisted setup session
|
|
955
|
+
.description('Read the persisted setup session and external-controller profile')
|
|
817
956
|
.option('--json', 'Output JSON instead of human-readable text')
|
|
818
957
|
.action((rawOpts: { json?: boolean }) => {
|
|
819
958
|
const session = readSetupSession();
|
|
959
|
+
const profile = readSetupProfile();
|
|
820
960
|
if (!session) {
|
|
821
|
-
|
|
961
|
+
if (rawOpts.json) console.log(JSON.stringify({ status: 'not_started', profile }, null, 2));
|
|
962
|
+
else console.log(profile ? `forge setup: not started\n${formatSetupProfile(profile)}\nRun: forge setup open` : 'forge setup: not started\nRun: forge setup');
|
|
822
963
|
return;
|
|
823
964
|
}
|
|
824
965
|
console.log(formatSetupSession(session, rawOpts.json === true));
|
|
@@ -826,15 +967,16 @@ export function buildSetupCommand(): Command {
|
|
|
826
967
|
|
|
827
968
|
command
|
|
828
969
|
.command('close')
|
|
829
|
-
.description('Close setup after
|
|
830
|
-
.option('--target <target>', `Host target to verify: ${VALID_TARGETS.join('|')}`, 'both')
|
|
970
|
+
.description('Close setup after the selected external controller path is ready')
|
|
831
971
|
.option('--check-updates', 'Include network-backed version update advisories')
|
|
832
972
|
.option('--force', 'Close even when checks still need attention')
|
|
833
973
|
.option('--json', 'Output JSON instead of human-readable text')
|
|
834
|
-
.action((rawOpts: {
|
|
974
|
+
.action((rawOpts: { checkUpdates?: boolean; force?: boolean; json?: boolean }) => {
|
|
835
975
|
try {
|
|
976
|
+
const profile = readSetupProfile();
|
|
836
977
|
const session = closeSetupSession({
|
|
837
|
-
|
|
978
|
+
profile,
|
|
979
|
+
target: setupHostTarget(profile),
|
|
838
980
|
checkUpdates: rawOpts.checkUpdates === true,
|
|
839
981
|
force: rawOpts.force === true,
|
|
840
982
|
});
|
|
@@ -848,14 +990,15 @@ export function buildSetupCommand(): Command {
|
|
|
848
990
|
|
|
849
991
|
command
|
|
850
992
|
.command('check')
|
|
851
|
-
.description('Run the
|
|
852
|
-
.option('--target <target>', `Host
|
|
993
|
+
.description('Run the read-only readiness checklist for the configured external controller set')
|
|
994
|
+
.option('--target <target>', `Host-tooling override: ${VALID_TARGETS.join('|')}`)
|
|
853
995
|
.option('--check-updates', 'Include network-backed version update advisories')
|
|
854
996
|
.option('--json', 'Output JSON instead of human-readable text')
|
|
855
|
-
.action((rawOpts: { target
|
|
997
|
+
.action((rawOpts: { target?: string; checkUpdates?: boolean; json?: boolean }) => {
|
|
856
998
|
try {
|
|
999
|
+
const profile = readSetupProfile();
|
|
857
1000
|
const report = runInitHook({
|
|
858
|
-
target: setupTarget(rawOpts.target, 'forge setup check'),
|
|
1001
|
+
target: setupTarget(rawOpts.target, 'forge setup check') ?? setupHostTarget(profile),
|
|
859
1002
|
checkUpdates: rawOpts.checkUpdates === true,
|
|
860
1003
|
});
|
|
861
1004
|
console.log(formatInitHook(report, rawOpts.json === true));
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Existing-repository Forge bootstrap/update implementation.
|
|
3
3
|
*
|
|
4
|
-
* This backs the public `forge adopt` command and the
|
|
5
|
-
* `forge-init` skill facade: default the target repo to cwd,
|
|
4
|
+
* This backs the public `forge adopt` command and reusable bootstrap primitives: default the target repo to cwd,
|
|
6
5
|
* install/refresh the machine runtime pieces, apply the repo-local workflow
|
|
7
6
|
* migration, then verify the installed harness.
|
|
8
7
|
*/
|
|
@@ -382,7 +381,7 @@ export function runInit(opts: InitCommandOptions = {}): InitCommandResult {
|
|
|
382
381
|
const verify = opts.verify !== false;
|
|
383
382
|
const syncSkill = opts.syncSkill !== false;
|
|
384
383
|
const hostAdapters = opts.hostAdapters !== false;
|
|
385
|
-
const externalSkills = opts.externalSkills
|
|
384
|
+
const externalSkills = opts.externalSkills === true;
|
|
386
385
|
const codegraph = opts.codegraph !== false;
|
|
387
386
|
const configureCgMcp = opts.configureCodegraphMcp === true;
|
|
388
387
|
const syncCodegraph = opts.syncCodegraph === true;
|
|
@@ -576,15 +575,15 @@ export function runInit(opts: InitCommandOptions = {}): InitCommandResult {
|
|
|
576
575
|
steps.push(
|
|
577
576
|
withStepName(
|
|
578
577
|
handoff,
|
|
579
|
-
"refresh
|
|
578
|
+
"refresh session continuation",
|
|
580
579
|
"scripts/prepare-codex-handoff.sh --reason forge-adopt-verify",
|
|
581
580
|
),
|
|
582
581
|
);
|
|
583
582
|
} else {
|
|
584
583
|
steps.push({
|
|
585
|
-
step: "refresh
|
|
584
|
+
step: "refresh session continuation",
|
|
586
585
|
status: "skipped",
|
|
587
|
-
detail: "scripts/prepare-codex-handoff.sh
|
|
586
|
+
detail: "session continuation helper missing (legacy filename scripts/prepare-codex-handoff.sh)",
|
|
588
587
|
});
|
|
589
588
|
}
|
|
590
589
|
}
|
package/src/cli/commands/mcp.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
runMcpPrintGuide,
|
|
13
13
|
runMcpSetupChatgpt,
|
|
14
14
|
runMcpSetupCodex,
|
|
15
|
+
runMcpSetupClaude,
|
|
15
16
|
} from '../mcp/setup';
|
|
16
17
|
|
|
17
18
|
export interface McpServeOptions {
|
|
@@ -42,15 +43,20 @@ interface McpAccessOptions {
|
|
|
42
43
|
|
|
43
44
|
interface McpSetupChatgptOptions {
|
|
44
45
|
repo?: string;
|
|
46
|
+
controllerHome?: string;
|
|
47
|
+
userLevel?: boolean;
|
|
45
48
|
host?: string;
|
|
46
49
|
port?: string;
|
|
47
50
|
endpoint?: string;
|
|
48
51
|
serverName?: string;
|
|
52
|
+
localControllerPort?: string;
|
|
53
|
+
connectorPort?: string;
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
interface
|
|
56
|
+
interface McpSetupLocalControllerOptions {
|
|
52
57
|
repo?: string;
|
|
53
58
|
scope?: string;
|
|
59
|
+
profile?: string;
|
|
54
60
|
dryRun?: boolean;
|
|
55
61
|
}
|
|
56
62
|
|
|
@@ -221,14 +227,18 @@ export function buildMcpCommand(): Command {
|
|
|
221
227
|
});
|
|
222
228
|
});
|
|
223
229
|
|
|
224
|
-
const setup = new Command('setup').description('
|
|
230
|
+
const setup = new Command('setup').description('Configure an external controller connection to Forge');
|
|
225
231
|
|
|
226
232
|
setup
|
|
227
233
|
.command('chatgpt')
|
|
228
234
|
.description('Generate ChatGPT Connector local config and manual setup guide')
|
|
229
235
|
.option('--repo <path>', 'Repository root to configure', '.')
|
|
236
|
+
.option('--controller-home <path>', 'User Controller Home (used with --user-level)')
|
|
237
|
+
.option('--user-level', 'Configure the user-level Controller without writing repository guide/gitignore files')
|
|
230
238
|
.option('--host <host>', 'Local MCP HTTP bind host', '127.0.0.1')
|
|
231
239
|
.option('--port <port>', 'Local MCP HTTP bind port', '8765')
|
|
240
|
+
.option('--local-controller-port <port>', 'Local-only Utility Console port; defaults to MCP port + 1')
|
|
241
|
+
.option('--connector-port <port>', 'Loopback OAuth connector port for ChatGPT tunnels; defaults to MCP port + 2')
|
|
232
242
|
.option('--endpoint <url>', 'Stable public HTTPS /mcp endpoint to store in ignored local config')
|
|
233
243
|
.option('--server-name <name>', 'ChatGPT Connector/MCP server name to record in ignored local config')
|
|
234
244
|
.action((rawOpts: McpSetupChatgptOptions) => {
|
|
@@ -240,17 +250,33 @@ export function buildMcpCommand(): Command {
|
|
|
240
250
|
|
|
241
251
|
setup
|
|
242
252
|
.command('codex')
|
|
243
|
-
.description('
|
|
253
|
+
.description('Configure Codex as an explicit Forge controller or executor')
|
|
244
254
|
.option('--repo <path>', 'Repository root to configure', '.')
|
|
245
255
|
.option('--scope <scope>', 'Config scope: project|user', 'project')
|
|
256
|
+
.option('--profile <profile>', 'Forge MCP role: controller|executor', 'executor')
|
|
246
257
|
.option('--dry-run', 'Print planned changes without writing files')
|
|
247
|
-
.action((rawOpts:
|
|
258
|
+
.action((rawOpts: McpSetupLocalControllerOptions) => {
|
|
248
259
|
void runMcpAction(() => {
|
|
249
260
|
const result = runMcpSetupCodex(rawOpts);
|
|
250
261
|
console.log(result.lines.join('\n'));
|
|
251
262
|
});
|
|
252
263
|
});
|
|
253
264
|
|
|
265
|
+
|
|
266
|
+
setup
|
|
267
|
+
.command('claude')
|
|
268
|
+
.description('Configure Claude Code as an explicit Forge controller or executor through the Claude CLI')
|
|
269
|
+
.option('--repo <path>', 'Repository root to expose initially', '.')
|
|
270
|
+
.option('--scope <scope>', 'Claude MCP scope: local|project|user', 'user')
|
|
271
|
+
.option('--profile <profile>', 'Forge MCP role: controller|executor', 'controller')
|
|
272
|
+
.option('--dry-run', 'Print the Claude MCP command without changing Claude config')
|
|
273
|
+
.action((rawOpts: McpSetupLocalControllerOptions) => {
|
|
274
|
+
void runMcpAction(() => {
|
|
275
|
+
const result = runMcpSetupClaude(rawOpts);
|
|
276
|
+
console.log(result.lines.join('\n'));
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
|
|
254
280
|
mcp.addCommand(setup);
|
|
255
281
|
|
|
256
282
|
const access = new Command('access').description('Read or change repository Request / Full Access permission levels');
|
|
@@ -284,7 +310,7 @@ export function buildMcpCommand(): Command {
|
|
|
284
310
|
|
|
285
311
|
mcp
|
|
286
312
|
.command('prepare-goal')
|
|
287
|
-
.description('Prepare .ai/harness/
|
|
313
|
+
.description('Prepare .ai/harness/controller/packets/codex-goal.md and print a host-native /goal prompt from a PRD and checklist Sprint')
|
|
288
314
|
.option('--repo <path>', 'Repository root to configure', '.')
|
|
289
315
|
.requiredOption('--prd <path>', 'PRD path to read')
|
|
290
316
|
.requiredOption('--sprint <path>', 'Checklist Sprint path to execute')
|