create-standards 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 (83) hide show
  1. package/README.md +89 -0
  2. package/bin/create-standards.js +3 -0
  3. package/package.json +32 -0
  4. package/src/cli.js +355 -0
  5. package/src/discover.js +113 -0
  6. package/src/ide-config.js +57 -0
  7. package/src/install.js +77 -0
  8. package/standards/nodejs-express-standards/README.md +59 -0
  9. package/standards/nodejs-express-standards/antigravity/.agents/skills/nodejs-express-standards/SKILL.md +40 -0
  10. package/standards/nodejs-express-standards/antigravity/.agents/skills/nodejs-express-standards/references/01-project-structure.md +33 -0
  11. package/standards/nodejs-express-standards/antigravity/.agents/skills/nodejs-express-standards/references/02-api-design-standards.md +41 -0
  12. package/standards/nodejs-express-standards/antigravity/.agents/skills/nodejs-express-standards/references/03-error-handling-validation.md +27 -0
  13. package/standards/nodejs-express-standards/antigravity/.agents/skills/nodejs-express-standards/references/04-security-standards.md +17 -0
  14. package/standards/nodejs-express-standards/antigravity/.agents/skills/nodejs-express-standards/references/05-database-model-standards.md +10 -0
  15. package/standards/nodejs-express-standards/antigravity/.agents/skills/nodejs-express-standards/references/06-testing-standards.md +10 -0
  16. package/standards/nodejs-express-standards/antigravity/.agents/skills/nodejs-express-standards/references/07-new-component-checklist.md +16 -0
  17. package/standards/nodejs-express-standards/antigravity/.agents/skills/nodejs-express-standards/references/08-code-style-general.md +9 -0
  18. package/standards/nodejs-express-standards/claude-code/.claude/skills/nodejs-express-standards/SKILL.md +40 -0
  19. package/standards/nodejs-express-standards/claude-code/.claude/skills/nodejs-express-standards/references/01-project-structure.md +33 -0
  20. package/standards/nodejs-express-standards/claude-code/.claude/skills/nodejs-express-standards/references/02-api-design-standards.md +41 -0
  21. package/standards/nodejs-express-standards/claude-code/.claude/skills/nodejs-express-standards/references/03-error-handling-validation.md +27 -0
  22. package/standards/nodejs-express-standards/claude-code/.claude/skills/nodejs-express-standards/references/04-security-standards.md +17 -0
  23. package/standards/nodejs-express-standards/claude-code/.claude/skills/nodejs-express-standards/references/05-database-model-standards.md +10 -0
  24. package/standards/nodejs-express-standards/claude-code/.claude/skills/nodejs-express-standards/references/06-testing-standards.md +10 -0
  25. package/standards/nodejs-express-standards/claude-code/.claude/skills/nodejs-express-standards/references/07-new-component-checklist.md +16 -0
  26. package/standards/nodejs-express-standards/claude-code/.claude/skills/nodejs-express-standards/references/08-code-style-general.md +9 -0
  27. package/standards/nodejs-express-standards/cursor/.cursor/rules/00-index.mdc +25 -0
  28. package/standards/nodejs-express-standards/cursor/.cursor/rules/01-project-structure.mdc +38 -0
  29. package/standards/nodejs-express-standards/cursor/.cursor/rules/02-api-design.mdc +46 -0
  30. package/standards/nodejs-express-standards/cursor/.cursor/rules/03-error-handling-validation.mdc +32 -0
  31. package/standards/nodejs-express-standards/cursor/.cursor/rules/04-security.mdc +22 -0
  32. package/standards/nodejs-express-standards/cursor/.cursor/rules/05-database-models.mdc +15 -0
  33. package/standards/nodejs-express-standards/cursor/.cursor/rules/06-testing.mdc +15 -0
  34. package/standards/nodejs-express-standards/cursor/.cursor/rules/07-new-component-checklist.mdc +21 -0
  35. package/standards/nodejs-express-standards/cursor/.cursor/rules/08-code-style.mdc +14 -0
  36. package/standards/nodejs-express-standards/shared-reference/01-project-structure.md +33 -0
  37. package/standards/nodejs-express-standards/shared-reference/02-api-design-standards.md +41 -0
  38. package/standards/nodejs-express-standards/shared-reference/03-error-handling-validation.md +27 -0
  39. package/standards/nodejs-express-standards/shared-reference/04-security-standards.md +17 -0
  40. package/standards/nodejs-express-standards/shared-reference/05-database-model-standards.md +10 -0
  41. package/standards/nodejs-express-standards/shared-reference/06-testing-standards.md +10 -0
  42. package/standards/nodejs-express-standards/shared-reference/07-new-component-checklist.md +16 -0
  43. package/standards/nodejs-express-standards/shared-reference/08-code-style-general.md +8 -0
  44. package/standards/rails-standards/README.md +86 -0
  45. package/standards/rails-standards/antigravity/.agents/skills/rails-standards/SKILL.md +66 -0
  46. package/standards/rails-standards/antigravity/.agents/skills/rails-standards/references/00-quick-scaffold.md +83 -0
  47. package/standards/rails-standards/antigravity/.agents/skills/rails-standards/references/01-project-structure.md +44 -0
  48. package/standards/rails-standards/antigravity/.agents/skills/rails-standards/references/02-api-design-standards.md +46 -0
  49. package/standards/rails-standards/antigravity/.agents/skills/rails-standards/references/03-error-handling-validation.md +35 -0
  50. package/standards/rails-standards/antigravity/.agents/skills/rails-standards/references/04-security-standards.md +32 -0
  51. package/standards/rails-standards/antigravity/.agents/skills/rails-standards/references/05-database-model-standards.md +25 -0
  52. package/standards/rails-standards/antigravity/.agents/skills/rails-standards/references/06-testing-standards.md +26 -0
  53. package/standards/rails-standards/antigravity/.agents/skills/rails-standards/references/07-new-component-checklist.md +26 -0
  54. package/standards/rails-standards/antigravity/.agents/skills/rails-standards/references/08-code-style-general.md +47 -0
  55. package/standards/rails-standards/claude-code/.claude/skills/rails-standards/SKILL.md +66 -0
  56. package/standards/rails-standards/claude-code/.claude/skills/rails-standards/references/00-quick-scaffold.md +83 -0
  57. package/standards/rails-standards/claude-code/.claude/skills/rails-standards/references/01-project-structure.md +44 -0
  58. package/standards/rails-standards/claude-code/.claude/skills/rails-standards/references/02-api-design-standards.md +46 -0
  59. package/standards/rails-standards/claude-code/.claude/skills/rails-standards/references/03-error-handling-validation.md +35 -0
  60. package/standards/rails-standards/claude-code/.claude/skills/rails-standards/references/04-security-standards.md +32 -0
  61. package/standards/rails-standards/claude-code/.claude/skills/rails-standards/references/05-database-model-standards.md +25 -0
  62. package/standards/rails-standards/claude-code/.claude/skills/rails-standards/references/06-testing-standards.md +26 -0
  63. package/standards/rails-standards/claude-code/.claude/skills/rails-standards/references/07-new-component-checklist.md +26 -0
  64. package/standards/rails-standards/claude-code/.claude/skills/rails-standards/references/08-code-style-general.md +47 -0
  65. package/standards/rails-standards/cursor/.cursor/rules/00-always-on.mdc +26 -0
  66. package/standards/rails-standards/cursor/.cursor/rules/01-project-structure.mdc +49 -0
  67. package/standards/rails-standards/cursor/.cursor/rules/02-api-design.mdc +51 -0
  68. package/standards/rails-standards/cursor/.cursor/rules/03-error-handling-validation.mdc +40 -0
  69. package/standards/rails-standards/cursor/.cursor/rules/04-security.mdc +37 -0
  70. package/standards/rails-standards/cursor/.cursor/rules/05-database-models.mdc +30 -0
  71. package/standards/rails-standards/cursor/.cursor/rules/06-testing.mdc +31 -0
  72. package/standards/rails-standards/cursor/.cursor/rules/07-new-component-checklist.mdc +31 -0
  73. package/standards/rails-standards/cursor/.cursor/rules/08-code-style.mdc +52 -0
  74. package/standards/rails-standards/cursor/.cursor/rules/09-quick-scaffold.mdc +88 -0
  75. package/standards/rails-standards/shared-reference/00-quick-scaffold.md +83 -0
  76. package/standards/rails-standards/shared-reference/01-project-structure.md +44 -0
  77. package/standards/rails-standards/shared-reference/02-api-design-standards.md +46 -0
  78. package/standards/rails-standards/shared-reference/03-error-handling-validation.md +35 -0
  79. package/standards/rails-standards/shared-reference/04-security-standards.md +32 -0
  80. package/standards/rails-standards/shared-reference/05-database-model-standards.md +25 -0
  81. package/standards/rails-standards/shared-reference/06-testing-standards.md +26 -0
  82. package/standards/rails-standards/shared-reference/07-new-component-checklist.md +26 -0
  83. package/standards/rails-standards/shared-reference/08-code-style-general.md +47 -0
