forge-cc 0.1.41 → 1.0.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.
Files changed (62) hide show
  1. package/README.md +454 -338
  2. package/dist/cli.js +194 -935
  3. package/dist/cli.js.map +1 -1
  4. package/dist/config/loader.d.ts +1 -1
  5. package/dist/config/loader.js +49 -56
  6. package/dist/config/loader.js.map +1 -1
  7. package/dist/config/schema.d.ts +37 -125
  8. package/dist/config/schema.js +13 -28
  9. package/dist/config/schema.js.map +1 -1
  10. package/dist/doctor.d.ts +10 -0
  11. package/dist/doctor.js +148 -0
  12. package/dist/doctor.js.map +1 -0
  13. package/dist/gates/index.d.ts +14 -12
  14. package/dist/gates/index.js +53 -105
  15. package/dist/gates/index.js.map +1 -1
  16. package/dist/gates/lint-gate.d.ts +2 -2
  17. package/dist/gates/lint-gate.js +60 -66
  18. package/dist/gates/lint-gate.js.map +1 -1
  19. package/dist/gates/tests-gate.d.ts +2 -4
  20. package/dist/gates/tests-gate.js +75 -203
  21. package/dist/gates/tests-gate.js.map +1 -1
  22. package/dist/gates/types-gate.d.ts +2 -2
  23. package/dist/gates/types-gate.js +53 -59
  24. package/dist/gates/types-gate.js.map +1 -1
  25. package/dist/linear/client.d.ts +31 -108
  26. package/dist/linear/client.js +88 -388
  27. package/dist/linear/client.js.map +1 -1
  28. package/dist/linear/sync.d.ts +15 -0
  29. package/dist/linear/sync.js +102 -0
  30. package/dist/linear/sync.js.map +1 -0
  31. package/dist/runner/loop.d.ts +4 -0
  32. package/dist/runner/loop.js +168 -0
  33. package/dist/runner/loop.js.map +1 -0
  34. package/dist/runner/prompt.d.ts +14 -0
  35. package/dist/runner/prompt.js +59 -0
  36. package/dist/runner/prompt.js.map +1 -0
  37. package/dist/runner/update.d.ts +1 -0
  38. package/dist/runner/update.js +72 -0
  39. package/dist/runner/update.js.map +1 -0
  40. package/dist/server.d.ts +6 -2
  41. package/dist/server.js +43 -101
  42. package/dist/server.js.map +1 -1
  43. package/dist/setup.d.ts +5 -0
  44. package/dist/setup.js +208 -0
  45. package/dist/setup.js.map +1 -0
  46. package/dist/state/cache.d.ts +3 -0
  47. package/dist/state/cache.js +23 -0
  48. package/dist/state/cache.js.map +1 -0
  49. package/dist/state/status.d.ts +66 -0
  50. package/dist/state/status.js +96 -0
  51. package/dist/state/status.js.map +1 -0
  52. package/dist/types.d.ts +46 -114
  53. package/dist/worktree/manager.d.ts +6 -103
  54. package/dist/worktree/manager.js +25 -296
  55. package/dist/worktree/manager.js.map +1 -1
  56. package/hooks/pre-commit-verify.js +109 -109
  57. package/package.json +3 -2
  58. package/skills/forge-go.md +20 -13
  59. package/skills/forge-setup.md +149 -388
  60. package/skills/forge-spec.md +367 -342
  61. package/skills/forge-triage.md +179 -133
  62. package/skills/forge-update.md +87 -93
