@moretea-labs/forge 1.5.0-rc.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -11
- package/CHANGELOG.md +19 -0
- package/CLAUDE.md +8 -10
- package/DESIGN.md +278 -0
- package/README.md +70 -90
- package/README.zh-CN.md +50 -55
- package/SKILL.md +8 -11
- package/THIRD_PARTY_NOTICES.md +9 -3
- package/assets/branding/README.md +4 -2
- package/assets/hooks/lib/workflow-state.sh +19 -18
- package/assets/hooks/post-edit-guard.sh +6 -75
- package/assets/hooks/prompt-guard.sh +24 -12
- package/assets/hooks/session-start-context.sh +17 -17
- package/assets/hooks/stop-orchestrator.sh +2 -2
- package/assets/partials/04-project-structure.partial.md +6 -6
- package/assets/partials/05-workflow.partial.md +6 -6
- package/assets/partials/07-footer.partial.md +1 -1
- package/assets/partials/08-orchestration.partial.md +2 -2
- package/assets/partials-agents/02-operating-mode.partial.md +5 -5
- package/assets/partials-agents/03-orchestration.partial.md +3 -3
- package/assets/partials-agents/04-task-protocol.partial.md +3 -3
- package/assets/partials-agents/08-deep-docs.partial.md +1 -1
- package/assets/reference-configs/agentic-development-flow.md +49 -86
- package/assets/reference-configs/external-tooling.md +21 -61
- package/assets/reference-configs/handoff-protocol.md +25 -20
- package/assets/reference-configs/harness-overview.md +8 -8
- package/assets/templates/helpers/archive-workflow.sh +0 -1
- package/assets/templates/helpers/capture-plan.sh +3 -3
- package/assets/templates/helpers/check-task-workflow.sh +2 -2
- package/assets/templates/helpers/codex-handoff-resume.sh +5 -5
- package/assets/templates/helpers/ensure-task-workflow.sh +37 -35
- package/assets/templates/helpers/new-plan.sh +1 -1
- package/assets/templates/helpers/plan-to-todo.sh +2 -2
- package/assets/templates/helpers/prepare-codex-handoff.sh +2 -2
- package/assets/templates/helpers/prepare-handoff.sh +9 -9
- package/assets/templates/helpers/refresh-current-status.sh +2 -2
- package/assets/templates/helpers/ship-worktrees.sh +1 -1
- package/assets/templates/helpers/sprint-backlog.sh +1 -1
- package/assets/templates/helpers/verify-sprint.sh +7 -7
- package/assets/templates/helpers/workstream-sync.sh +1 -1
- package/assets/templates/plan.template.md +1 -1
- package/assets/workflow-contract.v1.json +6 -3
- package/docs/architecture/current/README.md +10 -9
- package/docs/architecture/current/approved-target-architecture.zh-CN.md +2 -2
- package/docs/architecture/current/architecture-invariants.md +2 -2
- package/docs/architecture/current/automation-and-schedule-engine.md +15 -15
- package/docs/architecture/current/codegraph-context-provider.md +2 -2
- package/docs/architecture/current/control-plane-authority-inventory.md +12 -0
- package/docs/architecture/current/dispatch-and-agent-strategy.md +11 -11
- package/docs/architecture/current/entity-model.md +0 -27
- package/docs/architecture/current/failure-recovery.md +0 -24
- package/docs/architecture/current/governance.md +1 -1
- package/docs/architecture/current/implementation-status.md +1 -1
- package/docs/architecture/current/legacy-governance.md +58 -0
- package/docs/architecture/current/multi-repository-execution.md +1 -1
- package/docs/architecture/current/peer-supercontroller-runtime.md +1 -1
- package/docs/architecture/current/personal-assistant-plugin-baseline.md +4 -5
- package/docs/architecture/current/scheduler-and-resource-claims.md +0 -10
- package/docs/architecture/current/target-requirements-traceability.md +2 -2
- package/docs/architecture/current/thin-harness-governance-policy.md +1 -1
- package/docs/architecture/current/thin-harness-v1.md +9 -11
- package/docs/architecture/domains/runtime-harness.md +1 -1
- package/docs/forge-autonomous-goal-loop.md +3 -1
- package/docs/forge-chatgpt-mcp-setup.md +51 -184
- package/docs/images/forge-banner-cn.svg +26 -1
- package/docs/images/forge-banner.svg +26 -1
- package/docs/operations/features.md +1 -1
- package/docs/operations/homebrew.md +3 -3
- package/docs/operations/mcp-tool-exposure.md +5 -5
- package/docs/operations/platform-support.md +45 -37
- package/docs/operations/platform-support.zh-CN.md +40 -38
- package/docs/operations/releasing.md +3 -3
- package/docs/operations/releasing.zh-CN.md +3 -3
- package/docs/operations/troubleshooting.md +11 -6
- package/docs/operations/troubleshooting.zh-CN.md +11 -6
- package/docs/public-usage-guide.md +28 -21
- package/docs/public-usage-guide.zh-CN.md +28 -21
- package/docs/tutorials/01-install-and-start.md +56 -35
- package/docs/tutorials/01-install-and-start.zh-CN.md +56 -35
- package/docs/tutorials/02-connect-chatgpt.md +112 -46
- package/docs/tutorials/02-connect-chatgpt.zh-CN.md +113 -45
- package/docs/wiki/Architecture.md +1 -1
- package/docs/wiki/Installation.md +2 -2
- package/docs/wiki/Quick-Start.md +1 -1
- package/docs/wiki/Work-Lifecycle.md +1 -1
- package/install.ps1 +4 -5
- package/install.sh +4 -6
- package/package.json +15 -5
- package/scripts/archive-workflow.sh +0 -1
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +27 -14
- package/scripts/build-controller-ui.ts +28 -0
- package/scripts/capture-plan.sh +4 -4
- package/scripts/check-agent-tooling.sh +12 -1
- package/scripts/check-platform-support.mjs +2 -2
- package/scripts/check-public-docs.sh +16 -5
- package/scripts/check-release-readiness.sh +5 -11
- package/scripts/check-runtime-architecture.mjs +14 -22
- package/scripts/check-tarball-install-smoke.sh +3 -2
- package/scripts/check-task-workflow.sh +2 -2
- package/scripts/codex-handoff-resume.sh +5 -5
- package/scripts/create-project-dirs.sh +3 -3
- package/scripts/ensure-task-workflow.sh +45 -35
- package/scripts/init-project.sh +4 -4
- package/scripts/install-desktop-operator-registration.ts +2 -2
- package/scripts/lib/project-init-lib.sh +46 -44
- package/scripts/migrate-project-template.sh +7 -4
- package/scripts/new-plan.sh +1 -1
- package/scripts/plan-to-todo.sh +2 -2
- package/scripts/prepare-codex-handoff.sh +2 -2
- package/scripts/prepare-handoff.sh +9 -9
- package/scripts/refresh-current-status.sh +2 -2
- package/scripts/setup-plugins.sh +3 -3
- package/scripts/ship-worktrees.sh +1 -1
- package/scripts/sprint-backlog.sh +5 -5
- package/scripts/sync-codex-installed-copies.sh +2 -3
- package/scripts/verify-sprint.sh +7 -7
- package/scripts/workstream-sync.sh +1 -1
- package/src/cli/chatgpt-browser/bridge-extension.ts +1 -1
- package/src/cli/chatgpt-browser/bridge-provider.ts +29 -0
- package/src/cli/chatgpt-browser/file-policy.ts +3 -1
- package/src/cli/commands/chatgpt.ts +51 -0
- package/src/cli/commands/doctor.ts +1 -1
- package/src/cli/commands/init-hook.ts +211 -70
- package/src/cli/commands/init.ts +5 -6
- package/src/cli/commands/mcp.ts +29 -5
- package/src/cli/commands/runtime.ts +60 -8
- package/src/cli/commands/setup-profile.ts +441 -0
- package/src/cli/controller/check-runner.ts +20 -3
- package/src/cli/controller/codex-continuation.ts +4 -7
- package/src/cli/controller/context-pack.ts +118 -14
- package/src/cli/controller/operational-plan.ts +4 -4
- package/src/cli/controller/task-ledger.ts +10 -10
- package/src/cli/controller/work-mode.ts +6 -13
- package/src/cli/index.ts +14 -35
- package/src/cli/local-bridge/connector-freshness.ts +1 -1
- package/src/cli/local-bridge/console-automations.ts +160 -0
- package/src/cli/local-bridge/dashboard.ts +8 -1303
- package/src/cli/local-bridge/facade-api.ts +16 -7
- package/src/cli/local-bridge/frontend/src/App.tsx +10 -0
- package/src/cli/local-bridge/frontend/src/components/Button.tsx +1 -0
- package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +3 -0
- package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +1 -0
- package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +1 -0
- package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +1 -0
- package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +3 -0
- package/src/cli/local-bridge/frontend/src/design/icons.tsx +11 -0
- package/src/cli/local-bridge/frontend/src/design/tokens.css +8 -0
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +3 -0
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +4 -0
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +3 -0
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +2 -0
- package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +2 -0
- package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +2 -0
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +3 -0
- package/src/cli/local-bridge/frontend/src/lib/api.ts +23 -0
- package/src/cli/local-bridge/frontend/src/lib/format.ts +4 -0
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +7 -0
- package/src/cli/local-bridge/frontend/src/main.tsx +1 -0
- package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +1 -0
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +2 -0
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +3 -0
- package/src/cli/local-bridge/frontend/src/styles.css +12 -0
- package/src/cli/local-bridge/frontend/src/types.ts +14 -0
- package/src/cli/local-bridge/frontend/src/vite-env.d.ts +1 -0
- package/src/cli/local-bridge/frontend/vite.config.ts +27 -0
- package/src/cli/local-bridge/server.ts +44 -0
- package/src/cli/local-bridge/ui-dist/app.css +1 -0
- package/src/cli/local-bridge/ui-dist/app.js +11094 -0
- package/src/cli/mcp/instructions.ts +3 -3
- package/src/cli/mcp/legacy-tool-service.ts +27 -23
- package/src/cli/mcp/multi-repository.ts +2 -0
- package/src/cli/mcp/policy.ts +7 -5
- package/src/cli/mcp/repository-tools.ts +53 -14
- package/src/cli/mcp/server.ts +5 -10
- package/src/cli/mcp/setup.ts +211 -275
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/toolset-names.ts +1 -1
- package/src/cli/mcp/toolset.ts +0 -1
- package/src/cli/mcp/transports/http.ts +24 -4
- package/src/cli/repositories/branch-name-policy.ts +0 -7
- package/src/cli/repositories/controller-home.ts +110 -3
- package/src/cli/repositories/safe-patch.ts +1 -1
- package/src/cli/repositories/selected-path-actions.ts +26 -24
- package/src/core/adoption/gitignore-plan.ts +2 -3
- package/src/core/adoption/plan.ts +4 -1
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +556 -0
- package/src/runtime/control-plane/execution/work-handle-store.ts +128 -1
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +277 -0
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +169 -0
- package/src/runtime/control-plane/facade/capability-registry.ts +0 -10
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +44 -25
- package/src/runtime/control-plane/facade/suggested-actions.ts +7 -1
- package/src/runtime/control-plane/facade/types.ts +0 -1
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +30 -8
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +114 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +175 -0
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +161 -0
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +64 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +117 -24
- package/src/runtime/control-plane/routing/route-policy.ts +14 -14
- package/src/runtime/control-plane/runtime-cleanup.ts +0 -1
- package/src/runtime/evidence/event-ledger.ts +1 -1
- package/src/runtime/{workflow/campaigns/workspace.ts → execution/managed-workspace.ts} +41 -43
- package/src/runtime/execution/process-runtime/check-facade.ts +6 -0
- package/src/runtime/execution/process-runtime/check-result.ts +45 -0
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +42 -16
- package/src/runtime/execution/process-runtime/command-facade.ts +4 -2
- package/src/runtime/execution/process-runtime/gc.ts +1 -1
- package/src/runtime/execution/process-runtime/index.ts +3 -0
- package/src/runtime/execution/process-runtime/interactive-admission.ts +14 -5
- package/src/runtime/execution/process-runtime/persisted-check.ts +285 -0
- package/src/runtime/execution/process-runtime/resource-claims.ts +30 -0
- package/src/runtime/execution/process-runtime/runtime.ts +18 -1
- package/src/runtime/execution/process-runtime/store.ts +1 -19
- package/src/runtime/execution/process-runtime/types.ts +4 -0
- package/src/runtime/execution/thin-harness/execution-router.ts +0 -1
- package/src/runtime/execution/thin-harness/fast-executor.ts +1 -1
- package/src/runtime/execution/thin-harness/lightweight-lanes.ts +1 -2
- package/src/runtime/execution/thin-harness/types.ts +0 -1
- package/src/runtime/execution/workers/executor.ts +1 -1
- package/src/runtime/gateway/mcp/execution-tools.ts +1 -1
- package/src/runtime/gateway/mcp/persisted-check-process.ts +3 -255
- package/src/runtime/gateway/mcp/process-tools.ts +16 -3
- package/src/runtime/gateway/mcp/resource-policy.ts +0 -9
- package/src/runtime/gateway/mcp/router.ts +117 -182
- package/src/runtime/gateway/mcp/runtime-tools.ts +331 -409
- package/src/runtime/gateway/mcp/work-validation-reconciler.ts +1 -219
- package/src/runtime/plugins/browser-adapter.ts +5 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +1 -1
- package/src/runtime/plugins/store.ts +14 -6
- package/src/runtime/plugins/types.ts +1 -1
- package/src/runtime/projections/materialized-view.ts +1 -23
- package/src/runtime/recovery/maintenance-executor.ts +9 -0
- package/src/runtime/resources/ownership.ts +0 -1
- package/src/runtime/root/gateway-adapter.ts +2 -0
- package/src/runtime/root/mcp-transport.ts +10 -2
- package/src/runtime/root/package-runtime-release.ts +161 -0
- package/src/runtime/root/package-runtime-service.ts +172 -0
- package/src/runtime/root/runtime.ts +2 -1
- package/src/runtime/root/scheduler.ts +5 -0
- package/src/runtime/root/service.ts +18 -5
- package/src/runtime/standalone-recovery/core.ts +65 -16
- package/src/runtime/workflow/findings/store.ts +145 -106
- package/src/runtime/workflow/findings/types.ts +22 -0
- package/src/runtime/workflow/schedules/engine.ts +132 -2
- package/src/runtime/workflow/schedules/pending-activation.ts +139 -0
- package/src/runtime/workflow/schedules/work-continuation.ts +218 -0
- package/docs/CHANGELOG.md +0 -978
- package/docs/README.zh-CN.md +0 -58
- package/scripts/smoke-chatgpt-supervised-automation.ts +0 -208
- package/src/cli/commands/controller.ts +0 -680
- package/src/runtime/workflow/campaigns/cleanup.ts +0 -263
- package/src/runtime/workflow/campaigns/engine.ts +0 -112
- package/src/runtime/workflow/campaigns/normalize.ts +0 -100
- package/src/runtime/workflow/campaigns/review.ts +0 -315
- package/src/runtime/workflow/campaigns/store.ts +0 -526
- package/src/runtime/workflow/campaigns/supervisor.ts +0 -112
- package/src/runtime/workflow/campaigns/types.ts +0 -290
- /package/src/runtime/{workflow/campaigns → execution}/workspace-agent.ts +0 -0
|
@@ -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,22 @@ 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 {
|
|
21
|
+
configureSetupProfile,
|
|
22
|
+
detectSetupPlatform,
|
|
23
|
+
formatSetupProfile,
|
|
24
|
+
readSetupProfile,
|
|
25
|
+
resolveControllerGuidance,
|
|
26
|
+
resolveRuntimeGuidance,
|
|
27
|
+
resolveTunnelGuidance,
|
|
28
|
+
setupHostTarget,
|
|
29
|
+
type SetupHostTarget,
|
|
30
|
+
type SetupPlatformSnapshot,
|
|
31
|
+
type SetupProfile,
|
|
32
|
+
} from './setup-profile';
|
|
33
|
+
|
|
34
|
+
export type InitHookTarget = SetupHostTarget;
|
|
22
35
|
export type InitHookStatus = 'ok' | 'attention' | 'blocked';
|
|
23
36
|
export type InitHookCheckStatus = CheckStatus | 'needs_agent';
|
|
24
37
|
export type InitHookCheckSource =
|
|
@@ -108,7 +121,7 @@ const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
|
|
|
108
121
|
const REPO_ROOT = resolve(SCRIPT_DIR, '..', '..', '..');
|
|
109
122
|
const UPDATE_CHECK_ENV = 'FORGE_CHECK_UPDATES';
|
|
110
123
|
const GLOBAL_RULES_BEGIN = '<!-- BEGIN: forge global-working-rules -->';
|
|
111
|
-
const VALID_TARGETS: readonly InitHookTarget[] = ['codex', 'claude', 'both'];
|
|
124
|
+
const VALID_TARGETS: readonly InitHookTarget[] = ['none', 'codex', 'claude', 'both'];
|
|
112
125
|
|
|
113
126
|
function withProcessEnv<T>(env: NodeJS.ProcessEnv | undefined, fn: () => T): T {
|
|
114
127
|
if (!env) return fn();
|
|
@@ -129,6 +142,7 @@ function withProcessEnv<T>(env: NodeJS.ProcessEnv | undefined, fn: () => T): T {
|
|
|
129
142
|
}
|
|
130
143
|
|
|
131
144
|
function selectedTargets(target: InitHookTarget): Array<'codex' | 'claude'> {
|
|
145
|
+
if (target === 'none') return [];
|
|
132
146
|
if (target === 'both') return ['codex', 'claude'];
|
|
133
147
|
return [target];
|
|
134
148
|
}
|
|
@@ -230,6 +244,19 @@ function parseActionCommand(detail: string): string | undefined {
|
|
|
230
244
|
return run?.[1]?.trim();
|
|
231
245
|
}
|
|
232
246
|
|
|
247
|
+
function doctorEntryRelevant(id: string, target: InitHookTarget): boolean {
|
|
248
|
+
if (id === 'cli-on-path' || id === 'cli-version' || id === 'cli-update' || id === 'security-config') return true;
|
|
249
|
+
if (target === 'none') return false;
|
|
250
|
+
if (id === 'repo-hook-scripts' || id === 'codegraph-readiness' || id === 'codegraph-index') return true;
|
|
251
|
+
if (target === 'codex' || target === 'both') {
|
|
252
|
+
if (id === 'codex-adapter' || id === 'codex-trust-state' || id === 'codex-codegraph-mcp') return true;
|
|
253
|
+
}
|
|
254
|
+
if (target === 'claude' || target === 'both') {
|
|
255
|
+
if (id === 'claude-adapter' || id === 'claude-codegraph-mcp') return true;
|
|
256
|
+
}
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
233
260
|
function doctorChecks(
|
|
234
261
|
report: DoctorReport,
|
|
235
262
|
target: InitHookTarget,
|
|
@@ -238,6 +265,7 @@ function doctorChecks(
|
|
|
238
265
|
): InitHookCheck[] {
|
|
239
266
|
const checks: InitHookCheck[] = [];
|
|
240
267
|
for (const entry of report.checks) {
|
|
268
|
+
if (!doctorEntryRelevant(entry.id, target)) continue;
|
|
241
269
|
const source: InitHookCheckSource = entry.id === 'security-config' ? 'security' : 'doctor';
|
|
242
270
|
let checkStatus: InitHookCheckStatus = entry.status;
|
|
243
271
|
|
|
@@ -425,7 +453,7 @@ function commandForToolGap(toolName: string, tool: ToolingTool, target: InitHook
|
|
|
425
453
|
return normalizeToolCommand(tool.install_command, target);
|
|
426
454
|
}
|
|
427
455
|
if (toolName === 'codex_automation_profile') {
|
|
428
|
-
return 'forge
|
|
456
|
+
return 'forge install --target codex --no-cli --no-hooks --no-codegraph';
|
|
429
457
|
}
|
|
430
458
|
return normalizeToolCommand(
|
|
431
459
|
tool.sync_command ?? tool.ensure_command ?? tool.mcp_install_command ?? tool.install_command ?? tool.upgrade_command,
|
|
@@ -579,24 +607,26 @@ function overallStatus(summary: InitHookReport['summary']): InitHookStatus {
|
|
|
579
607
|
export function runInitHook(opts: InitHookOptions = {}): InitHookReport {
|
|
580
608
|
const cwd = resolve(opts.cwd ?? process.cwd());
|
|
581
609
|
const sourceRoot = resolve(opts.sourceRoot ?? REPO_ROOT);
|
|
582
|
-
const target = opts.target ?? '
|
|
610
|
+
const target = opts.target ?? 'none';
|
|
583
611
|
const checkUpdates = opts.checkUpdates === true;
|
|
584
612
|
const actions: InitHookAction[] = [];
|
|
585
613
|
|
|
586
614
|
const statusReport = opts.statusReport ?? withProcessEnv(opts.env, () => runStatus(cwd));
|
|
587
615
|
const doctorEnv = { ...(opts.env ?? {}), [UPDATE_CHECK_ENV]: checkUpdates ? '1' : undefined };
|
|
588
616
|
const doctorReport = opts.doctorReport ?? withProcessEnv(doctorEnv, () => runDoctor(cwd));
|
|
589
|
-
const toolingProbe =
|
|
590
|
-
? { report:
|
|
591
|
-
:
|
|
617
|
+
const toolingProbe = target === 'none'
|
|
618
|
+
? { report: undefined, error: undefined }
|
|
619
|
+
: opts.toolingReport
|
|
620
|
+
? { report: opts.toolingReport, error: undefined }
|
|
621
|
+
: collectToolingReport(sourceRoot, cwd, target, checkUpdates, opts.env);
|
|
592
622
|
|
|
593
623
|
const checks: InitHookCheck[] = [
|
|
594
|
-
...statusChecks(statusReport, target, checkUpdates, actions),
|
|
624
|
+
...(target === 'none' ? [] : statusChecks(statusReport, target, checkUpdates, actions)),
|
|
595
625
|
...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),
|
|
626
|
+
...(target === 'none' ? [] : globalRulesChecks(target, opts.env, checkUpdates, actions)),
|
|
627
|
+
...(target === 'none' ? [] : runtimeCapabilityChecks(toolingProbe.report, target, checkUpdates, actions)),
|
|
628
|
+
...(target === 'none' ? [] : toolingChecks(toolingProbe.report, target, checkUpdates, actions, toolingProbe.error)),
|
|
629
|
+
...(target === 'none' ? [] : legacyChecks(cwd, target, checkUpdates, actions)),
|
|
600
630
|
];
|
|
601
631
|
|
|
602
632
|
const summary = summarize(checks);
|
|
@@ -617,7 +647,7 @@ export function formatInitHook(report: InitHookReport, asJson = false): string {
|
|
|
617
647
|
lines.push(`forge setup check: ${report.status}`);
|
|
618
648
|
lines.push(`target=${report.target}; check-updates=${report.checkUpdates ? 'on' : 'off'}`);
|
|
619
649
|
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-
|
|
650
|
+
`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
651
|
);
|
|
622
652
|
lines.push('');
|
|
623
653
|
lines.push('Checks:');
|
|
@@ -625,7 +655,7 @@ export function formatInitHook(report: InitHookReport, asJson = false): string {
|
|
|
625
655
|
lines.push(` [${check.status}] ${check.id}: ${check.detail}`);
|
|
626
656
|
}
|
|
627
657
|
lines.push('');
|
|
628
|
-
lines.push('
|
|
658
|
+
lines.push('Actions:');
|
|
629
659
|
if (report.agent_actions.length === 0) {
|
|
630
660
|
lines.push(' none');
|
|
631
661
|
} else {
|
|
@@ -640,30 +670,6 @@ export function formatInitHook(report: InitHookReport, asJson = false): string {
|
|
|
640
670
|
return lines.join('\n');
|
|
641
671
|
}
|
|
642
672
|
|
|
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
673
|
export type SetupSessionStatus = 'open' | 'blocked' | 'ready' | 'closed';
|
|
668
674
|
|
|
669
675
|
export interface SetupSession {
|
|
@@ -672,6 +678,8 @@ export interface SetupSession {
|
|
|
672
678
|
status: SetupSessionStatus;
|
|
673
679
|
target: InitHookTarget;
|
|
674
680
|
checkUpdates: boolean;
|
|
681
|
+
profile?: SetupProfile;
|
|
682
|
+
platform?: SetupPlatformSnapshot;
|
|
675
683
|
createdAt: string;
|
|
676
684
|
updatedAt: string;
|
|
677
685
|
closedAt?: string;
|
|
@@ -681,6 +689,10 @@ export interface SetupSession {
|
|
|
681
689
|
|
|
682
690
|
export interface SetupSessionOptions extends InitHookOptions {
|
|
683
691
|
setupRoot?: string;
|
|
692
|
+
profile?: SetupProfile;
|
|
693
|
+
platform?: SetupPlatformSnapshot;
|
|
694
|
+
controllerHome?: string;
|
|
695
|
+
accountHome?: string;
|
|
684
696
|
report?: InitHookReport;
|
|
685
697
|
now?: () => Date;
|
|
686
698
|
uuid?: () => string;
|
|
@@ -714,28 +726,85 @@ export function readSetupSession(options: Pick<SetupSessionOptions, 'setupRoot'
|
|
|
714
726
|
return readSetupSessionAt(setupSessionPath(options));
|
|
715
727
|
}
|
|
716
728
|
|
|
717
|
-
function setupStatus(report: InitHookReport): SetupSessionStatus {
|
|
729
|
+
function setupStatus(report: InitHookReport, nextAction?: InitHookAction): SetupSessionStatus {
|
|
718
730
|
if (report.status === 'blocked') return 'blocked';
|
|
719
|
-
if (report.status === 'ok' && report.agent_actions.length === 0) return 'ready';
|
|
731
|
+
if (report.status === 'ok' && report.agent_actions.length === 0 && !nextAction) return 'ready';
|
|
720
732
|
return 'open';
|
|
721
733
|
}
|
|
722
734
|
|
|
735
|
+
function profileNextAction(profile: SetupProfile | undefined, platform: SetupPlatformSnapshot, options: { controllerHome?: string; accountHome?: string } = {}): InitHookAction | undefined {
|
|
736
|
+
if (!profile) {
|
|
737
|
+
return {
|
|
738
|
+
id: 'controller.select',
|
|
739
|
+
status: 'needs_agent',
|
|
740
|
+
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.',
|
|
741
|
+
requires_agent: true,
|
|
742
|
+
risk: 'Writes only the local Forge setup profile. It does not install or authenticate third-party software.',
|
|
743
|
+
command: 'forge setup configure --controller chatgpt',
|
|
744
|
+
verification: 'forge setup next',
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
const controller = resolveControllerGuidance(profile, { controllerHome: options.controllerHome, home: options.accountHome });
|
|
748
|
+
if (controller && !controller.ready) {
|
|
749
|
+
return {
|
|
750
|
+
id: `controller.${controller.controller}.configure`,
|
|
751
|
+
status: 'needs_agent',
|
|
752
|
+
reason: `${controller.title}: ${controller.detail}`,
|
|
753
|
+
requires_agent: true,
|
|
754
|
+
risk: 'Configures only the explicitly selected external controller entry. Unselected Codex/Claude providers remain untouched.',
|
|
755
|
+
...(controller.command ? { command: controller.command } : {}),
|
|
756
|
+
verification: 'forge setup next',
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
const runtime = resolveRuntimeGuidance(profile, { controllerHome: options.controllerHome });
|
|
760
|
+
if (runtime && !runtime.ready) {
|
|
761
|
+
return {
|
|
762
|
+
id: 'runtime.package.install',
|
|
763
|
+
status: 'needs_agent',
|
|
764
|
+
reason: `${runtime.title}: ${runtime.detail}`,
|
|
765
|
+
requires_agent: true,
|
|
766
|
+
risk: 'Installs or diagnoses the user-level Forge Runtime only. Standalone Recovery and source-release activation are not part of normal setup.',
|
|
767
|
+
...(runtime.command ? { command: runtime.command } : {}),
|
|
768
|
+
verification: 'forge setup next',
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
const tunnel = resolveTunnelGuidance(profile, platform, { controllerHome: options.controllerHome });
|
|
772
|
+
if (!tunnel.ready) {
|
|
773
|
+
return {
|
|
774
|
+
id: `tunnel.${tunnel.provider}.configure`,
|
|
775
|
+
status: 'needs_agent',
|
|
776
|
+
reason: `${tunnel.title}: ${tunnel.detail}`,
|
|
777
|
+
requires_agent: true,
|
|
778
|
+
risk: 'Remote connectivity is provider-owned. Forge keeps its MCP listener on loopback; credentials, authentication, and account changes remain explicit.',
|
|
779
|
+
...(tunnel.command ? { command: tunnel.command } : {}),
|
|
780
|
+
verification: 'forge setup next',
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
return undefined;
|
|
784
|
+
}
|
|
785
|
+
|
|
723
786
|
export function openSetupSession(options: SetupSessionOptions = {}): SetupSession {
|
|
724
787
|
const path = setupSessionPath(options);
|
|
725
788
|
const previous = readSetupSessionAt(path);
|
|
726
|
-
const
|
|
789
|
+
const profile = options.profile ?? readSetupProfile(options);
|
|
790
|
+
const platform = options.platform ?? detectSetupPlatform({ env: options.env });
|
|
791
|
+
const target = options.target ?? setupHostTarget(profile);
|
|
792
|
+
const report = options.report ?? runInitHook({ ...options, target });
|
|
793
|
+
const nextAction = profileNextAction(profile, platform, { controllerHome: options.controllerHome, accountHome: options.accountHome }) ?? report.agent_actions[0];
|
|
727
794
|
const now = (options.now ?? (() => new Date()))().toISOString();
|
|
728
795
|
const reuse = previous && previous.status !== 'closed';
|
|
729
796
|
return writeSetupSessionAt(path, {
|
|
730
797
|
schemaVersion: 1,
|
|
731
798
|
sessionId: reuse ? previous.sessionId : (options.uuid ?? randomUUID)(),
|
|
732
|
-
status: setupStatus(report),
|
|
799
|
+
status: setupStatus(report, nextAction),
|
|
733
800
|
target: report.target,
|
|
734
801
|
checkUpdates: report.checkUpdates,
|
|
802
|
+
...(profile ? { profile } : {}),
|
|
803
|
+
platform,
|
|
735
804
|
createdAt: reuse ? previous.createdAt : now,
|
|
736
805
|
updatedAt: now,
|
|
737
806
|
lastReport: report,
|
|
738
|
-
...(
|
|
807
|
+
...(nextAction ? { nextAction } : {}),
|
|
739
808
|
});
|
|
740
809
|
}
|
|
741
810
|
|
|
@@ -756,8 +825,9 @@ export function formatSetupSession(session: SetupSession, asJson = false): strin
|
|
|
756
825
|
if (asJson) return JSON.stringify(session, null, 2);
|
|
757
826
|
const lines = [
|
|
758
827
|
`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-
|
|
828
|
+
`session=${session.sessionId}; controller=${session.profile?.primaryController ?? 'not-selected'}; host-tooling=${session.target}; updated=${session.updatedAt}`,
|
|
829
|
+
`summary: ${session.lastReport.summary.ok} ok, ${session.lastReport.summary.warn} warn, ${session.lastReport.summary.fail} fail, ${session.lastReport.summary.needs_agent} needs-action`,
|
|
830
|
+
...(session.profile ? ['', formatSetupProfile(session.profile, session.platform)] : []),
|
|
761
831
|
];
|
|
762
832
|
if (session.nextAction) {
|
|
763
833
|
lines.push('', `Next: ${session.nextAction.reason}`);
|
|
@@ -771,17 +841,50 @@ export function formatSetupSession(session: SetupSession, asJson = false): strin
|
|
|
771
841
|
return lines.join('\n');
|
|
772
842
|
}
|
|
773
843
|
|
|
774
|
-
function setupTarget(value: string, surface: string): InitHookTarget {
|
|
844
|
+
function setupTarget(value: string | undefined, surface: string): InitHookTarget | undefined {
|
|
845
|
+
if (value === undefined) return undefined;
|
|
775
846
|
if (!VALID_TARGETS.includes(value as InitHookTarget)) {
|
|
776
847
|
throw new Error(`${surface}: invalid --target "${value}" (expected: ${VALID_TARGETS.join(', ')})`);
|
|
777
848
|
}
|
|
778
849
|
return value as InitHookTarget;
|
|
779
850
|
}
|
|
780
851
|
|
|
781
|
-
|
|
852
|
+
interface SetupCycleRawOptions {
|
|
853
|
+
target?: string;
|
|
854
|
+
controller?: string;
|
|
855
|
+
addController?: string[];
|
|
856
|
+
tunnel?: string;
|
|
857
|
+
endpoint?: string;
|
|
858
|
+
tunnelId?: string;
|
|
859
|
+
checkUpdates?: boolean;
|
|
860
|
+
json?: boolean;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
function collectOption(value: string, previous: string[] = []): string[] {
|
|
864
|
+
return [...previous, value];
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
function syncExplicitRemoteControllerEndpoint(profile: SetupProfile | undefined, endpoint: string | undefined): void {
|
|
868
|
+
if (!profile || !endpoint || !profile.controllers.some((controller) => controller === 'chatgpt' || controller === 'mcp')) return;
|
|
869
|
+
runMcpSetupChatgpt({ userLevel: true, endpoint });
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
function setupCycle(rawOpts: SetupCycleRawOptions, surface: string): void {
|
|
782
873
|
try {
|
|
874
|
+
let profile = readSetupProfile();
|
|
875
|
+
if (rawOpts.controller || rawOpts.addController?.length || rawOpts.tunnel || rawOpts.endpoint || rawOpts.tunnelId) {
|
|
876
|
+
profile = configureSetupProfile({
|
|
877
|
+
controller: rawOpts.controller,
|
|
878
|
+
addControllers: rawOpts.addController,
|
|
879
|
+
tunnel: rawOpts.tunnel,
|
|
880
|
+
endpoint: rawOpts.endpoint,
|
|
881
|
+
tunnelId: rawOpts.tunnelId,
|
|
882
|
+
});
|
|
883
|
+
syncExplicitRemoteControllerEndpoint(profile, rawOpts.endpoint);
|
|
884
|
+
}
|
|
783
885
|
const session = openSetupSession({
|
|
784
|
-
|
|
886
|
+
profile,
|
|
887
|
+
target: setupTarget(rawOpts.target, surface) ?? setupHostTarget(profile),
|
|
785
888
|
checkUpdates: rawOpts.checkUpdates === true,
|
|
786
889
|
});
|
|
787
890
|
console.log(formatSetupSession(session, rawOpts.json === true));
|
|
@@ -792,33 +895,69 @@ function setupCycle(rawOpts: { target: string; checkUpdates?: boolean; json?: bo
|
|
|
792
895
|
}
|
|
793
896
|
}
|
|
794
897
|
|
|
898
|
+
function addSetupSelectionOptions(command: Command): Command {
|
|
899
|
+
return command
|
|
900
|
+
.option('--controller <controller>', 'Primary external controller: chatgpt|codex|claude|mcp')
|
|
901
|
+
.option('--add-controller <controller>', 'Also configure another external controller entry (repeatable)', collectOption, [])
|
|
902
|
+
.option('--tunnel <provider>', 'Remote connection: auto|openai|cloudflare|tailscale|existing|none')
|
|
903
|
+
.option('--tunnel-id <id>', 'OpenAI Secure MCP Tunnel id (non-secret tunnel_...)')
|
|
904
|
+
.option('--endpoint <url>', 'Existing/stable public HTTPS URL ending in /mcp')
|
|
905
|
+
.option('--target <target>', `Deprecated host-tooling override: ${VALID_TARGETS.join('|')}`)
|
|
906
|
+
.option('--check-updates', 'Include network-backed version update advisories')
|
|
907
|
+
.option('--json', 'Output JSON instead of human-readable text');
|
|
908
|
+
}
|
|
909
|
+
|
|
795
910
|
export function buildSetupCommand(): Command {
|
|
796
911
|
const command = new Command('setup');
|
|
797
912
|
command
|
|
798
|
-
.description('
|
|
799
|
-
.option('--target <target>', `Host target to configure: ${VALID_TARGETS.join('|')}`, 'both')
|
|
913
|
+
.description('Configure Forge around one external controller brain and optional additional controller entries')
|
|
800
914
|
.option('--check-updates', 'Include network-backed version update advisories')
|
|
801
915
|
.option('--json', 'Output JSON instead of human-readable text')
|
|
802
|
-
.action((rawOpts:
|
|
916
|
+
.action((rawOpts: SetupCycleRawOptions) => setupCycle(rawOpts, 'forge setup'));
|
|
803
917
|
|
|
804
918
|
for (const name of ['open', 'next'] as const) {
|
|
805
|
-
command
|
|
919
|
+
addSetupSelectionOptions(command
|
|
806
920
|
.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}`));
|
|
921
|
+
.description(name === 'open' ? 'Start or resume the guided Forge setup session' : 'Re-check configuration and advance to the next action'))
|
|
922
|
+
.action((rawOpts: SetupCycleRawOptions) => setupCycle(rawOpts, `forge setup ${name}`));
|
|
812
923
|
}
|
|
813
924
|
|
|
925
|
+
command
|
|
926
|
+
.command('configure')
|
|
927
|
+
.description('Choose the primary external controller, optional additional controllers, and public access provider')
|
|
928
|
+
.requiredOption('--controller <controller>', 'Primary external controller: chatgpt|codex|claude|mcp')
|
|
929
|
+
.option('--add-controller <controller>', 'Also configure another external controller entry (repeatable)', collectOption, [])
|
|
930
|
+
.option('--tunnel <provider>', 'Remote connection: auto|openai|cloudflare|tailscale|existing|none')
|
|
931
|
+
.option('--tunnel-id <id>', 'OpenAI Secure MCP Tunnel id (non-secret tunnel_...)')
|
|
932
|
+
.option('--endpoint <url>', 'Existing/stable public HTTPS URL ending in /mcp')
|
|
933
|
+
.option('--json', 'Output JSON instead of human-readable text')
|
|
934
|
+
.action((rawOpts: { controller: string; addController?: string[]; tunnel?: string; tunnelId?: string; endpoint?: string; json?: boolean }) => {
|
|
935
|
+
try {
|
|
936
|
+
const profile = configureSetupProfile({
|
|
937
|
+
controller: rawOpts.controller,
|
|
938
|
+
addControllers: rawOpts.addController,
|
|
939
|
+
tunnel: rawOpts.tunnel,
|
|
940
|
+
endpoint: rawOpts.endpoint,
|
|
941
|
+
tunnelId: rawOpts.tunnelId,
|
|
942
|
+
});
|
|
943
|
+
syncExplicitRemoteControllerEndpoint(profile, rawOpts.endpoint);
|
|
944
|
+
console.log(rawOpts.json ? JSON.stringify(profile, null, 2) : `${formatSetupProfile(profile)}\n\nNext: forge setup next`);
|
|
945
|
+
} catch (error) {
|
|
946
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
947
|
+
process.exitCode = 2;
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
|
|
814
951
|
command
|
|
815
952
|
.command('status')
|
|
816
|
-
.description('Read the persisted setup session
|
|
953
|
+
.description('Read the persisted setup session and external-controller profile')
|
|
817
954
|
.option('--json', 'Output JSON instead of human-readable text')
|
|
818
955
|
.action((rawOpts: { json?: boolean }) => {
|
|
819
956
|
const session = readSetupSession();
|
|
957
|
+
const profile = readSetupProfile();
|
|
820
958
|
if (!session) {
|
|
821
|
-
|
|
959
|
+
if (rawOpts.json) console.log(JSON.stringify({ status: 'not_started', profile }, null, 2));
|
|
960
|
+
else console.log(profile ? `forge setup: not started\n${formatSetupProfile(profile)}\nRun: forge setup open` : 'forge setup: not started\nRun: forge setup');
|
|
822
961
|
return;
|
|
823
962
|
}
|
|
824
963
|
console.log(formatSetupSession(session, rawOpts.json === true));
|
|
@@ -826,15 +965,16 @@ export function buildSetupCommand(): Command {
|
|
|
826
965
|
|
|
827
966
|
command
|
|
828
967
|
.command('close')
|
|
829
|
-
.description('Close setup after
|
|
830
|
-
.option('--target <target>', `Host target to verify: ${VALID_TARGETS.join('|')}`, 'both')
|
|
968
|
+
.description('Close setup after the selected external controller path is ready')
|
|
831
969
|
.option('--check-updates', 'Include network-backed version update advisories')
|
|
832
970
|
.option('--force', 'Close even when checks still need attention')
|
|
833
971
|
.option('--json', 'Output JSON instead of human-readable text')
|
|
834
|
-
.action((rawOpts: {
|
|
972
|
+
.action((rawOpts: { checkUpdates?: boolean; force?: boolean; json?: boolean }) => {
|
|
835
973
|
try {
|
|
974
|
+
const profile = readSetupProfile();
|
|
836
975
|
const session = closeSetupSession({
|
|
837
|
-
|
|
976
|
+
profile,
|
|
977
|
+
target: setupHostTarget(profile),
|
|
838
978
|
checkUpdates: rawOpts.checkUpdates === true,
|
|
839
979
|
force: rawOpts.force === true,
|
|
840
980
|
});
|
|
@@ -848,14 +988,15 @@ export function buildSetupCommand(): Command {
|
|
|
848
988
|
|
|
849
989
|
command
|
|
850
990
|
.command('check')
|
|
851
|
-
.description('Run the
|
|
852
|
-
.option('--target <target>', `Host
|
|
991
|
+
.description('Run the read-only readiness checklist for the configured external controller set')
|
|
992
|
+
.option('--target <target>', `Host-tooling override: ${VALID_TARGETS.join('|')}`)
|
|
853
993
|
.option('--check-updates', 'Include network-backed version update advisories')
|
|
854
994
|
.option('--json', 'Output JSON instead of human-readable text')
|
|
855
|
-
.action((rawOpts: { target
|
|
995
|
+
.action((rawOpts: { target?: string; checkUpdates?: boolean; json?: boolean }) => {
|
|
856
996
|
try {
|
|
997
|
+
const profile = readSetupProfile();
|
|
857
998
|
const report = runInitHook({
|
|
858
|
-
target: setupTarget(rawOpts.target, 'forge setup check'),
|
|
999
|
+
target: setupTarget(rawOpts.target, 'forge setup check') ?? setupHostTarget(profile),
|
|
859
1000
|
checkUpdates: rawOpts.checkUpdates === true,
|
|
860
1001
|
});
|
|
861
1002
|
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,19 @@ 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;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
interface
|
|
55
|
+
interface McpSetupLocalControllerOptions {
|
|
52
56
|
repo?: string;
|
|
53
57
|
scope?: string;
|
|
58
|
+
profile?: string;
|
|
54
59
|
dryRun?: boolean;
|
|
55
60
|
}
|
|
56
61
|
|
|
@@ -221,14 +226,17 @@ export function buildMcpCommand(): Command {
|
|
|
221
226
|
});
|
|
222
227
|
});
|
|
223
228
|
|
|
224
|
-
const setup = new Command('setup').description('
|
|
229
|
+
const setup = new Command('setup').description('Configure an external controller connection to Forge');
|
|
225
230
|
|
|
226
231
|
setup
|
|
227
232
|
.command('chatgpt')
|
|
228
233
|
.description('Generate ChatGPT Connector local config and manual setup guide')
|
|
229
234
|
.option('--repo <path>', 'Repository root to configure', '.')
|
|
235
|
+
.option('--controller-home <path>', 'User Controller Home (used with --user-level)')
|
|
236
|
+
.option('--user-level', 'Configure the user-level Controller without writing repository guide/gitignore files')
|
|
230
237
|
.option('--host <host>', 'Local MCP HTTP bind host', '127.0.0.1')
|
|
231
238
|
.option('--port <port>', 'Local MCP HTTP bind port', '8765')
|
|
239
|
+
.option('--local-controller-port <port>', 'Local-only Utility Console port; defaults to MCP port + 1')
|
|
232
240
|
.option('--endpoint <url>', 'Stable public HTTPS /mcp endpoint to store in ignored local config')
|
|
233
241
|
.option('--server-name <name>', 'ChatGPT Connector/MCP server name to record in ignored local config')
|
|
234
242
|
.action((rawOpts: McpSetupChatgptOptions) => {
|
|
@@ -240,17 +248,33 @@ export function buildMcpCommand(): Command {
|
|
|
240
248
|
|
|
241
249
|
setup
|
|
242
250
|
.command('codex')
|
|
243
|
-
.description('
|
|
251
|
+
.description('Configure Codex as an explicit Forge controller or executor')
|
|
244
252
|
.option('--repo <path>', 'Repository root to configure', '.')
|
|
245
253
|
.option('--scope <scope>', 'Config scope: project|user', 'project')
|
|
254
|
+
.option('--profile <profile>', 'Forge MCP role: controller|executor', 'executor')
|
|
246
255
|
.option('--dry-run', 'Print planned changes without writing files')
|
|
247
|
-
.action((rawOpts:
|
|
256
|
+
.action((rawOpts: McpSetupLocalControllerOptions) => {
|
|
248
257
|
void runMcpAction(() => {
|
|
249
258
|
const result = runMcpSetupCodex(rawOpts);
|
|
250
259
|
console.log(result.lines.join('\n'));
|
|
251
260
|
});
|
|
252
261
|
});
|
|
253
262
|
|
|
263
|
+
|
|
264
|
+
setup
|
|
265
|
+
.command('claude')
|
|
266
|
+
.description('Configure Claude Code as an explicit Forge controller or executor through the Claude CLI')
|
|
267
|
+
.option('--repo <path>', 'Repository root to expose initially', '.')
|
|
268
|
+
.option('--scope <scope>', 'Claude MCP scope: local|project|user', 'user')
|
|
269
|
+
.option('--profile <profile>', 'Forge MCP role: controller|executor', 'controller')
|
|
270
|
+
.option('--dry-run', 'Print the Claude MCP command without changing Claude config')
|
|
271
|
+
.action((rawOpts: McpSetupLocalControllerOptions) => {
|
|
272
|
+
void runMcpAction(() => {
|
|
273
|
+
const result = runMcpSetupClaude(rawOpts);
|
|
274
|
+
console.log(result.lines.join('\n'));
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
254
278
|
mcp.addCommand(setup);
|
|
255
279
|
|
|
256
280
|
const access = new Command('access').description('Read or change repository Request / Full Access permission levels');
|
|
@@ -284,7 +308,7 @@ export function buildMcpCommand(): Command {
|
|
|
284
308
|
|
|
285
309
|
mcp
|
|
286
310
|
.command('prepare-goal')
|
|
287
|
-
.description('Prepare .ai/harness/
|
|
311
|
+
.description('Prepare .ai/harness/controller/packets/codex-goal.md and print a host-native /goal prompt from a PRD and checklist Sprint')
|
|
288
312
|
.option('--repo <path>', 'Repository root to configure', '.')
|
|
289
313
|
.requiredOption('--prd <path>', 'PRD path to read')
|
|
290
314
|
.requiredOption('--sprint <path>', 'Checklist Sprint path to execute')
|