package/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # create-standards
2
+
3
+ Install coding standards for known tech stacks into your project. Copies Cursor rules, Claude Code skills, and Antigravity skills so each tool picks them up automatically — no extra config.
4
+
5
+ ## Install / run
6
+
7
+ ```bash
8
+ # one-shot
9
+ npx create-standards --list
10
+ npx create-standards rails
11
+ npx create-standards rails --cursor
12
+
13
+ # or via npm create
14
+ npm create standards -- --list
15
+ npm create standards -- rails
16
+ npm create standards -- rails --cursor
17
+
18
+ # global
19
+ npm i -g create-standards
20
+ create-standards rails --claude
21
+ create-standards rails --cursor
22
+ ```
23
+
24
+ ## Commands
25
+
26
+ | Command | What it does |
27
+ |---|---|
28
+ | `create-standards --list` | List stacks and example commands |
29
+ | `create-standards <stack>` | Install **all** IDE packs + `shared-reference/` |
30
+ | `create-standards <stack> --cursor` | Cursor only → `.cursor/` |
31
+ | `create-standards <stack> --claude` | Claude Code only → `.claude/` |
32
+ | `create-standards <stack> --antigravity` | Antigravity only → `.agents/` |
33
+ | `create-standards <stack> --cursor --claude` | Multiple IDEs |
34
+ | `create-standards` (no args, TTY) | Interactive picker |
35
+
36
+ Aliases: `--available-stack` for `--list`, `--claude-code` for `--claude`.
37
+
38
+ ### Options
39
+
40
+ | Flag | Meaning |
41
+ |---|---|
42
+ | `--path <dir>` / `-C <dir>` | Install into another directory (default: cwd) |
43
+ | `--force` | Overwrite existing destinations |
44
+ | `--dry-run` | Print destinations without writing |
45
+ | `--no-shared` | Skip `shared-reference/` |
46
+ | `-h` / `--help` | Help |
47
+
48
+ ## What gets created
49
+
50
+ For a full install of `rails`:
51
+
52
+ ```text
53
+ .cursor/ # from standards/rails-standards/cursor/.cursor
54
+ .claude/ # from standards/rails-standards/claude-code/.claude
55
+ .agents/ # from standards/rails-standards/antigravity/.agents
56
+ shared-reference/ # human-readable source docs
57
+ ```
58
+
59
+ These paths are what Cursor, Claude Code, and Antigravity already look for — no parent wrapper folder.
60
+
61
+ ## Available stacks
62
+
63
+ Stacks are discovered automatically from the package’s `standards/` folder. Adding a new directory (for example `standards/django-standards/`) with the same IDE layout makes it show up in `--list` and installable as `create-standards django` after you publish a new version.
64
+
65
+ Current packs in this repo:
66
+
67
+ - `rails` (`rails-standards`)
68
+ - `nodejs-express` (`nodejs-express-standards`)
69
+
70
+ ## Local development
71
+
72
+ From this repo (without publishing):
73
+
74
+ ```bash
75
+ node bin/create-standards.js --list
76
+ node bin/create-standards.js rails --dry-run
77
+ node bin/create-standards.js rails --cursor --path /tmp/test-app --force
78
+ ```
79
+
80
+ ## Publish
81
+
82
+ ```bash
83
+ npm login
84
+ npm publish
85
+ ```
86
+
87
+ ## License
88
+
89
+ ISC
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require('../src/cli').run(process.argv.slice(2));
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "create-standards",
3
+ "version": "1.0.0",
4
+ "description": "Install coding standards (Cursor, Claude Code, Antigravity) for known tech stacks into your project",
5
+ "main": "src/cli.js",
6
+ "bin": {
7
+ "create-standards": "./bin/create-standards.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "src",
12
+ "standards"
13
+ ],
14
+ "scripts": {
15
+ "start": "node bin/create-standards.js",
16
+ "test": "node bin/create-standards.js --list"
17
+ },
18
+ "keywords": [
19
+ "standards",
20
+ "cursor",
21
+ "claude",
22
+ "antigravity",
23
+ "coding-standards",
24
+ "create-standards"
25
+ ],
26
+ "author": "Sakshi Jain",
27
+ "license": "ISC",
28
+ "type": "commonjs",
29
+ "engines": {
30
+ "node": ">=18"
31
+ }
32
+ }
package/src/cli.js ADDED
@@ -0,0 +1,355 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const readline = require('readline');
4
+ const { listAvailableStacks, findStackByName } = require('./discover');
5
+ const { getIdeFolderFromFlag } = require('./ide-config');
6
+ const { copyStandardsIntoProject } = require('./install');
7
+
8
+ const RESERVED_FLAGS = new Set([
9
+ 'list',
10
+ 'available-stack',
11
+ 'available-stacks',
12
+ 'help',
13
+ 'h',
14
+ 'dry-run',
15
+ 'force',
16
+ 'path',
17
+ 'C',
18
+ 'no-shared',
19
+ 'stack',
20
+ ]);
21
+
22
+ const FLAG_DISPLAY_ORDER = ['cursor', 'claude', 'claude-code', 'antigravity'];
23
+
24
+ function sortIdeFlags(flags) {
25
+ return [...flags].sort((a, b) => {
26
+ const orderA = FLAG_DISPLAY_ORDER.indexOf(a);
27
+ const orderB = FLAG_DISPLAY_ORDER.indexOf(b);
28
+ const rankA = orderA === -1 ? Number.MAX_SAFE_INTEGER : orderA;
29
+ const rankB = orderB === -1 ? Number.MAX_SAFE_INTEGER : orderB;
30
+ if (rankA !== rankB) return rankA - rankB;
31
+ return a.localeCompare(b);
32
+ });
33
+ }
34
+
35
+ function getDisplayFlagsForStack(stack) {
36
+ const flags = sortIdeFlags(stack.idePacks.flatMap((pack) => pack.flags));
37
+ return flags.map((flag) => `--${flag}`);
38
+ }
39
+
40
+ function printHelp(stacks) {
41
+ const stackLines =
42
+ stacks.length === 0
43
+ ? ' (no stacks found under standards/)'
44
+ : stacks
45
+ .map((stack) => {
46
+ const flags = getDisplayFlagsForStack(stack);
47
+ return (
48
+ ` ${stack.shortName} (${stack.folderName})\n` +
49
+ ` Flags: ${flags.length ? flags.join(', ') : '(none)'}\n` +
50
+ ` create-standards ${stack.shortName}\n` +
51
+ ` create-standards ${stack.shortName}${flags[0] ? ` ${flags[0]}` : ''}`
52
+ );
53
+ })
54
+ .join('\n\n');
55
+
56
+ console.log(`Usage:
57
+ create-standards --list
58
+ create-standards <stack> [--cursor] [--claude] [--antigravity] [options]
59
+ create-standards --stack <stack> [options]
60
+
61
+ Install coding standards into the current project directory.
62
+ Without IDE flags, all available IDEs for that stack are installed.
63
+
64
+ Options:
65
+ --list, --available-stack List stacks and example commands
66
+ --stack <name> Stack to install (alternative to positional)
67
+ --cursor Install Cursor rules only (.cursor/)
68
+ --claude, --claude-code Install Claude Code skill only (.claude/)
69
+ --antigravity Install Antigravity skill only (.agents/)
70
+ --path <dir>, -C <dir> Target directory (default: cwd)
71
+ --force Overwrite existing destinations
72
+ --dry-run Show what would be copied
73
+ --no-shared Skip shared-reference/
74
+ -h, --help Show help
75
+
76
+ Available stacks:
77
+
78
+ ${stackLines}
79
+ `);
80
+ }
81
+
82
+ function printAvailableStacks(stacks) {
83
+ if (stacks.length === 0) {
84
+ console.log('No stacks found under standards/.');
85
+ return;
86
+ }
87
+
88
+ console.log('Available stacks:\n');
89
+ for (const stack of stacks) {
90
+ const flags = getDisplayFlagsForStack(stack);
91
+ console.log(` ${stack.shortName} (${stack.folderName})`);
92
+ console.log(` Flags: ${flags.length ? flags.join(', ') : '(none)'}`);
93
+ console.log(` create-standards ${stack.shortName}`);
94
+ if (flags[0]) {
95
+ console.log(` create-standards ${stack.shortName} ${flags[0]}`);
96
+ }
97
+ console.log('');
98
+ }
99
+ }
100
+
101
+ function parseCommandLineArgs(argv) {
102
+ const options = {
103
+ help: false,
104
+ list: false,
105
+ stackName: null,
106
+ ideFlags: [],
107
+ targetFolder: process.cwd(),
108
+ force: false,
109
+ dryRun: false,
110
+ includeSharedReference: true,
111
+ extraArgs: [],
112
+ };
113
+
114
+ for (let i = 0; i < argv.length; i++) {
115
+ const arg = argv[i];
116
+
117
+ if (arg === '--help' || arg === '-h') {
118
+ options.help = true;
119
+ continue;
120
+ }
121
+ if (arg === '--list' || arg === '--available-stack' || arg === '--available-stacks') {
122
+ options.list = true;
123
+ continue;
124
+ }
125
+ if (arg === '--force') {
126
+ options.force = true;
127
+ continue;
128
+ }
129
+ if (arg === '--dry-run') {
130
+ options.dryRun = true;
131
+ continue;
132
+ }
133
+ if (arg === '--no-shared') {
134
+ options.includeSharedReference = false;
135
+ continue;
136
+ }
137
+ if (arg === '--path' || arg === '-C') {
138
+ const value = argv[++i];
139
+ if (!value) throw new Error(`${arg} requires a directory path`);
140
+ options.targetFolder = path.resolve(value);
141
+ continue;
142
+ }
143
+ if (arg.startsWith('--path=')) {
144
+ options.targetFolder = path.resolve(arg.slice('--path='.length));
145
+ continue;
146
+ }
147
+ if (arg === '--stack') {
148
+ const value = argv[++i];
149
+ if (!value) throw new Error('--stack requires a name');
150
+ options.stackName = value;
151
+ continue;
152
+ }
153
+ if (arg.startsWith('--stack=')) {
154
+ options.stackName = arg.slice('--stack='.length);
155
+ continue;
156
+ }
157
+
158
+ if (arg.startsWith('--')) {
159
+ const flag = arg.slice(2);
160
+ if (RESERVED_FLAGS.has(flag)) {
161
+ throw new Error(`Unexpected use of --${flag}`);
162
+ }
163
+ options.ideFlags.push(flag);
164
+ continue;
165
+ }
166
+
167
+ if (arg.startsWith('-') && arg.length > 1) {
168
+ throw new Error(`Unknown option: ${arg}`);
169
+ }
170
+
171
+ options.extraArgs.push(arg);
172
+ }
173
+
174
+ if (!options.stackName && options.extraArgs.length > 0) {
175
+ options.stackName = options.extraArgs[0];
176
+ }
177
+ if (options.extraArgs.length > 1) {
178
+ throw new Error(
179
+ `Unexpected arguments: ${options.extraArgs.slice(1).join(', ')}. ` +
180
+ 'Pass IDE choices as flags, e.g. --cursor'
181
+ );
182
+ }
183
+
184
+ return options;
185
+ }
186
+
187
+ // Empty array means install every IDE for the stack
188
+ function resolveSelectedIdeFolders(ideFlags, stack) {
189
+ if (ideFlags.length === 0) return [];
190
+
191
+ const selected = [];
192
+ const seen = new Set();
193
+
194
+ for (const flag of ideFlags) {
195
+ const ideFolder = getIdeFolderFromFlag(flag);
196
+ const match = stack.idePacks.find(
197
+ (pack) => pack.ideFolder === ideFolder || pack.flags.includes(flag)
198
+ );
199
+
200
+ if (!match) {
201
+ const available = stack.idePacks.flatMap((pack) =>
202
+ pack.flags.map((name) => `--${name}`)
203
+ );
204
+ throw new Error(
205
+ `Unknown or unavailable IDE flag --${flag} for stack "${stack.shortName}".\n` +
206
+ `Available: ${available.length ? available.join(', ') : '(none)'}`
207
+ );
208
+ }
209
+
210
+ if (!seen.has(match.ideFolder)) {
211
+ seen.add(match.ideFolder);
212
+ selected.push(match.ideFolder);
213
+ }
214
+ }
215
+
216
+ return selected;
217
+ }
218
+
219
+ function askQuestion(rl, prompt) {
220
+ return new Promise((resolve) => {
221
+ rl.question(prompt, (answer) => resolve(answer.trim()));
222
+ });
223
+ }
224
+
225
+ async function promptForStackAndIde(stacks) {
226
+ if (stacks.length === 0) {
227
+ throw new Error('No stacks found under standards/.');
228
+ }
229
+
230
+ const rl = readline.createInterface({
231
+ input: process.stdin,
232
+ output: process.stdout,
233
+ });
234
+
235
+ try {
236
+ console.log('Available stacks:\n');
237
+ stacks.forEach((stack, index) => {
238
+ console.log(` ${index + 1}. ${stack.shortName}`);
239
+ });
240
+ console.log('');
241
+
242
+ const stackAnswer = await askQuestion(rl, `Choose a stack [1-${stacks.length}]: `);
243
+ const stackIndex = Number.parseInt(stackAnswer, 10);
244
+ if (!Number.isInteger(stackIndex) || stackIndex < 1 || stackIndex > stacks.length) {
245
+ throw new Error('Invalid stack selection.');
246
+ }
247
+ const stack = stacks[stackIndex - 1];
248
+
249
+ console.log('\nInstall target:\n');
250
+ console.log(' 1. All IDEs');
251
+ stack.idePacks.forEach((pack, index) => {
252
+ console.log(
253
+ ` ${index + 2}. ${pack.ideFolder} (${pack.flags.map((flag) => `--${flag}`).join(', ')})`
254
+ );
255
+ });
256
+ console.log('');
257
+
258
+ const ideAnswer = await askQuestion(
259
+ rl,
260
+ `Choose IDE [1-${stack.idePacks.length + 1}] (default 1): `
261
+ );
262
+ const ideIndex = ideAnswer === '' ? 1 : Number.parseInt(ideAnswer, 10);
263
+ if (
264
+ !Number.isInteger(ideIndex) ||
265
+ ideIndex < 1 ||
266
+ ideIndex > stack.idePacks.length + 1
267
+ ) {
268
+ throw new Error('Invalid IDE selection.');
269
+ }
270
+
271
+ return {
272
+ stackName: stack.shortName,
273
+ selectedIdeFolders: ideIndex === 1 ? [] : [stack.idePacks[ideIndex - 2].ideFolder],
274
+ };
275
+ } finally {
276
+ rl.close();
277
+ }
278
+ }
279
+
280
+ function installAndReport(stack, selectedIdeFolders, options) {
281
+ const { createdPaths } = copyStandardsIntoProject({
282
+ stack,
283
+ selectedIdeFolders,
284
+ targetFolder: options.targetFolder,
285
+ force: options.force,
286
+ dryRun: options.dryRun,
287
+ includeSharedReference: options.includeSharedReference,
288
+ });
289
+
290
+ console.log(options.dryRun ? '[dry-run] Would create:' : 'Created:');
291
+ for (const createdPath of createdPaths) {
292
+ console.log(` ${createdPath}`);
293
+ }
294
+ if (!options.dryRun) {
295
+ console.log(
296
+ `\nInstalled "${stack.shortName}" standards into ${path.resolve(options.targetFolder)}`
297
+ );
298
+ }
299
+ }
300
+
301
+ function ensureTargetFolderExists(targetFolder) {
302
+ if (!fs.existsSync(targetFolder)) {
303
+ fs.mkdirSync(targetFolder, { recursive: true });
304
+ }
305
+ }
306
+
307
+ async function run(argv) {
308
+ try {
309
+ const stacks = listAvailableStacks();
310
+ const options = parseCommandLineArgs(argv);
311
+
312
+ if (options.help) {
313
+ printHelp(stacks);
314
+ return;
315
+ }
316
+
317
+ if (options.list) {
318
+ printAvailableStacks(stacks);
319
+ return;
320
+ }
321
+
322
+ if (!options.stackName) {
323
+ if (!process.stdin.isTTY) {
324
+ printHelp(stacks);
325
+ process.exitCode = 1;
326
+ return;
327
+ }
328
+
329
+ const choice = await promptForStackAndIde(stacks);
330
+ const stack = findStackByName(choice.stackName);
331
+ if (!stack) throw new Error(`Unknown stack: ${choice.stackName}`);
332
+
333
+ ensureTargetFolderExists(options.targetFolder);
334
+ installAndReport(stack, choice.selectedIdeFolders, options);
335
+ return;
336
+ }
337
+
338
+ const stack = findStackByName(options.stackName);
339
+ if (!stack) {
340
+ const names = stacks.map((item) => item.shortName).join(', ');
341
+ throw new Error(
342
+ `Unknown stack "${options.stackName}". Available: ${names || '(none)'}`
343
+ );
344
+ }
345
+
346
+ const selectedIdeFolders = resolveSelectedIdeFolders(options.ideFlags, stack);
347
+ ensureTargetFolderExists(options.targetFolder);
348
+ installAndReport(stack, selectedIdeFolders, options);
349
+ } catch (error) {
350
+ console.error(`Error: ${error.message}`);
351
+ process.exitCode = 1;
352
+ }
353
+ }
354
+
355
+ module.exports = { run, parseCommandLineArgs };
@@ -0,0 +1,113 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const {
4
+ IDE_CONFIG,
5
+ getStackShortName,
6
+ getFlagsForIde,
7
+ getInstallPathsForIde,
8
+ } = require('./ide-config');
9
+
10
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
11
+ const STANDARDS_FOLDER = path.join(PACKAGE_ROOT, 'standards');
12
+
13
+ function isDirectory(filePath) {
14
+ return fs.existsSync(filePath) && fs.statSync(filePath).isDirectory();
15
+ }
16
+
17
+ // Find IDE packs inside one stack folder (cursor/, claude-code/, antigravity/, …)
18
+ function findIdePacksInStack(stackPath) {
19
+ if (!isDirectory(stackPath)) return [];
20
+
21
+ const idePacks = [];
22
+
23
+ for (const entry of fs.readdirSync(stackPath, { withFileTypes: true })) {
24
+ if (!entry.isDirectory()) continue;
25
+ if (entry.name === 'shared-reference' || entry.name.startsWith('.')) continue;
26
+
27
+ const ideFolder = entry.name;
28
+ const idePath = path.join(stackPath, ideFolder);
29
+
30
+ if (IDE_CONFIG[ideFolder]) {
31
+ const { sourceFolder, installAs } = getInstallPathsForIde(ideFolder);
32
+ const sourcePath = path.join(idePath, sourceFolder);
33
+ if (isDirectory(sourcePath)) {
34
+ idePacks.push({
35
+ ideFolder,
36
+ sourcePath,
37
+ installAs,
38
+ flags: getFlagsForIde(ideFolder),
39
+ });
40
+ }
41
+ continue;
42
+ }
43
+
44
+ // Newer IDE folders: look for .<name> or a single hidden nested folder
45
+ const preferredSource = path.join(idePath, `.${ideFolder}`);
46
+ if (isDirectory(preferredSource)) {
47
+ idePacks.push({
48
+ ideFolder,
49
+ sourcePath: preferredSource,
50
+ installAs: `.${ideFolder}`,
51
+ flags: getFlagsForIde(ideFolder),
52
+ });
53
+ continue;
54
+ }
55
+
56
+ const hiddenFolders = fs
57
+ .readdirSync(idePath, { withFileTypes: true })
58
+ .filter((child) => child.isDirectory() && child.name.startsWith('.'));
59
+
60
+ if (hiddenFolders.length === 1) {
61
+ idePacks.push({
62
+ ideFolder,
63
+ sourcePath: path.join(idePath, hiddenFolders[0].name),
64
+ installAs: hiddenFolders[0].name,
65
+ flags: getFlagsForIde(ideFolder),
66
+ });
67
+ }
68
+ }
69
+
70
+ return idePacks.sort((a, b) => a.ideFolder.localeCompare(b.ideFolder));
71
+ }
72
+
73
+ function listAvailableStacks() {
74
+ if (!isDirectory(STANDARDS_FOLDER)) return [];
75
+
76
+ return fs
77
+ .readdirSync(STANDARDS_FOLDER, { withFileTypes: true })
78
+ .filter((entry) => entry.isDirectory() && !entry.name.startsWith('.'))
79
+ .map((entry) => {
80
+ const stackPath = path.join(STANDARDS_FOLDER, entry.name);
81
+ const sharedReferencePath = path.join(stackPath, 'shared-reference');
82
+ const hasSharedReference = isDirectory(sharedReferencePath);
83
+
84
+ return {
85
+ folderName: entry.name,
86
+ shortName: getStackShortName(entry.name),
87
+ path: stackPath,
88
+ idePacks: findIdePacksInStack(stackPath),
89
+ hasSharedReference,
90
+ sharedReferencePath: hasSharedReference ? sharedReferencePath : null,
91
+ };
92
+ })
93
+ .sort((a, b) => a.shortName.localeCompare(b.shortName));
94
+ }
95
+
96
+ function findStackByName(name) {
97
+ const normalized = name.trim().toLowerCase();
98
+ return (
99
+ listAvailableStacks().find(
100
+ (stack) =>
101
+ stack.shortName.toLowerCase() === normalized ||
102
+ stack.folderName.toLowerCase() === normalized
103
+ ) || null
104
+ );
105
+ }
106
+
107
+ module.exports = {
108
+ PACKAGE_ROOT,
109
+ STANDARDS_FOLDER,
110
+ listAvailableStacks,
111
+ findIdePacksInStack,
112
+ findStackByName,
113
+ };
@@ -0,0 +1,57 @@
1
+ // Maps each IDE folder under a stack to CLI flags and where files land in the project.
2
+ const IDE_CONFIG = {
3
+ cursor: {
4
+ folder: 'cursor',
5
+ sourceFolder: '.cursor',
6
+ installAs: '.cursor',
7
+ flags: ['cursor'],
8
+ },
9
+ 'claude-code': {
10
+ folder: 'claude-code',
11
+ sourceFolder: '.claude',
12
+ installAs: '.claude',
13
+ flags: ['claude', 'claude-code'],
14
+ },
15
+ antigravity: {
16
+ folder: 'antigravity',
17
+ sourceFolder: '.agents',
18
+ installAs: '.agents',
19
+ flags: ['antigravity'],
20
+ },
21
+ };
22
+
23
+ // "rails-skills" → "rails"
24
+ function getStackShortName(folderName) {
25
+ return folderName.endsWith('-skills')
26
+ ? folderName.slice(0, -'-skills'.length)
27
+ : folderName;
28
+ }
29
+
30
+ // "--claude" → "claude-code"; unknown flags map 1:1 to a folder name
31
+ function getIdeFolderFromFlag(flag) {
32
+ for (const ide of Object.values(IDE_CONFIG)) {
33
+ if (ide.flags.includes(flag)) return ide.folder;
34
+ }
35
+ return flag || null;
36
+ }
37
+
38
+ function getFlagsForIde(ideFolder) {
39
+ const known = IDE_CONFIG[ideFolder];
40
+ return known ? known.flags : [ideFolder];
41
+ }
42
+
43
+ function getInstallPathsForIde(ideFolder) {
44
+ const known = IDE_CONFIG[ideFolder];
45
+ if (known) {
46
+ return { sourceFolder: known.sourceFolder, installAs: known.installAs };
47
+ }
48
+ return { sourceFolder: `.${ideFolder}`, installAs: `.${ideFolder}` };
49
+ }
50
+
51
+ module.exports = {
52
+ IDE_CONFIG,
53
+ getStackShortName,
54
+ getIdeFolderFromFlag,
55
+ getFlagsForIde,
56
+ getInstallPathsForIde,
57
+ };