@bonesofspring/ai-rules 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js ADDED
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @bonesofspring/ai-rules CLI
4
+ */
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
8
+ const packageRoot = path.join(__dirname, '..');
9
+
10
+ const PRESETS = {
11
+ cursor: {
12
+ rulesDir: '.cursor/rules',
13
+ commandsDir: '.cursor/commands',
14
+ relBase: ['presets', 'cursor'],
15
+ },
16
+ claude: {
17
+ rulesDir: '.claude/rules',
18
+ commandsDir: '.claude/commands',
19
+ relBase: ['presets', 'claude'],
20
+ },
21
+ };
22
+
23
+ function printHelp() {
24
+ console.log(`@bonesofspring/ai-rules
25
+
26
+ Usage:
27
+ ai-rules init <cursor|claude> --preset <name> Copy preset rules and commands into the current directory
28
+ ai-rules clean <cursor|claude> Remove preset target rules and commands directories
29
+
30
+ Examples:
31
+ npx @bonesofspring/ai-rules init cursor --preset next
32
+ npx @bonesofspring/ai-rules clean claude
33
+ `);
34
+ }
35
+
36
+ function parseArgs(argv) {
37
+ const args = { _: [] };
38
+ for (let i = 0; i < argv.length; i++) {
39
+ const a = argv[i];
40
+ if (a === '--preset') {
41
+ args.preset = argv[++i];
42
+ continue;
43
+ }
44
+ if (a.startsWith('--preset=')) {
45
+ args.preset = a.slice('--preset='.length);
46
+ continue;
47
+ }
48
+ args._.push(a);
49
+ }
50
+ return args;
51
+ }
52
+
53
+ function copyDir(src, dest) {
54
+ if (!fs.existsSync(src)) {
55
+ throw new Error(`Source not found: ${src}`);
56
+ }
57
+ fs.mkdirSync(dest, { recursive: true });
58
+ const entries = fs.readdirSync(src, { withFileTypes: true });
59
+ for (const e of entries) {
60
+ const from = path.join(src, e.name);
61
+ const to = path.join(dest, e.name);
62
+ if (e.isDirectory()) {
63
+ copyDir(from, to);
64
+ } else {
65
+ fs.copyFileSync(from, to);
66
+ }
67
+ }
68
+ }
69
+
70
+ function removeDirIfExists(dir) {
71
+ if (fs.existsSync(dir)) {
72
+ fs.rmSync(dir, { recursive: true, force: true });
73
+ }
74
+ }
75
+
76
+ function cmdInit(tool, preset) {
77
+ const cfg = PRESETS[tool];
78
+ if (!cfg) {
79
+ console.error(`Unknown tool: ${tool}. Use cursor or claude.`);
80
+ process.exit(1);
81
+ }
82
+ if (!preset) {
83
+ console.error('Missing --preset <name>');
84
+ process.exit(1);
85
+ }
86
+ const base = path.join(packageRoot, ...cfg.relBase, preset);
87
+ const rulesSrc = path.join(base, 'rules');
88
+ const commandsSrc = path.join(base, 'commands');
89
+ const cwd = process.cwd();
90
+
91
+ if (!fs.existsSync(rulesSrc) && !fs.existsSync(commandsSrc)) {
92
+ console.error(`Preset "${preset}" for ${tool} not found under ${base}`);
93
+ process.exit(1);
94
+ }
95
+
96
+ if (fs.existsSync(rulesSrc)) {
97
+ copyDir(rulesSrc, path.join(cwd, cfg.rulesDir));
98
+ console.log(`Copied rules → ${cfg.rulesDir}`);
99
+ }
100
+ if (fs.existsSync(commandsSrc)) {
101
+ copyDir(commandsSrc, path.join(cwd, cfg.commandsDir));
102
+ console.log(`Copied commands → ${cfg.commandsDir}`);
103
+ }
104
+ }
105
+
106
+ function cmdClean(tool) {
107
+ const cfg = PRESETS[tool];
108
+ if (!cfg) {
109
+ console.error(`Unknown tool: ${tool}. Use cursor or claude.`);
110
+ process.exit(1);
111
+ }
112
+ const cwd = process.cwd();
113
+ removeDirIfExists(path.join(cwd, cfg.rulesDir));
114
+ removeDirIfExists(path.join(cwd, cfg.commandsDir));
115
+ console.log(`Removed ${cfg.rulesDir} and ${cfg.commandsDir} (if present)`);
116
+ }
117
+
118
+ function main() {
119
+ const argv = process.argv.slice(2);
120
+ if (argv.length === 0 || argv.includes('-h') || argv.includes('--help')) {
121
+ printHelp();
122
+ process.exit(0);
123
+ }
124
+
125
+ const parsed = parseArgs(argv);
126
+ const [command, tool] = parsed._;
127
+
128
+ if (command === 'init') {
129
+ cmdInit(tool, parsed.preset);
130
+ return;
131
+ }
132
+ if (command === 'clean') {
133
+ cmdClean(tool);
134
+ return;
135
+ }
136
+
137
+ printHelp();
138
+ process.exit(1);
139
+ }
140
+
141
+ main();
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@bonesofspring/ai-rules",
3
+ "version": "0.1.0",
4
+ "description": "Presets of Cursor and Claude rules/commands for Revy Ross personal use",
5
+ "license": "MIT",
6
+ "author": "Revy Ross",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/bonesofspring/ai-rules.git"
10
+ },
11
+ "keywords": [
12
+ "cursor",
13
+ "claude",
14
+ "rules",
15
+ "ai",
16
+ "bonesofspring"
17
+ ],
18
+ "bin": {
19
+ "ai-rules": "./bin/cli.js"
20
+ },
21
+ "files": [
22
+ "bin",
23
+ "presets"
24
+ ],
25
+ "engines": {
26
+ "node": ">=18"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ }
31
+ }
@@ -0,0 +1,3 @@
1
+ # Claude commands (next preset)
2
+
3
+ Add slash command definitions for this preset. They are copied to `.claude/commands` when you run `ai-rules init claude --preset next`.
@@ -0,0 +1,3 @@
1
+ # Claude rules (next preset)
2
+
3
+ Add markdown instruction files for this preset. They are copied to `.claude/rules` when you run `ai-rules init claude --preset next`.
@@ -0,0 +1,3 @@
1
+ # Cursor commands (next preset)
2
+
3
+ Place command definitions for this preset here. They are copied to `.cursor/commands` when you run `ai-rules init cursor --preset next`.
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Next.js stack conventions (placeholder — extend this preset)
3
+ globs: **/*.{ts,tsx}
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Next.js preset
8
+
9
+ This file is a placeholder for the **next** Cursor preset. Replace with your project rules.