rebar-mcp 2.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 (248) hide show
  1. package/.claude/agents/template-writer.md +43 -0
  2. package/.claude/agents/test-runner.md +47 -0
  3. package/.claude/mcp.json +9 -0
  4. package/.claude/settings.json +29 -0
  5. package/.claude/skills/ /SKILL.md +21 -0
  6. package/.claude/skills/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/SKILL.md +21 -0
  7. package/.claude/skills/bmmibwetxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  8. package/.claude/skills/bmmibwjgvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  9. package/.claude/skills/bmmibwsesxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  10. package/.claude/skills/bmmibwxufxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  11. package/.claude/skills/bmmibx3r9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  12. package/.claude/skills/bmmji0lrkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  13. package/.claude/skills/bmmjiniphxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  14. package/.claude/skills/bmmjio86zxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  15. package/.claude/skills/bmmjiolfbxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  16. package/.claude/skills/bmmjit1lvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  17. package/.claude/skills/bmmjita1qxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/SKILL.md +21 -0
  18. package/.claude/skills/bnd-mmibweu3/SKILL.md +21 -0
  19. package/.claude/skills/bnd-mmibwjh4/SKILL.md +21 -0
  20. package/.claude/skills/bnd-mmibwsey/SKILL.md +21 -0
  21. package/.claude/skills/bnd-mmibwxup/SKILL.md +21 -0
  22. package/.claude/skills/bnd-mmibx3rg/SKILL.md +21 -0
  23. package/.claude/skills/bnd-mmji0lrp/SKILL.md +21 -0
  24. package/.claude/skills/bnd-mmjinipm/SKILL.md +21 -0
  25. package/.claude/skills/bnd-mmjio875/SKILL.md +21 -0
  26. package/.claude/skills/bnd-mmjiolfg/SKILL.md +21 -0
  27. package/.claude/skills/bnd-mmjit1m3/SKILL.md +21 -0
  28. package/.claude/skills/bnd-mmjita1x/SKILL.md +21 -0
  29. package/.claude/skills/coercion-test/SKILL.md +50 -0
  30. package/.claude/skills/large-skill/SKILL.md +21 -0
  31. package/.claude/skills/long-desc-skill/SKILL.md +21 -0
  32. package/.claude/skills/mcp-dev/SKILL.md +61 -0
  33. package/.claude/skills/nl-mmibweus/SKILL.md +25 -0
  34. package/.claude/skills/nl-mmibwjhf/SKILL.md +25 -0
  35. package/.claude/skills/nl-mmibwsf7/SKILL.md +25 -0
  36. package/.claude/skills/nl-mmibwxvq/SKILL.md +25 -0
  37. package/.claude/skills/nl-mmibx3rt/SKILL.md +25 -0
  38. package/.claude/skills/nl-mmji0lrz/SKILL.md +25 -0
  39. package/.claude/skills/nl-mmjinipx/SKILL.md +25 -0
  40. package/.claude/skills/nl-mmjio87f/SKILL.md +25 -0
  41. package/.claude/skills/nl-mmjiolfs/SKILL.md +25 -0
  42. package/.claude/skills/nl-mmjit1mc/SKILL.md +25 -0
  43. package/.claude/skills/nl-mmjita26/SKILL.md +25 -0
  44. package/.claude/skills/rapid-1/SKILL.md +21 -0
  45. package/.claude/skills/rapid-2/SKILL.md +21 -0
  46. package/.claude/skills/rapid-3/SKILL.md +21 -0
  47. package/.claude/skills/rapid-4/SKILL.md +21 -0
  48. package/.claude/skills/rapid-5/SKILL.md +21 -0
  49. package/.claude/skills/test/", /"malicious/": /"true/SKILL.md" +69 -0
  50. package/.claude/skills/test-emoji-/360/237/230/200-skill/SKILL.md +69 -0
  51. package/.claude/skills/test-skill/SKILL.md +69 -0
  52. package/.claude/skills/test; rm -rf /; skill/SKILL.md +69 -0
  53. package/.claude/skills/test<script>alert(1)</script>skill/SKILL.md +69 -0
  54. package/.claudeignore +5 -0
  55. package/.mcp.json +3 -0
  56. package/CHANGELOG.md +29 -0
  57. package/CLAUDE.md +76 -0
  58. package/LICENSE +21 -0
  59. package/README.md +149 -0
  60. package/ROADMAP.md +526 -0
  61. package/ccboot-PRD-v1.0.docx.md +732 -0
  62. package/ccboot-v1.2.0-enforcement-spec.md +1272 -0
  63. package/dist/cli.d.ts +3 -0
  64. package/dist/cli.d.ts.map +1 -0
  65. package/dist/cli.js +674 -0
  66. package/dist/cli.js.map +1 -0
  67. package/dist/constants.d.ts +25 -0
  68. package/dist/constants.d.ts.map +1 -0
  69. package/dist/constants.js +118 -0
  70. package/dist/constants.js.map +1 -0
  71. package/dist/index.d.ts +3 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +47 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/schemas/common.d.ts +62 -0
  76. package/dist/schemas/common.d.ts.map +1 -0
  77. package/dist/schemas/common.js +15 -0
  78. package/dist/schemas/common.js.map +1 -0
  79. package/dist/schemas/scaffolding.d.ts +277 -0
  80. package/dist/schemas/scaffolding.d.ts.map +1 -0
  81. package/dist/schemas/scaffolding.js +133 -0
  82. package/dist/schemas/scaffolding.js.map +1 -0
  83. package/dist/services/claudemd-generator.d.ts +16 -0
  84. package/dist/services/claudemd-generator.d.ts.map +1 -0
  85. package/dist/services/claudemd-generator.js +426 -0
  86. package/dist/services/claudemd-generator.js.map +1 -0
  87. package/dist/services/codex-generator.d.ts +6 -0
  88. package/dist/services/codex-generator.d.ts.map +1 -0
  89. package/dist/services/codex-generator.js +35 -0
  90. package/dist/services/codex-generator.js.map +1 -0
  91. package/dist/services/cursor-generator.d.ts +15 -0
  92. package/dist/services/cursor-generator.d.ts.map +1 -0
  93. package/dist/services/cursor-generator.js +134 -0
  94. package/dist/services/cursor-generator.js.map +1 -0
  95. package/dist/services/file-ops.d.ts +48 -0
  96. package/dist/services/file-ops.d.ts.map +1 -0
  97. package/dist/services/file-ops.js +153 -0
  98. package/dist/services/file-ops.js.map +1 -0
  99. package/dist/services/output-formatter.d.ts +57 -0
  100. package/dist/services/output-formatter.d.ts.map +1 -0
  101. package/dist/services/output-formatter.js +88 -0
  102. package/dist/services/output-formatter.js.map +1 -0
  103. package/dist/services/platform-detect.d.ts +14 -0
  104. package/dist/services/platform-detect.d.ts.map +1 -0
  105. package/dist/services/platform-detect.js +63 -0
  106. package/dist/services/platform-detect.js.map +1 -0
  107. package/dist/services/project-analyzer.d.ts +71 -0
  108. package/dist/services/project-analyzer.d.ts.map +1 -0
  109. package/dist/services/project-analyzer.js +595 -0
  110. package/dist/services/project-analyzer.js.map +1 -0
  111. package/dist/services/rules-engine.d.ts +41 -0
  112. package/dist/services/rules-engine.d.ts.map +1 -0
  113. package/dist/services/rules-engine.js +304 -0
  114. package/dist/services/rules-engine.js.map +1 -0
  115. package/dist/services/strictness.d.ts +37 -0
  116. package/dist/services/strictness.d.ts.map +1 -0
  117. package/dist/services/strictness.js +182 -0
  118. package/dist/services/strictness.js.map +1 -0
  119. package/dist/services/template-engine.d.ts +16 -0
  120. package/dist/services/template-engine.d.ts.map +1 -0
  121. package/dist/services/template-engine.js +85 -0
  122. package/dist/services/template-engine.js.map +1 -0
  123. package/dist/services/validation.d.ts +41 -0
  124. package/dist/services/validation.d.ts.map +1 -0
  125. package/dist/services/validation.js +104 -0
  126. package/dist/services/validation.js.map +1 -0
  127. package/dist/services/windsurf-generator.d.ts +15 -0
  128. package/dist/services/windsurf-generator.d.ts.map +1 -0
  129. package/dist/services/windsurf-generator.js +127 -0
  130. package/dist/services/windsurf-generator.js.map +1 -0
  131. package/dist/tests/enforcement.test.d.ts +2 -0
  132. package/dist/tests/enforcement.test.d.ts.map +1 -0
  133. package/dist/tests/enforcement.test.js +541 -0
  134. package/dist/tests/enforcement.test.js.map +1 -0
  135. package/dist/tests/enterprise.test.d.ts +2 -0
  136. package/dist/tests/enterprise.test.d.ts.map +1 -0
  137. package/dist/tests/enterprise.test.js +353 -0
  138. package/dist/tests/enterprise.test.js.map +1 -0
  139. package/dist/tests/fuzzing.test.d.ts +2 -0
  140. package/dist/tests/fuzzing.test.d.ts.map +1 -0
  141. package/dist/tests/fuzzing.test.js +596 -0
  142. package/dist/tests/fuzzing.test.js.map +1 -0
  143. package/dist/tests/knowledge.test.d.ts +2 -0
  144. package/dist/tests/knowledge.test.d.ts.map +1 -0
  145. package/dist/tests/knowledge.test.js +292 -0
  146. package/dist/tests/knowledge.test.js.map +1 -0
  147. package/dist/tests/management.test.d.ts +2 -0
  148. package/dist/tests/management.test.d.ts.map +1 -0
  149. package/dist/tests/management.test.js +338 -0
  150. package/dist/tests/management.test.js.map +1 -0
  151. package/dist/tests/scaffolding.test.d.ts +2 -0
  152. package/dist/tests/scaffolding.test.d.ts.map +1 -0
  153. package/dist/tests/scaffolding.test.js +419 -0
  154. package/dist/tests/scaffolding.test.js.map +1 -0
  155. package/dist/tests/test-utils.d.ts +76 -0
  156. package/dist/tests/test-utils.d.ts.map +1 -0
  157. package/dist/tests/test-utils.js +171 -0
  158. package/dist/tests/test-utils.js.map +1 -0
  159. package/dist/tests/tool-harness.d.ts +18 -0
  160. package/dist/tests/tool-harness.d.ts.map +1 -0
  161. package/dist/tests/tool-harness.js +51 -0
  162. package/dist/tests/tool-harness.js.map +1 -0
  163. package/dist/tools/enterprise.d.ts +8 -0
  164. package/dist/tools/enterprise.d.ts.map +1 -0
  165. package/dist/tools/enterprise.js +571 -0
  166. package/dist/tools/enterprise.js.map +1 -0
  167. package/dist/tools/knowledge.d.ts +7 -0
  168. package/dist/tools/knowledge.d.ts.map +1 -0
  169. package/dist/tools/knowledge.js +120 -0
  170. package/dist/tools/knowledge.js.map +1 -0
  171. package/dist/tools/management.d.ts +10 -0
  172. package/dist/tools/management.d.ts.map +1 -0
  173. package/dist/tools/management.js +1541 -0
  174. package/dist/tools/management.js.map +1 -0
  175. package/dist/tools/scaffolding.d.ts +8 -0
  176. package/dist/tools/scaffolding.d.ts.map +1 -0
  177. package/dist/tools/scaffolding.js +736 -0
  178. package/dist/tools/scaffolding.js.map +1 -0
  179. package/dist/types.d.ts +54 -0
  180. package/dist/types.d.ts.map +1 -0
  181. package/dist/types.js +5 -0
  182. package/dist/types.js.map +1 -0
  183. package/landing/app/layout.tsx +30 -0
  184. package/landing/app/page.tsx +944 -0
  185. package/landing/next-env.d.ts +6 -0
  186. package/landing/next.config.js +6 -0
  187. package/landing/package-lock.json +896 -0
  188. package/landing/package.json +20 -0
  189. package/landing/tsconfig.json +40 -0
  190. package/package.json +49 -0
  191. package/rebar-v2.0.0-platform-spec.md +1567 -0
  192. package/server.json +20 -0
  193. package/src/cli.ts +735 -0
  194. package/src/constants.ts +131 -0
  195. package/src/index.ts +54 -0
  196. package/src/schemas/common.ts +22 -0
  197. package/src/schemas/scaffolding.ts +161 -0
  198. package/src/services/claudemd-generator.ts +481 -0
  199. package/src/services/codex-generator.ts +44 -0
  200. package/src/services/cursor-generator.ts +153 -0
  201. package/src/services/file-ops.ts +172 -0
  202. package/src/services/platform-detect.ts +80 -0
  203. package/src/services/project-analyzer.ts +690 -0
  204. package/src/services/rules-engine.ts +353 -0
  205. package/src/services/strictness.ts +202 -0
  206. package/src/services/template-engine.ts +119 -0
  207. package/src/services/validation.ts +138 -0
  208. package/src/services/windsurf-generator.ts +145 -0
  209. package/src/tests/enforcement.test.ts +794 -0
  210. package/src/tests/enterprise.test.ts +483 -0
  211. package/src/tests/fuzzing.test.ts +690 -0
  212. package/src/tests/knowledge.test.ts +371 -0
  213. package/src/tests/management.test.ts +451 -0
  214. package/src/tests/scaffolding.test.ts +575 -0
  215. package/src/tests/test-utils.ts +206 -0
  216. package/src/tests/tool-harness.ts +70 -0
  217. package/src/tools/enterprise.ts +666 -0
  218. package/src/tools/knowledge.ts +162 -0
  219. package/src/tools/management.ts +1706 -0
  220. package/src/tools/scaffolding.ts +909 -0
  221. package/src/types.ts +93 -0
  222. package/supabase/.temp/cli-latest +1 -0
  223. package/supabase/.temp/gotrue-version +1 -0
  224. package/supabase/.temp/pooler-url +1 -0
  225. package/supabase/.temp/postgres-version +1 -0
  226. package/supabase/.temp/project-ref +1 -0
  227. package/supabase/.temp/rest-version +1 -0
  228. package/supabase/.temp/storage-migration +1 -0
  229. package/supabase/.temp/storage-version +1 -0
  230. package/templates/agents/explore.md +41 -0
  231. package/templates/agents/plan.md +73 -0
  232. package/templates/agents/security-auditor.md +77 -0
  233. package/templates/agents/test-runner.md +60 -0
  234. package/templates/claudemd/fastapi.md +49 -0
  235. package/templates/claudemd/monorepo.md +48 -0
  236. package/templates/claudemd/nextjs.md +52 -0
  237. package/templates/claudemd/react-spa.md +50 -0
  238. package/templates/claudemd/springboot.md +50 -0
  239. package/templates/hooks/danger-blocker.json +11 -0
  240. package/templates/hooks/format-on-write.json +17 -0
  241. package/templates/hooks/lint-on-write.json +16 -0
  242. package/templates/hooks/secret-detector.json +11 -0
  243. package/templates/skills/code-review.md +68 -0
  244. package/templates/skills/documentation.md +62 -0
  245. package/templates/skills/performance-audit.md +80 -0
  246. package/templates/skills/security-scan.md +66 -0
  247. package/templates/skills/test-writer.md +56 -0
  248. package/tsconfig.json +19 -0
