ai-ide-config 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -1,117 +1,117 @@
1
- # ai-ide-config
2
-
3
- Scaffold shared Cursor IDE / agent setup into a project: shared `.cursor` rules/commands, plus stack-specific `AGENTS.md` and stack rules when needed.
4
-
5
- ## Install / run
6
-
7
- No global install required:
8
-
9
- ```bash
10
- npx ai-ide-config init
11
- ```
12
-
13
- From a local checkout:
14
-
15
- ```bash
16
- cd ai-ide-config
17
- npm link
18
- cd /path/to/your-project
19
- npx ai-ide-config init
20
- ```
21
-
22
- ## Usage
23
-
24
- ```bash
25
- # Interactive: pick a stack
26
- npx ai-ide-config init
27
-
28
- # Non-interactive
29
- npx ai-ide-config init --stack angular
30
- npx ai-ide-config init-angular
31
-
32
- # Options
33
- npx ai-ide-config init --force # overwrite existing files
34
- npx ai-ide-config init --dry-run # preview only
35
- npx ai-ide-config init --skip-skills # skip angular/skills install
36
- npx ai-ide-config init ./apps/web # target directory
37
- ```
38
-
39
- Existing template files are **skipped** unless you pass `--force`.
40
-
41
- `.gitignore` is handled specially:
42
-
43
- - If missing → create it with `.cursor/` and `.agents/`
44
- - If present → append `.cursor/` and/or `.agents/` only when missing
45
-
46
- If `package.json` exists, init pins an **exact** `packageManager` / `devEngines.packageManager` to the installed pnpm version. That avoids Corepack failing on ranges like `^11.13.0` from `pnpm init`.
47
-
48
- After scaffolding, the CLI runs:
49
-
50
- ```bash
51
- pnpx skills add https://github.com/angular/skills
52
- ```
53
-
54
- (`pnpx` is used instead of `npx` because the skills package requires pnpm via `devEngines`.)
55
-
56
- Use `--skip-skills` to skip that step. On `--dry-run`, the command is only printed.
57
-
58
- In CI or non-TTY shells, pass `--stack` (or use `init-<stack>`). Interactive prompts require a terminal.
59
-
60
- ## What gets written
61
-
62
- | Path | Source |
63
- |------|--------|
64
- | `.cursor/rules/conventional-commits.mdc` | shared |
65
- | `.cursor/commands/generate-pr-description.md` | shared |
66
- | `.cursor/rules/angular-20.mdc` | angular ([angular.dev](https://angular.dev/assets/context/angular-20.mdc)) |
67
- | `AGENTS.md` | angular |
68
- | `pnpm-workspace.yaml` | angular (`blockExoticSubdeps`, `minimumReleaseAge: 4320`) |
69
- | `.gitignore` | create or append `.cursor/` and `.agents/` |
70
-
71
- After init, edit `AGENTS.md` placeholders (`<PROJECT_NAME>`, package manager, domains, paths) for the target repo.
72
-
73
- ## Stacks
74
-
75
- | Id | Label |
76
- |----|-------|
77
- | `angular` | Angular |
78
-
79
- ### Adding a stack
80
-
81
- 1. Add `templates/<stack>/AGENTS.md`
82
- 2. Register it in [`src/stacks.mjs`](src/stacks.mjs)
83
- 3. Document it here
84
-
85
- Shared Cursor rules/commands stay under `templates/shared/`.
86
-
87
- ## Publishing to npm
88
-
89
- CD publishes to npm when you create a **GitHub Release** (workflow: [`.github/workflows/publish.yml`](.github/workflows/publish.yml)).
90
-
91
- ### One-time setup
92
-
93
- 1. Create an [npmjs.com](https://www.npmjs.com) account and verify your email.
94
- 2. Create the package on npm (first publish can also create it), or claim the name `ai-ide-config`.
95
- 3. In the package settings on npm → **Trusted Publisher**:
96
- - **Organization or user:** `iraldoad`
97
- - **Repository:** `ai-ide-config`
98
- - **Workflow filename:** `publish.yml`
99
- - Allow **npm publish**
100
- 4. No `NPM_TOKEN` secret is required (OIDC Trusted Publishing).
101
-
102
- ### Release a version
103
-
104
- 1. Bump `version` in `package.json` (e.g. `0.1.1`).
105
- 2. Commit and push.
106
- 3. Create a GitHub Release for that commit (e.g. tag `v0.1.1`).
107
- 4. The workflow runs `npm publish --access public --provenance`.
108
-
109
- After the first successful publish:
110
-
111
- ```bash
112
- npx ai-ide-config init
113
- ```
114
-
115
- ## License
116
-
117
- MIT
1
+ # ai-ide-config
2
+
3
+ Scaffold shared Cursor IDE / agent setup into a project: shared `.cursor` rules/commands, plus stack-specific `AGENTS.md` and stack rules when needed.
4
+
5
+ ## Install / run
6
+
7
+ No global install required:
8
+
9
+ ```bash
10
+ npx ai-ide-config init
11
+ ```
12
+
13
+ From a local checkout:
14
+
15
+ ```bash
16
+ cd ai-ide-config
17
+ npm link
18
+ cd /path/to/your-project
19
+ npx ai-ide-config init
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```bash
25
+ # Interactive: pick a stack
26
+ npx ai-ide-config init
27
+
28
+ # Non-interactive
29
+ npx ai-ide-config init --stack angular
30
+ npx ai-ide-config init-angular
31
+
32
+ # Options
33
+ npx ai-ide-config init --force # overwrite existing files
34
+ npx ai-ide-config init --dry-run # preview only
35
+ npx ai-ide-config init --skip-skills # skip midudev/autoskills install
36
+ npx ai-ide-config init ./apps/web # target directory
37
+ ```
38
+
39
+ Existing template files are **skipped** unless you pass `--force`.
40
+
41
+ `.gitignore` is handled specially:
42
+
43
+ - If missing → create it with `.cursor/` and `.agents/`
44
+ - If present → append `.cursor/` and/or `.agents/` only when missing
45
+
46
+ If `package.json` exists, init pins an **exact** `packageManager` / `devEngines.packageManager` to the installed pnpm version. That avoids Corepack failing on ranges like `^11.13.0` from `pnpm init`.
47
+
48
+ After scaffolding, the CLI runs:
49
+
50
+ ```bash
51
+ pnpx skills add midudev/autoskills
52
+ ```
53
+
54
+ (`pnpx` is used instead of `npx` because the skills package requires pnpm via `devEngines`.)
55
+
56
+ Use `--skip-skills` to skip that step. On `--dry-run`, the command is only printed.
57
+
58
+ In CI or non-TTY shells, pass `--stack` (or use `init-<stack>`). Interactive prompts require a terminal.
59
+
60
+ ## What gets written
61
+
62
+ | Path | Source |
63
+ |------|--------|
64
+ | `.cursor/rules/conventional-commits.mdc` | shared |
65
+ | `.cursor/commands/generate-pr-description.md` | shared |
66
+ | `.cursor/rules/angular-20.mdc` | angular ([angular.dev](https://angular.dev/assets/context/angular-20.mdc)) |
67
+ | `AGENTS.md` | angular |
68
+ | `pnpm-workspace.yaml` | angular (`blockExoticSubdeps`, `minimumReleaseAge: 4320`) |
69
+ | `.gitignore` | create or append `.cursor/` and `.agents/` |
70
+
71
+ After init, edit `AGENTS.md` placeholders (`<PROJECT_NAME>`, package manager, domains, paths) for the target repo.
72
+
73
+ ## Stacks
74
+
75
+ | Id | Label |
76
+ |----|-------|
77
+ | `angular` | Angular |
78
+
79
+ ### Adding a stack
80
+
81
+ 1. Add `templates/<stack>/AGENTS.md`
82
+ 2. Register it in [`src/stacks.mjs`](src/stacks.mjs)
83
+ 3. Document it here
84
+
85
+ Shared Cursor rules/commands stay under `templates/shared/`.
86
+
87
+ ## Publishing to npm
88
+
89
+ CD publishes to npm when you create a **GitHub Release** (workflow: [`.github/workflows/publish.yml`](.github/workflows/publish.yml)).
90
+
91
+ ### One-time setup
92
+
93
+ 1. Create an [npmjs.com](https://www.npmjs.com) account and verify your email.
94
+ 2. Create the package on npm (first publish can also create it), or claim the name `ai-ide-config`.
95
+ 3. In the package settings on npm → **Trusted Publisher**:
96
+ - **Organization or user:** `iraldoad`
97
+ - **Repository:** `ai-ide-config`
98
+ - **Workflow filename:** `publish.yml`
99
+ - Allow **npm publish**
100
+ 4. No `NPM_TOKEN` secret is required (OIDC Trusted Publishing).
101
+
102
+ ### Release a version
103
+
104
+ 1. Bump `version` in `package.json` (e.g. `0.1.1`).
105
+ 2. Commit and push.
106
+ 3. Create a GitHub Release for that commit (e.g. tag `v0.1.1`).
107
+ 4. The workflow runs `npm publish --access public --provenance`.
108
+
109
+ After the first successful publish:
110
+
111
+ ```bash
112
+ npx ai-ide-config init
113
+ ```
114
+
115
+ ## License
116
+
117
+ MIT
package/bin/cli.mjs CHANGED
@@ -1,186 +1,186 @@
1
- #!/usr/bin/env node
2
-
3
- import path from 'node:path';
4
- import { getStack, listStacks, stackIds } from '../src/stacks.mjs';
5
- import { promptForStack } from '../src/prompt.mjs';
6
- import { initStack, printReport } from '../src/init.mjs';
7
- import { runSkillsAdd, SKILLS_ADD_COMMAND } from '../src/skills.mjs';
8
-
9
- function printUsage() {
10
- const stacks = listStacks()
11
- .map((s) => ` init-${s.id}`.padEnd(18) + `# shortcut for init --stack ${s.id}`)
12
- .join('\n');
13
-
14
- console.log(`Usage:
15
- ai-ide-config init [dir] [--stack <name>] [--force] [--dry-run] [--skip-skills]
16
- ai-ide-config init-<stack> [dir] [--force] [--dry-run] [--skip-skills]
17
-
18
- Options:
19
- --stack <name> Skip interactive prompt (e.g. angular)
20
- --force Overwrite existing files
21
- --dry-run Show what would be written
22
- --skip-skills Do not run: ${SKILLS_ADD_COMMAND}
23
-
24
- Stacks:
25
- ${listStacks()
26
- .map((s) => ` ${s.id.padEnd(12)} ${s.label}`)
27
- .join('\n')}
28
-
29
- Shortcuts:
30
- ${stacks}
31
- `);
32
- }
33
-
34
- /**
35
- * @param {string[]} argv
36
- */
37
- function parseArgs(argv) {
38
- const args = [...argv];
39
- /** @type {{ command: string | null, targetDir: string, stackId: string | null, force: boolean, dryRun: boolean, skipSkills: boolean, help: boolean }} */
40
- const result = {
41
- command: null,
42
- targetDir: process.cwd(),
43
- stackId: null,
44
- force: false,
45
- dryRun: false,
46
- skipSkills: false,
47
- help: false,
48
- };
49
-
50
- const positionals = [];
51
-
52
- while (args.length > 0) {
53
- const token = args.shift();
54
-
55
- if (token === '--help' || token === '-h') {
56
- result.help = true;
57
- continue;
58
- }
59
- if (token === '--force') {
60
- result.force = true;
61
- continue;
62
- }
63
- if (token === '--dry-run') {
64
- result.dryRun = true;
65
- continue;
66
- }
67
- if (token === '--skip-skills') {
68
- result.skipSkills = true;
69
- continue;
70
- }
71
- if (token === '--stack') {
72
- const value = args.shift();
73
- if (!value) {
74
- throw new Error('--stack requires a value');
75
- }
76
- result.stackId = value;
77
- continue;
78
- }
79
- if (token.startsWith('-')) {
80
- throw new Error(`Unknown option: ${token}`);
81
- }
82
- positionals.push(token);
83
- }
84
-
85
- result.command = positionals[0] ?? null;
86
- if (positionals[1]) {
87
- result.targetDir = path.resolve(positionals[1]);
88
- }
89
-
90
- return result;
91
- }
92
-
93
- /**
94
- * Resolve stack id from command name like init-angular.
95
- * @param {string} command
96
- * @returns {string | null}
97
- */
98
- function stackFromInitAlias(command) {
99
- const match = /^init-(.+)$/.exec(command);
100
- if (!match) return null;
101
- return match[1];
102
- }
103
-
104
- async function main() {
105
- let parsed;
106
- try {
107
- parsed = parseArgs(process.argv.slice(2));
108
- } catch (err) {
109
- console.error(err.message);
110
- printUsage();
111
- process.exitCode = 1;
112
- return;
113
- }
114
-
115
- if (parsed.help || !parsed.command) {
116
- printUsage();
117
- process.exitCode = parsed.help ? 0 : 1;
118
- return;
119
- }
120
-
121
- let stackId = parsed.stackId;
122
-
123
- if (parsed.command === 'init') {
124
- // stackId may already be set via --stack
125
- } else {
126
- const aliasStack = stackFromInitAlias(parsed.command);
127
- if (aliasStack) {
128
- if (stackId && stackId !== aliasStack) {
129
- console.error(
130
- `Conflicting stacks: command is init-${aliasStack} but --stack ${stackId} was passed.`,
131
- );
132
- process.exitCode = 1;
133
- return;
134
- }
135
- stackId = aliasStack;
136
- } else {
137
- console.error(`Unknown command: ${parsed.command}`);
138
- printUsage();
139
- process.exitCode = 1;
140
- return;
141
- }
142
- }
143
-
144
- if (!stackId) {
145
- try {
146
- stackId = await promptForStack();
147
- } catch (err) {
148
- console.error(err.message);
149
- process.exitCode = 1;
150
- return;
151
- }
152
- }
153
-
154
- const stack = getStack(stackId);
155
- if (!stack) {
156
- console.error(
157
- `Unknown stack "${stackId}". Available: ${stackIds().join(', ')}`,
158
- );
159
- process.exitCode = 1;
160
- return;
161
- }
162
-
163
- try {
164
- const report = initStack({
165
- stack,
166
- targetDir: parsed.targetDir,
167
- force: parsed.force,
168
- dryRun: parsed.dryRun,
169
- });
170
-
171
- console.log(
172
- `${parsed.dryRun ? '[dry-run] ' : ''}Scaffolding ${stack.label} AI IDE config into ${parsed.targetDir}`,
173
- );
174
- printReport(report, { dryRun: parsed.dryRun });
175
-
176
- runSkillsAdd(parsed.targetDir, {
177
- dryRun: parsed.dryRun,
178
- skip: parsed.skipSkills,
179
- });
180
- } catch (err) {
181
- console.error(err.message);
182
- process.exitCode = 1;
183
- }
184
- }
185
-
186
- main();
1
+ #!/usr/bin/env node
2
+
3
+ import path from 'node:path';
4
+ import { getStack, listStacks, stackIds } from '../src/stacks.mjs';
5
+ import { promptForStack } from '../src/prompt.mjs';
6
+ import { initStack, printReport } from '../src/init.mjs';
7
+ import { runSkillsAdd, SKILLS_ADD_COMMAND } from '../src/skills.mjs';
8
+
9
+ function printUsage() {
10
+ const stacks = listStacks()
11
+ .map((s) => ` init-${s.id}`.padEnd(18) + `# shortcut for init --stack ${s.id}`)
12
+ .join('\n');
13
+
14
+ console.log(`Usage:
15
+ ai-ide-config init [dir] [--stack <name>] [--force] [--dry-run] [--skip-skills]
16
+ ai-ide-config init-<stack> [dir] [--force] [--dry-run] [--skip-skills]
17
+
18
+ Options:
19
+ --stack <name> Skip interactive prompt (e.g. angular)
20
+ --force Overwrite existing files
21
+ --dry-run Show what would be written
22
+ --skip-skills Do not run: ${SKILLS_ADD_COMMAND}
23
+
24
+ Stacks:
25
+ ${listStacks()
26
+ .map((s) => ` ${s.id.padEnd(12)} ${s.label}`)
27
+ .join('\n')}
28
+
29
+ Shortcuts:
30
+ ${stacks}
31
+ `);
32
+ }
33
+
34
+ /**
35
+ * @param {string[]} argv
36
+ */
37
+ function parseArgs(argv) {
38
+ const args = [...argv];
39
+ /** @type {{ command: string | null, targetDir: string, stackId: string | null, force: boolean, dryRun: boolean, skipSkills: boolean, help: boolean }} */
40
+ const result = {
41
+ command: null,
42
+ targetDir: process.cwd(),
43
+ stackId: null,
44
+ force: false,
45
+ dryRun: false,
46
+ skipSkills: false,
47
+ help: false,
48
+ };
49
+
50
+ const positionals = [];
51
+
52
+ while (args.length > 0) {
53
+ const token = args.shift();
54
+
55
+ if (token === '--help' || token === '-h') {
56
+ result.help = true;
57
+ continue;
58
+ }
59
+ if (token === '--force') {
60
+ result.force = true;
61
+ continue;
62
+ }
63
+ if (token === '--dry-run') {
64
+ result.dryRun = true;
65
+ continue;
66
+ }
67
+ if (token === '--skip-skills') {
68
+ result.skipSkills = true;
69
+ continue;
70
+ }
71
+ if (token === '--stack') {
72
+ const value = args.shift();
73
+ if (!value) {
74
+ throw new Error('--stack requires a value');
75
+ }
76
+ result.stackId = value;
77
+ continue;
78
+ }
79
+ if (token.startsWith('-')) {
80
+ throw new Error(`Unknown option: ${token}`);
81
+ }
82
+ positionals.push(token);
83
+ }
84
+
85
+ result.command = positionals[0] ?? null;
86
+ if (positionals[1]) {
87
+ result.targetDir = path.resolve(positionals[1]);
88
+ }
89
+
90
+ return result;
91
+ }
92
+
93
+ /**
94
+ * Resolve stack id from command name like init-angular.
95
+ * @param {string} command
96
+ * @returns {string | null}
97
+ */
98
+ function stackFromInitAlias(command) {
99
+ const match = /^init-(.+)$/.exec(command);
100
+ if (!match) return null;
101
+ return match[1];
102
+ }
103
+
104
+ async function main() {
105
+ let parsed;
106
+ try {
107
+ parsed = parseArgs(process.argv.slice(2));
108
+ } catch (err) {
109
+ console.error(err.message);
110
+ printUsage();
111
+ process.exitCode = 1;
112
+ return;
113
+ }
114
+
115
+ if (parsed.help || !parsed.command) {
116
+ printUsage();
117
+ process.exitCode = parsed.help ? 0 : 1;
118
+ return;
119
+ }
120
+
121
+ let stackId = parsed.stackId;
122
+
123
+ if (parsed.command === 'init') {
124
+ // stackId may already be set via --stack
125
+ } else {
126
+ const aliasStack = stackFromInitAlias(parsed.command);
127
+ if (aliasStack) {
128
+ if (stackId && stackId !== aliasStack) {
129
+ console.error(
130
+ `Conflicting stacks: command is init-${aliasStack} but --stack ${stackId} was passed.`,
131
+ );
132
+ process.exitCode = 1;
133
+ return;
134
+ }
135
+ stackId = aliasStack;
136
+ } else {
137
+ console.error(`Unknown command: ${parsed.command}`);
138
+ printUsage();
139
+ process.exitCode = 1;
140
+ return;
141
+ }
142
+ }
143
+
144
+ if (!stackId) {
145
+ try {
146
+ stackId = await promptForStack();
147
+ } catch (err) {
148
+ console.error(err.message);
149
+ process.exitCode = 1;
150
+ return;
151
+ }
152
+ }
153
+
154
+ const stack = getStack(stackId);
155
+ if (!stack) {
156
+ console.error(
157
+ `Unknown stack "${stackId}". Available: ${stackIds().join(', ')}`,
158
+ );
159
+ process.exitCode = 1;
160
+ return;
161
+ }
162
+
163
+ try {
164
+ const report = initStack({
165
+ stack,
166
+ targetDir: parsed.targetDir,
167
+ force: parsed.force,
168
+ dryRun: parsed.dryRun,
169
+ });
170
+
171
+ console.log(
172
+ `${parsed.dryRun ? '[dry-run] ' : ''}Scaffolding ${stack.label} AI IDE config into ${parsed.targetDir}`,
173
+ );
174
+ printReport(report, { dryRun: parsed.dryRun });
175
+
176
+ runSkillsAdd(parsed.targetDir, {
177
+ dryRun: parsed.dryRun,
178
+ skip: parsed.skipSkills,
179
+ });
180
+ } catch (err) {
181
+ console.error(err.message);
182
+ process.exitCode = 1;
183
+ }
184
+ }
185
+
186
+ main();
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "ai-ide-config",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Scaffold shared Cursor IDE / agent config (rules, commands, stack AGENTS.md)",
5
5
  "type": "module",
6
6
  "bin": {
7
- "ai-ide-config": "./bin/cli.mjs"
7
+ "ai-ide-config": "bin/cli.mjs"
8
8
  },
9
9
  "files": [
10
10
  "bin",
@@ -31,4 +31,4 @@
31
31
  "angular"
32
32
  ],
33
33
  "license": "MIT"
34
- }
34
+ }