@@ -0,0 +1,168 @@
1
+ import { spawn, execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { basename, dirname, join, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { loadConfig } from "../config/loader.js";
6
+ import { readStatus, updateMilestoneStatus, findNextPending, discoverStatuses, } from "../state/status.js";
7
+ import { readMilestoneSection, buildPrompt } from "./prompt.js";
8
+ import { createWorktree, mergeWorktree, removeWorktree, } from "../worktree/manager.js";
9
+ import { ForgeLinearClient } from "../linear/client.js";
10
+ import { syncMilestoneStart, syncMilestoneComplete, } from "../linear/sync.js";
11
+ const execFileAsync = promisify(execFile);
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const cliPath = join(__dirname, "..", "cli.js");
14
+ function repoName(projectDir) {
15
+ return basename(resolve(projectDir));
16
+ }
17
+ function worktreePath(projectDir, slug, milestoneNumber) {
18
+ return resolve(projectDir, "..", ".forge-wt", repoName(projectDir), `${slug}-m${milestoneNumber}`);
19
+ }
20
+ function parseMilestoneNumber(key) {
21
+ const match = /(\d+)/.exec(key);
22
+ if (!match)
23
+ throw new Error(`Cannot parse milestone number from key: ${key}`);
24
+ return Number.parseInt(match[1], 10);
25
+ }
26
+ function parseMilestoneName(key) {
27
+ const colonIndex = key.indexOf(":");
28
+ if (colonIndex === -1)
29
+ return key;
30
+ return key.slice(colonIndex + 1).trim();
31
+ }
32
+ function spawnClaude(prompt, cwd) {
33
+ return new Promise((resolve, reject) => {
34
+ // Strip CLAUDECODE env var to allow spawning claude from within a Claude Code session
35
+ const env = { ...process.env };
36
+ delete env.CLAUDECODE;
37
+ const child = spawn("claude", ["-p", "-", "--dangerously-skip-permissions"], {
38
+ cwd,
39
+ env,
40
+ stdio: ["pipe", "pipe", "pipe"],
41
+ });
42
+ child.stdin.write(prompt);
43
+ child.stdin.end();
44
+ child.stdout.pipe(process.stdout);
45
+ child.stderr.pipe(process.stderr);
46
+ child.on("error", reject);
47
+ child.on("close", (code) => {
48
+ resolve(code ?? 1);
49
+ });
50
+ });
51
+ }
52
+ async function runVerifyInWorktree(wtPath) {
53
+ try {
54
+ const { stdout } = await execFileAsync("node", [cliPath, "verify", "--json"], {
55
+ cwd: wtPath,
56
+ });
57
+ return JSON.parse(stdout);
58
+ }
59
+ catch (err) {
60
+ // execFile rejects on non-zero exit, but stdout still contains the JSON result
61
+ if (typeof err === "object" &&
62
+ err !== null &&
63
+ "stdout" in err &&
64
+ typeof err.stdout === "string") {
65
+ const stdout = err.stdout;
66
+ if (stdout.trim()) {
67
+ return JSON.parse(stdout);
68
+ }
69
+ }
70
+ throw err;
71
+ }
72
+ }
73
+ export async function runRalphLoop(opts) {
74
+ const { slug, projectDir } = opts;
75
+ const config = await loadConfig(projectDir);
76
+ const maxIterations = config.maxIterations;
77
+ // Find the PRD file
78
+ const prdPath = join(projectDir, ".planning", "prds", `${slug}.md`);
79
+ // Get the status for this slug
80
+ const status = await readStatus(projectDir, slug);
81
+ const prdBranch = status.branch;
82
+ // Find all pending milestones and process them in order
83
+ const allStatuses = await discoverStatuses(projectDir);
84
+ let pending = findNextPending(allStatuses.filter((s) => s.slug === slug));
85
+ while (pending.length > 0) {
86
+ const { milestone: milestoneKey } = pending[0];
87
+ const milestoneNumber = parseMilestoneNumber(milestoneKey);
88
+ const milestoneName = parseMilestoneName(milestoneKey);
89
+ console.log(`\n[forge] Starting milestone ${milestoneNumber}: ${milestoneName}`);
90
+ // Mark in_progress
91
+ await updateMilestoneStatus(projectDir, slug, milestoneKey, "in_progress");
92
+ // Linear sync: start
93
+ const apiKey = process.env.LINEAR_API_KEY;
94
+ if (apiKey && status.linearTeamId) {
95
+ try {
96
+ const client = new ForgeLinearClient({ apiKey, teamId: status.linearTeamId });
97
+ await syncMilestoneStart(client, config, status, milestoneKey);
98
+ }
99
+ catch {
100
+ // Linear sync is best-effort
101
+ }
102
+ }
103
+ // Read milestone section from PRD
104
+ const milestoneSection = await readMilestoneSection(prdPath, milestoneNumber);
105
+ // Create worktree
106
+ const wtPath = worktreePath(projectDir, slug, milestoneNumber);
107
+ const wtBranch = `${prdBranch}/m${milestoneNumber}`;
108
+ await createWorktree(wtPath, wtBranch, prdBranch, projectDir);
109
+ let passed = false;
110
+ let verifyErrors = null;
111
+ for (let iteration = 1; iteration <= maxIterations; iteration++) {
112
+ console.log(`\n[forge] Milestone ${milestoneNumber}, iteration ${iteration}/${maxIterations}`);
113
+ // Build prompt
114
+ const prompt = buildPrompt({
115
+ milestoneName,
116
+ milestoneNumber,
117
+ milestoneSection,
118
+ verifyErrors,
119
+ });
120
+ // Spawn Claude
121
+ await spawnClaude(prompt, wtPath);
122
+ // Run verify
123
+ try {
124
+ const result = await runVerifyInWorktree(wtPath);
125
+ if (result.result === "PASSED") {
126
+ passed = true;
127
+ break;
128
+ }
129
+ verifyErrors = result;
130
+ console.log(`[forge] Verify failed on iteration ${iteration}. Retrying...`);
131
+ }
132
+ catch (err) {
133
+ // verify itself may exit non-zero; try to parse stderr/stdout
134
+ console.warn(`[forge] Verify execution error on iteration ${iteration}:`, err);
135
+ verifyErrors = null;
136
+ }
137
+ }
138
+ if (!passed) {
139
+ console.error(`\n[forge] Milestone ${milestoneNumber} failed after ${maxIterations} iterations.`);
140
+ await removeWorktree(wtPath, projectDir);
141
+ process.exit(1);
142
+ }
143
+ // Merge back and clean up
144
+ console.log(`\n[forge] Milestone ${milestoneNumber} passed. Merging...`);
145
+ await mergeWorktree(wtBranch, prdBranch, projectDir);
146
+ await removeWorktree(wtPath, projectDir);
147
+ // Update status
148
+ const milestoneKeys = Object.keys(status.milestones);
149
+ const isLast = milestoneKeys.indexOf(milestoneKey) === milestoneKeys.length - 1;
150
+ await updateMilestoneStatus(projectDir, slug, milestoneKey, "complete");
151
+ // Linear sync: complete
152
+ if (apiKey && status.linearTeamId) {
153
+ try {
154
+ const client = new ForgeLinearClient({ apiKey, teamId: status.linearTeamId });
155
+ await syncMilestoneComplete(client, config, status, milestoneKey, isLast);
156
+ }
157
+ catch {
158
+ // Linear sync is best-effort
159
+ }
160
+ }
161
+ console.log(`[forge] Milestone ${milestoneNumber} complete.`);
162
+ // Refresh pending list for next iteration
163
+ const refreshed = await discoverStatuses(projectDir);
164
+ pending = findNextPending(refreshed.filter((s) => s.slug === slug));
165
+ }
166
+ console.log(`\n[forge] All milestones for "${slug}" complete.`);
167
+ }
168
+ //# sourceMappingURL=loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/runner/loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { PipelineResult } from "../types.js";
2
+ /**
3
+ * Extract a milestone section from a PRD markdown file.
4
+ * Looks for `### Milestone {N}:` and returns everything up to
5
+ * the next `### Milestone` header or end of file.
6
+ */
7
+ export declare function readMilestoneSection(prdPath: string, milestoneNumber: number): Promise<string>;
8
+ /** Build the full Ralph loop prompt for a milestone iteration. */
9
+ export declare function buildPrompt(opts: {
10
+ milestoneName: string;
11
+ milestoneNumber: number;
12
+ milestoneSection: string;
13
+ verifyErrors?: PipelineResult | null;
14
+ }): string;
@@ -0,0 +1,59 @@
1
+ import { readFile } from "node:fs/promises";
2
+ /**
3
+ * Extract a milestone section from a PRD markdown file.
4
+ * Looks for `### Milestone {N}:` and returns everything up to
5
+ * the next `### Milestone` header or end of file.
6
+ */
7
+ export async function readMilestoneSection(prdPath, milestoneNumber) {
8
+ const content = await readFile(prdPath, "utf-8");
9
+ const pattern = new RegExp(`^### Milestone ${milestoneNumber}\\b[^\n]*`, "m");
10
+ const match = pattern.exec(content);
11
+ if (!match) {
12
+ throw new Error(`Milestone ${milestoneNumber} not found in ${prdPath}`);
13
+ }
14
+ const startIndex = match.index;
15
+ // Find the next ### Milestone header after our match
16
+ const rest = content.slice(startIndex + match[0].length);
17
+ const nextHeader = /^### Milestone \d+/m.exec(rest);
18
+ const section = nextHeader
19
+ ? content.slice(startIndex, startIndex + match[0].length + nextHeader.index)
20
+ : content.slice(startIndex);
21
+ return section.trimEnd();
22
+ }
23
+ /** Format PipelineResult errors into a human-readable string. */
24
+ function formatVerifyErrors(result) {
25
+ const lines = [`forge verify: ${result.result}`];
26
+ for (const gate of result.gates) {
27
+ if (!gate.passed) {
28
+ lines.push(`\nGate "${gate.gate}" FAILED:`);
29
+ for (const err of gate.errors) {
30
+ const loc = err.column
31
+ ? `${err.file}:${err.line}:${err.column}`
32
+ : `${err.file}:${err.line}`;
33
+ const rule = err.rule ? ` [${err.rule}]` : "";
34
+ lines.push(` ${loc} — ${err.message}${rule}`);
35
+ }
36
+ }
37
+ }
38
+ return lines.join("\n");
39
+ }
40
+ /** Build the full Ralph loop prompt for a milestone iteration. */
41
+ export function buildPrompt(opts) {
42
+ const { milestoneName, milestoneNumber, milestoneSection, verifyErrors } = opts;
43
+ const currentState = verifyErrors && verifyErrors.result === "FAILED"
44
+ ? formatVerifyErrors(verifyErrors)
45
+ : "First iteration — start from scratch";
46
+ return `# Task: Complete Milestone ${milestoneNumber} — ${milestoneName}
47
+
48
+ ## What to build
49
+ ${milestoneSection}
50
+
51
+ ## Current state
52
+ ${currentState}
53
+
54
+ ## Rules
55
+ - Run \`npx forge verify\` before finishing. All gates must pass.
56
+ - Commit your work before exiting.
57
+ - Do NOT create tests just to make gates pass. Fix real issues only.`;
58
+ }
59
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/runner/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAe,EACf,eAAuB;IAEvB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,IAAI,MAAM,CACxB,kBAAkB,eAAe,WAAW,EAC5C,GAAG,CACJ,CAAC;IACF,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,aAAa,eAAe,iBAAiB,OAAO,EAAE,CACvD,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC;IAC/B,qDAAqD;IACrD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACzD,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,UAAU;QACxB,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC;QAC5E,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAE9B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;AAC3B,CAAC;AAED,iEAAiE;AACjE,SAAS,kBAAkB,CAAC,MAAsB;IAChD,MAAM,KAAK,GAAa,CAAC,iBAAiB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3D,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,WAAW,CAAC,CAAC;YAC5C,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC9B,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM;oBACpB,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,EAAE;oBACzC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;gBAC9B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9C,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,GAAG,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,WAAW,CAAC,IAK3B;IACC,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,GACtE,IAAI,CAAC;IAEP,MAAM,YAAY,GAChB,YAAY,IAAI,YAAY,CAAC,MAAM,KAAK,QAAQ;QAC9C,CAAC,CAAC,kBAAkB,CAAC,YAAY,CAAC;QAClC,CAAC,CAAC,sCAAsC,CAAC;IAE7C,OAAO,8BAA8B,eAAe,MAAM,aAAa;;;EAGvE,gBAAgB;;;EAGhB,YAAY;;;;;qEAKuD,CAAC;AACtE,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function checkForUpdate(projectDir: string): Promise<void>;
@@ -0,0 +1,72 @@
1
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
2
+ import { join, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ function cachePath(projectDir) {
6
+ return join(projectDir, ".forge", "version-check.json");
7
+ }
8
+ async function readCache(projectDir) {
9
+ try {
10
+ const raw = await readFile(cachePath(projectDir), "utf-8");
11
+ return JSON.parse(raw);
12
+ }
13
+ catch {
14
+ return null;
15
+ }
16
+ }
17
+ async function writeCache(projectDir, cache) {
18
+ const p = cachePath(projectDir);
19
+ await mkdir(dirname(p), { recursive: true });
20
+ await writeFile(p, JSON.stringify(cache, null, 2), "utf-8");
21
+ }
22
+ function isCacheFresh(cache) {
23
+ const cacheTime = new Date(cache.timestamp).getTime();
24
+ const now = Date.now();
25
+ const ONE_DAY_MS = 24 * 60 * 60 * 1000;
26
+ return now - cacheTime < ONE_DAY_MS;
27
+ }
28
+ async function getCurrentVersion() {
29
+ const pkgPath = join(__dirname, "..", "..", "package.json");
30
+ const raw = await readFile(pkgPath, "utf-8");
31
+ const pkg = JSON.parse(raw);
32
+ return pkg.version;
33
+ }
34
+ async function fetchLatestVersion() {
35
+ const response = await fetch("https://registry.npmjs.org/forge-cc/latest");
36
+ if (!response.ok) {
37
+ throw new Error(`npm registry returned ${response.status}`);
38
+ }
39
+ const data = (await response.json());
40
+ return data.version;
41
+ }
42
+ export async function checkForUpdate(projectDir) {
43
+ // Check cache first
44
+ const cache = await readCache(projectDir);
45
+ if (cache && isCacheFresh(cache)) {
46
+ const current = await getCurrentVersion();
47
+ if (cache.latestVersion !== current) {
48
+ console.log(`forge-cc v${cache.latestVersion} is available (current: v${current}). Run: npm install -g forge-cc`);
49
+ }
50
+ return;
51
+ }
52
+ // Fetch from registry
53
+ try {
54
+ const latestVersion = await fetchLatestVersion();
55
+ const current = await getCurrentVersion();
56
+ // Write cache
57
+ await writeCache(projectDir, {
58
+ timestamp: new Date().toISOString(),
59
+ latestVersion,
60
+ });
61
+ if (latestVersion !== current) {
62
+ console.log(`forge-cc v${latestVersion} is available (current: v${current}). Run: npm install -g forge-cc`);
63
+ }
64
+ else {
65
+ console.log(`forge-cc v${current} is up to date.`);
66
+ }
67
+ }
68
+ catch (err) {
69
+ console.warn("[forge] Version check failed:", err);
70
+ }
71
+ }
72
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/runner/update.ts"],"names":[],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -1,2 +1,6 @@
1
- #!/usr/bin/env node
2
- export {};
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ /**
3
+ * Create an MCP server instance with the forge_run_pipeline tool registered.
4
+ * Exported for testing — call `startServer()` to run with stdio transport.
5
+ */
6
+ export declare function createServer(): McpServer;
package/dist/server.js CHANGED
@@ -1,109 +1,51 @@
1
- #!/usr/bin/env node
2
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
3
  import { z } from "zod";
5
- import { verifyTypes, verifyLint, verifyTests, verifyVisual, verifyRuntime, verifyPrd, runPipeline, } from "./gates/index.js";
6
- const server = new McpServer({
7
- name: "forge-cc",
8
- version: "0.1.0",
9
- });
10
- // Individual gate tools
11
- // Each handler is wrapped in try-catch to return structured errors instead of crashing the MCP server.
12
- function errorResponse(err) {
13
- const message = err instanceof Error ? err.message : String(err);
14
- return { content: [{ type: "text", text: JSON.stringify({ error: message }) }] };
4
+ import { loadConfig } from "./config/loader.js";
5
+ import { registerGate, runPipeline, } from "./gates/index.js";
6
+ import { typesGate } from "./gates/types-gate.js";
7
+ import { lintGate } from "./gates/lint-gate.js";
8
+ import { testsGate } from "./gates/tests-gate.js";
9
+ /**
10
+ * Create an MCP server instance with the forge_run_pipeline tool registered.
11
+ * Exported for testing — call `startServer()` to run with stdio transport.
12
+ */
13
+ export function createServer() {
14
+ const server = new McpServer({ name: "forge", version: "1.0.0" }, { capabilities: { tools: {} } });
15
+ // Register default gates once at server creation (not per-call, to avoid race conditions)
16
+ registerGate(typesGate);
17
+ registerGate(lintGate);
18
+ registerGate(testsGate);
19
+ server.tool("forge_run_pipeline", "Run the Forge verification pipeline (types, lint, tests)", {
20
+ projectDir: z.string().optional().describe("Project directory (defaults to cwd)"),
21
+ gates: z.array(z.string()).optional().describe("Filter to specific gates"),
22
+ }, async ({ projectDir, gates }) => {
23
+ const dir = projectDir ?? process.cwd();
24
+ const config = await loadConfig(dir);
25
+ if (gates && gates.length > 0) {
26
+ config.gates = gates;
27
+ }
28
+ const result = await runPipeline(config, dir);
29
+ return {
30
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
31
+ };
32
+ });
33
+ return server;
15
34
  }
16
- server.tool("forge_verify_types", "Run TypeScript type checking (tsc --noEmit)", { projectDir: z.string().describe("Absolute path to project root") }, async ({ projectDir }) => {
17
- try {
18
- const result = await verifyTypes(projectDir);
19
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
20
- }
21
- catch (err) {
22
- return errorResponse(err);
23
- }
24
- });
25
- server.tool("forge_verify_lint", "Run Biome linting checks", { projectDir: z.string().describe("Absolute path to project root") }, async ({ projectDir }) => {
26
- try {
27
- const result = await verifyLint(projectDir);
28
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
29
- }
30
- catch (err) {
31
- return errorResponse(err);
32
- }
33
- });
34
- server.tool("forge_verify_tests", "Run project test suite", { projectDir: z.string().describe("Absolute path to project root") }, async ({ projectDir }) => {
35
- try {
36
- const result = await verifyTests(projectDir);
37
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
38
- }
39
- catch (err) {
40
- return errorResponse(err);
41
- }
42
- });
43
- server.tool("forge_verify_visual", "Take screenshots and check for console errors", {
44
- projectDir: z.string().describe("Absolute path to project root"),
45
- pages: z.array(z.string()).default(["/"]).describe("Page paths to check"),
46
- devServerCommand: z.string().optional().describe("Dev server start command"),
47
- devServerPort: z.number().optional().describe("Dev server port"),
48
- }, async ({ projectDir, pages, devServerCommand, devServerPort }) => {
49
- try {
50
- const result = await verifyVisual(projectDir, pages, { devServerCommand, devServerPort });
51
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
52
- }
53
- catch (err) {
54
- return errorResponse(err);
55
- }
56
- });
57
- server.tool("forge_verify_runtime", "Validate API endpoints return expected responses", {
58
- projectDir: z.string().describe("Absolute path to project root"),
59
- endpoints: z.array(z.string()).describe("API endpoints to test (e.g., 'GET /api/health')"),
60
- devServerCommand: z.string().optional().describe("Dev server start command"),
61
- devServerPort: z.number().optional().describe("Dev server port"),
62
- }, async ({ projectDir, endpoints, devServerCommand, devServerPort }) => {
63
- try {
64
- const result = await verifyRuntime(projectDir, endpoints, { devServerCommand, devServerPort });
65
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
66
- }
67
- catch (err) {
68
- return errorResponse(err);
69
- }
70
- });
71
- server.tool("forge_verify_prd", "Check code changes against PRD acceptance criteria", {
72
- projectDir: z.string().describe("Absolute path to project root"),
73
- prdPath: z.string().describe("Path to PRD markdown file"),
74
- baseBranch: z.string().default("main").describe("Base branch for diff comparison"),
75
- }, async ({ projectDir, prdPath, baseBranch }) => {
76
- try {
77
- const result = await verifyPrd(projectDir, prdPath, baseBranch);
78
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
79
- }
80
- catch (err) {
81
- return errorResponse(err);
82
- }
83
- });
84
- server.tool("forge_run_pipeline", "Run full verification pipeline (all configured gates)", {
85
- projectDir: z.string().describe("Absolute path to project root"),
86
- gates: z.array(z.string()).optional().describe("Gates to run (default: types,lint,tests)"),
87
- prdPath: z.string().optional().describe("Path to PRD file"),
88
- maxIterations: z.number().optional().describe("Max retry iterations"),
89
- }, async ({ projectDir, gates, prdPath, maxIterations }) => {
90
- try {
91
- const result = await runPipeline({
92
- projectDir,
93
- gates,
94
- prdPath,
95
- maxIterations,
96
- });
97
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
98
- }
99
- catch (err) {
100
- return errorResponse(err);
101
- }
102
- });
103
- // Start server
104
- async function main() {
35
+ /** Start the MCP server on stdio transport. */
36
+ async function startServer() {
37
+ const server = createServer();
105
38
  const transport = new StdioServerTransport();
106
39
  await server.connect(transport);
107
40
  }
108
- main().catch(console.error);
41
+ // Run when executed directly
42
+ const isMain = typeof process !== "undefined" &&
43
+ process.argv[1] &&
44
+ (process.argv[1].endsWith("/server.js") || process.argv[1].endsWith("\\server.js"));
45
+ if (isMain) {
46
+ startServer().catch((err) => {
47
+ process.stderr.write(`Forge MCP server error: ${String(err)}\n`);
48
+ process.exit(1);
49
+ });
50
+ }
109
51
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,YAAY,EACZ,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,EACnC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAC;IAEF,0FAA0F;IAC1F,YAAY,CAAC,SAAS,CAAC,CAAC;IACxB,YAAY,CAAC,QAAQ,CAAC,CAAC;IACvB,YAAY,CAAC,SAAS,CAAC,CAAC;IAExB,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,0DAA0D,EAC1D;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;QACjF,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;KAC3E,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE;QAC9B,MAAM,GAAG,GAAG,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;QAErC,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QACvB,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAE9C,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAC5E,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,+CAA+C;AAC/C,KAAK,UAAU,WAAW;IACxB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,6BAA6B;AAC7B,MAAM,MAAM,GACV,OAAO,OAAO,KAAK,WAAW;IAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACf,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;AAEtF,IAAI,MAAM,EAAE,CAAC;IACX,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,5 @@
1
+ export interface SetupOptions {
2
+ projectDir: string;
3
+ skillsOnly?: boolean;
4
+ }
5
+ export declare function runSetup(opts: SetupOptions): Promise<void>;