@@ -0,0 +1,172 @@
1
+ /**
2
+ * File operations service with atomic writes and safety checks
3
+ */
4
+ import * as fs from "node:fs/promises";
5
+ import * as path from "node:path";
6
+ import * as os from "node:os";
7
+ import * as crypto from "node:crypto";
8
+
9
+ /**
10
+ * Ensures a directory exists, creating it recursively if needed.
11
+ */
12
+ export async function ensureDir(dirPath: string): Promise<void> {
13
+ await fs.mkdir(dirPath, { recursive: true });
14
+ }
15
+
16
+ /**
17
+ * Writes a file atomically: writes to a temp file first, then renames.
18
+ * This prevents partial writes from corrupting existing files.
19
+ */
20
+ export async function atomicWrite(filePath: string, content: string): Promise<void> {
21
+ const dir = path.dirname(filePath);
22
+ await ensureDir(dir);
23
+
24
+ const tmpName = `.tmp-${crypto.randomBytes(8).toString("hex")}`;
25
+ const tmpPath = path.join(dir, tmpName);
26
+
27
+ try {
28
+ await fs.writeFile(tmpPath, content, "utf-8");
29
+ await fs.rename(tmpPath, filePath);
30
+ } catch (err: unknown) {
31
+ // Clean up temp file on failure
32
+ try {
33
+ await fs.unlink(tmpPath);
34
+ } catch {
35
+ // Ignore cleanup errors
36
+ }
37
+ throw err;
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Checks if a file exists.
43
+ */
44
+ export async function fileExists(filePath: string): Promise<boolean> {
45
+ try {
46
+ await fs.access(filePath);
47
+ return true;
48
+ } catch {
49
+ return false;
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Reads a file and returns its content, or null if it doesn't exist.
55
+ */
56
+ export async function readFileSafe(filePath: string): Promise<string | null> {
57
+ try {
58
+ return await fs.readFile(filePath, "utf-8");
59
+ } catch {
60
+ return null;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Lists files in a directory matching an optional extension filter.
66
+ */
67
+ export async function listFiles(
68
+ dirPath: string,
69
+ extension?: string
70
+ ): Promise<string[]> {
71
+ try {
72
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
73
+ return entries
74
+ .filter((e) => e.isFile() && (!extension || e.name.endsWith(extension)))
75
+ .map((e) => path.join(dirPath, e.name));
76
+ } catch {
77
+ return [];
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Recursively lists all files under a directory.
83
+ */
84
+ export async function listFilesRecursive(
85
+ dirPath: string,
86
+ extension?: string
87
+ ): Promise<string[]> {
88
+ const results: string[] = [];
89
+ try {
90
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
91
+ for (const entry of entries) {
92
+ const fullPath = path.join(dirPath, entry.name);
93
+ if (entry.isDirectory()) {
94
+ const sub = await listFilesRecursive(fullPath, extension);
95
+ results.push(...sub);
96
+ } else if (!extension || entry.name.endsWith(extension)) {
97
+ results.push(fullPath);
98
+ }
99
+ }
100
+ } catch {
101
+ // Directory doesn't exist or not readable
102
+ }
103
+ return results;
104
+ }
105
+
106
+ /**
107
+ * Resolves a project path to an absolute path.
108
+ */
109
+ export function resolveProjectPath(projectPath: string): string {
110
+ if (path.isAbsolute(projectPath)) {
111
+ return path.normalize(projectPath);
112
+ }
113
+ return path.resolve(process.cwd(), projectPath);
114
+ }
115
+
116
+ /**
117
+ * Sanitizes a file path to prevent directory traversal attacks.
118
+ * Ensures the resolved path is within the project root.
119
+ */
120
+ export function sanitizePath(basePath: string, relativePath: string): string {
121
+ const resolved = path.resolve(basePath, relativePath);
122
+ const normalizedBase = path.normalize(basePath);
123
+ if (!resolved.startsWith(normalizedBase)) {
124
+ throw new Error(
125
+ `Path traversal detected: "${relativePath}" resolves outside project root`
126
+ );
127
+ }
128
+ return resolved;
129
+ }
130
+
131
+ /**
132
+ * Writes a file only if it doesn't exist or mergeExisting is true.
133
+ * Returns info about what was done.
134
+ */
135
+ export async function safeWriteFile(
136
+ filePath: string,
137
+ content: string,
138
+ mergeExisting: boolean
139
+ ): Promise<{ written: boolean; merged: boolean; message: string }> {
140
+ const exists = await fileExists(filePath);
141
+
142
+ if (exists && !mergeExisting) {
143
+ return {
144
+ written: false,
145
+ merged: false,
146
+ message: `File already exists: ${filePath}. Set merge_existing=true to overwrite.`,
147
+ };
148
+ }
149
+
150
+ if (exists && mergeExisting) {
151
+ await atomicWrite(filePath, content);
152
+ return {
153
+ written: true,
154
+ merged: true,
155
+ message: `Merged/updated: ${filePath}`,
156
+ };
157
+ }
158
+
159
+ await atomicWrite(filePath, content);
160
+ return {
161
+ written: true,
162
+ merged: false,
163
+ message: `Created: ${filePath}`,
164
+ };
165
+ }
166
+
167
+ /**
168
+ * Creates a temp directory for intermediate operations.
169
+ */
170
+ export async function createTempDir(): Promise<string> {
171
+ return await fs.mkdtemp(path.join(os.tmpdir(), "rebar-"));
172
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Platform detection for multi-AI-tool support.
3
+ *
4
+ * Detects which AI coding platforms are configured in a project:
5
+ * - Claude Code: .claude/ directory or CLAUDE.md
6
+ * - Cursor: .cursor/ directory or .cursorrules
7
+ * - Windsurf: .windsurf/ directory
8
+ * - Codex CLI: AGENTS.md
9
+ */
10
+ import * as path from "node:path";
11
+ import { fileExists } from "./file-ops.js";
12
+
13
+ export type AIPlatform = "claude-code" | "cursor" | "windsurf" | "codex";
14
+
15
+ export interface DetectedPlatforms {
16
+ platforms: AIPlatform[];
17
+ evidence: Record<AIPlatform, string>;
18
+ }
19
+
20
+ /**
21
+ * Detects which AI coding platforms are configured in a project.
22
+ */
23
+ export async function detectPlatforms(projectPath: string): Promise<DetectedPlatforms> {
24
+ const platforms: AIPlatform[] = [];
25
+ const evidence: Partial<Record<AIPlatform, string>> = {};
26
+
27
+ // Claude Code: .claude/ directory or CLAUDE.md exists
28
+ if (await fileExists(path.join(projectPath, ".claude")) || await fileExists(path.join(projectPath, "CLAUDE.md"))) {
29
+ platforms.push("claude-code");
30
+ evidence["claude-code"] = "Found .claude/ directory or CLAUDE.md";
31
+ }
32
+
33
+ // Cursor: .cursor/ directory or .cursorrules exists
34
+ if (await fileExists(path.join(projectPath, ".cursor")) || await fileExists(path.join(projectPath, ".cursorrules"))) {
35
+ platforms.push("cursor");
36
+ evidence["cursor"] = "Found .cursor/ directory or .cursorrules";
37
+ }
38
+
39
+ // Windsurf: .windsurf/ directory exists
40
+ if (await fileExists(path.join(projectPath, ".windsurf"))) {
41
+ platforms.push("windsurf");
42
+ evidence["windsurf"] = "Found .windsurf/ directory";
43
+ }
44
+
45
+ // Codex: AGENTS.md exists
46
+ if (await fileExists(path.join(projectPath, "AGENTS.md"))) {
47
+ platforms.push("codex");
48
+ evidence["codex"] = "Found AGENTS.md";
49
+ }
50
+
51
+ // If nothing detected, default to Claude Code (since we're an MCP server running in it)
52
+ if (platforms.length === 0) {
53
+ platforms.push("claude-code");
54
+ evidence["claude-code"] = "Default (no platform detected)";
55
+ }
56
+
57
+ return {
58
+ platforms,
59
+ evidence: evidence as Record<AIPlatform, string>,
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Resolves "all" platform specifier to actual platforms.
65
+ */
66
+ export async function resolvePlatforms(
67
+ projectPath: string,
68
+ specified: string[]
69
+ ): Promise<AIPlatform[]> {
70
+ if (specified.includes("all")) {
71
+ // Detect existing platforms, or generate for all if none found
72
+ const detected = await detectPlatforms(projectPath);
73
+ if (detected.platforms.length <= 1 && detected.evidence["claude-code"]?.includes("Default")) {
74
+ // Nothing detected, generate for all platforms
75
+ return ["claude-code", "cursor", "windsurf", "codex"];
76
+ }
77
+ return detected.platforms;
78
+ }
79
+ return specified.filter((p) => p !== "all") as AIPlatform[];
80
+ }