dev-rules 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.
package/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # dev-rules CLI
2
+
3
+ CLI tool to automate "Senior Architect" setup for new and existing projects.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # Use directly with npx (no installation required)
9
+ npx dev-rules init my-app
10
+
11
+ # Or install globally
12
+ npm install -g dev-rules
13
+ ```
14
+
15
+ ## Commands
16
+
17
+ ### `dev-rules init <name>`
18
+
19
+ Scaffold a new project with the latest standards.
20
+
21
+ ```bash
22
+ dev-rules init my-app
23
+ dev-rules init my-app --template ts # TypeScript (default)
24
+ dev-rules init my-app --template python # Python
25
+ ```
26
+
27
+ **What it does:**
28
+ - Creates project directory with standard structure
29
+ - Generates `AGENTS.md` with strict development rules
30
+ - Installs relevant rule files to `.cursor/rules/`
31
+ - Sets up basic project files (package.json/pyproject.toml, tsconfig, etc.)
32
+
33
+ ### `dev-rules inject`
34
+
35
+ Add standards to an existing project (current directory).
36
+
37
+ ```bash
38
+ cd my-existing-project
39
+ dev-rules inject
40
+ dev-rules inject --force # Overwrite existing files
41
+ ```
42
+
43
+ **What it does:**
44
+ - Detects project type (TypeScript, Python, Rust)
45
+ - Generates customized `AGENTS.md`
46
+ - Installs relevant rule files to `.cursor/rules/`
47
+
48
+ ### `dev-rules update`
49
+
50
+ Check and update outdated rules from the source.
51
+
52
+ ```bash
53
+ dev-rules update
54
+ ```
55
+
56
+ **What it does:**
57
+ - Compares local `.cursor/rules/` files with source
58
+ - Shows which files are outdated
59
+ - Prompts user to select files to update
60
+ - Fetches and overwrites selected files
61
+
62
+ ## Source of Truth
63
+
64
+ The CLI automatically determines where to get rules from:
65
+
66
+ 1. **Local**: If running from within the `dev-handbook` repo, uses local files
67
+ 2. **Remote**: Otherwise, fetches from GitHub
68
+
69
+ ## Development
70
+
71
+ ```bash
72
+ cd cli
73
+ npm install
74
+ npm run build
75
+ npm run dev -- init test-app
76
+ ```
@@ -0,0 +1,6 @@
1
+ interface InitOptions {
2
+ template: string;
3
+ }
4
+ export declare function initCommand(name: string, options: InitOptions): Promise<void>;
5
+ export {};
6
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAUA,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCnF"}
@@ -0,0 +1,197 @@
1
+ import chalk from "chalk";
2
+ import prompts from "prompts";
3
+ import { existsSync } from "fs";
4
+ import { join, resolve } from "path";
5
+ import { getRulesSource } from "../utils/paths.js";
6
+ import { ensureDir, writeFile, copyFile, fetchRemoteFile } from "../utils/file-ops.js";
7
+ import { generateAgentsMd } from "../utils/agents-generator.js";
8
+ import { getRelevantRules } from "../utils/stack-detector.js";
9
+ export async function initCommand(name, options) {
10
+ const targetDir = resolve(process.cwd(), name);
11
+ if (existsSync(targetDir)) {
12
+ const response = await prompts({
13
+ type: "confirm",
14
+ name: "proceed",
15
+ message: `Directory "${name}" already exists. Continue anyway?`,
16
+ initial: false,
17
+ });
18
+ if (!response.proceed) {
19
+ console.log(chalk.red("Aborted."));
20
+ process.exit(1);
21
+ }
22
+ }
23
+ console.log(chalk.blue(`\nInitializing project: ${name}`));
24
+ console.log(chalk.blue(`Template: ${options.template}`));
25
+ ensureDir(targetDir);
26
+ const stack = buildStackFromTemplate(options.template);
27
+ await scaffoldProject(targetDir, name, stack, options.template);
28
+ console.log(chalk.green("\nProject initialized successfully!"));
29
+ console.log(chalk.blue("\nNext steps:"));
30
+ console.log(` cd ${name}`);
31
+ if (options.template === "ts") {
32
+ console.log(" npm install");
33
+ }
34
+ else if (options.template === "python") {
35
+ console.log(" pip install -r requirements.txt");
36
+ }
37
+ console.log(" # Start coding with AI assistance!");
38
+ }
39
+ function buildStackFromTemplate(template) {
40
+ switch (template) {
41
+ case "ts":
42
+ case "typescript":
43
+ return { primary: "typescript", hasReact: false, hasDatabase: false };
44
+ case "ts-react":
45
+ case "react":
46
+ return { primary: "typescript", hasReact: true, hasDatabase: false };
47
+ case "python":
48
+ case "py":
49
+ return { primary: "python", hasReact: false, hasDatabase: false };
50
+ case "rust":
51
+ case "rs":
52
+ return { primary: "rust", hasReact: false, hasDatabase: false };
53
+ default:
54
+ return { primary: "typescript", hasReact: false, hasDatabase: false };
55
+ }
56
+ }
57
+ async function scaffoldProject(targetDir, projectName, stack, template) {
58
+ const rulesDir = join(targetDir, ".cursor", "rules");
59
+ ensureDir(rulesDir);
60
+ const agentsMd = generateAgentsMd(stack, ".cursor/rules");
61
+ writeFile(join(targetDir, "AGENTS.md"), agentsMd);
62
+ console.log(chalk.green("Created AGENTS.md"));
63
+ await installRulesForInit(rulesDir, stack);
64
+ if (template === "ts" || template === "typescript") {
65
+ await scaffoldTypeScriptProject(targetDir, projectName);
66
+ }
67
+ else if (template === "python" || template === "py") {
68
+ await scaffoldPythonProject(targetDir, projectName);
69
+ }
70
+ const readmeContent = `# ${projectName}
71
+
72
+ > This project follows the Senior Architect development standards.
73
+
74
+ ## Getting Started
75
+
76
+ See \`AGENTS.md\` for development guidelines and rules.
77
+
78
+ ## Structure
79
+
80
+ - \`.cursor/rules/\` - Coding standards and rules for AI assistance
81
+ - \`AGENTS.md\` - Main configuration for AI development
82
+ `;
83
+ writeFile(join(targetDir, "README.md"), readmeContent);
84
+ console.log(chalk.green("Created README.md"));
85
+ const gitignoreContent = `node_modules/
86
+ dist/
87
+ .env
88
+ .env.local
89
+ *.log
90
+ .DS_Store
91
+ __pycache__/
92
+ *.pyc
93
+ .venv/
94
+ `;
95
+ writeFile(join(targetDir, ".gitignore"), gitignoreContent);
96
+ console.log(chalk.green("Created .gitignore"));
97
+ }
98
+ async function installRulesForInit(rulesDir, stack) {
99
+ const source = getRulesSource();
100
+ const relevantRules = getRelevantRules(stack);
101
+ console.log(chalk.blue(`Installing ${relevantRules.length} rule files...`));
102
+ for (const rule of relevantRules) {
103
+ const destPath = join(rulesDir, rule);
104
+ try {
105
+ if (source.type === "local") {
106
+ const srcPath = join(source.path, "rules", rule);
107
+ if (existsSync(srcPath)) {
108
+ copyFile(srcPath, destPath);
109
+ console.log(chalk.green(` Installed ${rule}`));
110
+ }
111
+ }
112
+ else {
113
+ const content = await fetchRemoteFile(`${source.path}/rules/${rule}`);
114
+ writeFile(destPath, content);
115
+ console.log(chalk.green(` Fetched ${rule}`));
116
+ }
117
+ }
118
+ catch (error) {
119
+ console.log(chalk.yellow(` Could not install ${rule}`));
120
+ }
121
+ }
122
+ }
123
+ async function scaffoldTypeScriptProject(targetDir, projectName) {
124
+ const packageJson = {
125
+ name: projectName,
126
+ version: "1.0.0",
127
+ description: "",
128
+ main: "dist/index.js",
129
+ scripts: {
130
+ build: "tsc",
131
+ dev: "ts-node src/index.ts",
132
+ start: "node dist/index.js",
133
+ test: "vitest",
134
+ lint: "eslint src/",
135
+ typecheck: "tsc --noEmit",
136
+ },
137
+ devDependencies: {
138
+ "@types/node": "^20.14.0",
139
+ "ts-node": "^10.9.2",
140
+ typescript: "^5.4.5",
141
+ vitest: "^1.6.0",
142
+ eslint: "^9.0.0",
143
+ },
144
+ };
145
+ writeFile(join(targetDir, "package.json"), JSON.stringify(packageJson, null, 2));
146
+ console.log(chalk.green("Created package.json"));
147
+ const tsconfig = {
148
+ compilerOptions: {
149
+ target: "ES2022",
150
+ module: "NodeNext",
151
+ moduleResolution: "NodeNext",
152
+ lib: ["ES2022"],
153
+ outDir: "./dist",
154
+ rootDir: "./src",
155
+ strict: true,
156
+ esModuleInterop: true,
157
+ skipLibCheck: true,
158
+ forceConsistentCasingInFileNames: true,
159
+ },
160
+ include: ["src/**/*"],
161
+ exclude: ["node_modules", "dist"],
162
+ };
163
+ writeFile(join(targetDir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
164
+ console.log(chalk.green("Created tsconfig.json"));
165
+ ensureDir(join(targetDir, "src"));
166
+ writeFile(join(targetDir, "src", "index.ts"), `console.log("Hello, ${projectName}!");\n`);
167
+ console.log(chalk.green("Created src/index.ts"));
168
+ }
169
+ async function scaffoldPythonProject(targetDir, projectName) {
170
+ const pyprojectToml = `[build-system]
171
+ requires = ["setuptools>=61.0"]
172
+ build-backend = "setuptools.build_meta"
173
+
174
+ [project]
175
+ name = "${projectName}"
176
+ version = "1.0.0"
177
+ description = ""
178
+ readme = "README.md"
179
+ requires-python = ">=3.11"
180
+ dependencies = []
181
+
182
+ [project.optional-dependencies]
183
+ dev = [
184
+ "pytest>=8.0.0",
185
+ "ruff>=0.4.0",
186
+ "mypy>=1.10.0",
187
+ ]
188
+ `;
189
+ writeFile(join(targetDir, "pyproject.toml"), pyprojectToml);
190
+ console.log(chalk.green("Created pyproject.toml"));
191
+ const srcDir = join(targetDir, "src", projectName.replace(/-/g, "_"));
192
+ ensureDir(srcDir);
193
+ writeFile(join(srcDir, "__init__.py"), "");
194
+ writeFile(join(srcDir, "main.py"), `def main() -> None:\n print("Hello, ${projectName}!")\n\n\nif __name__ == "__main__":\n main()\n`);
195
+ console.log(chalk.green("Created src module"));
196
+ }
197
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ interface InjectOptions {
2
+ force: boolean;
3
+ }
4
+ export declare function injectCommand(options: InjectOptions): Promise<void>;
5
+ export {};
6
+ //# sourceMappingURL=inject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject.d.ts","sourceRoot":"","sources":["../../src/commands/inject.ts"],"names":[],"mappings":"AASA,UAAU,aAAa;IACrB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDzE"}
@@ -0,0 +1,95 @@
1
+ import chalk from "chalk";
2
+ import prompts from "prompts";
3
+ import { existsSync } from "fs";
4
+ import { join } from "path";
5
+ import { detectStack, getRelevantRules } from "../utils/stack-detector.js";
6
+ import { getRulesSource } from "../utils/paths.js";
7
+ import { ensureDir, writeFile, copyFile, fetchRemoteFile } from "../utils/file-ops.js";
8
+ import { generateAgentsMd } from "../utils/agents-generator.js";
9
+ export async function injectCommand(options) {
10
+ const targetDir = process.cwd();
11
+ console.log(chalk.blue("Analyzing project..."));
12
+ const stack = detectStack(targetDir);
13
+ if (stack.primary === "unknown") {
14
+ console.log(chalk.yellow("Could not detect project type. No package.json, pyproject.toml, or Cargo.toml found."));
15
+ const response = await prompts({
16
+ type: "select",
17
+ name: "stack",
18
+ message: "What type of project is this?",
19
+ choices: [
20
+ { title: "TypeScript/Node.js", value: "typescript" },
21
+ { title: "Python", value: "python" },
22
+ { title: "Rust", value: "rust" },
23
+ ],
24
+ });
25
+ if (!response.stack) {
26
+ console.log(chalk.red("Aborted."));
27
+ process.exit(1);
28
+ }
29
+ stack.primary = response.stack;
30
+ }
31
+ console.log(chalk.green(`Detected stack: ${stack.primary}${stack.hasReact ? " + React" : ""}${stack.hasDatabase ? " + Database" : ""}`));
32
+ const agentsPath = join(targetDir, "AGENTS.md");
33
+ const rulesDir = join(targetDir, ".cursor", "rules");
34
+ if (existsSync(agentsPath) && !options.force) {
35
+ const response = await prompts({
36
+ type: "confirm",
37
+ name: "overwrite",
38
+ message: "AGENTS.md already exists. Overwrite?",
39
+ initial: false,
40
+ });
41
+ if (!response.overwrite) {
42
+ console.log(chalk.yellow("Skipping AGENTS.md"));
43
+ }
44
+ else {
45
+ await installAgentsMd(targetDir, stack, rulesDir);
46
+ }
47
+ }
48
+ else {
49
+ await installAgentsMd(targetDir, stack, rulesDir);
50
+ }
51
+ await installRules(targetDir, stack, rulesDir, options.force);
52
+ console.log(chalk.green("\nInjection complete!"));
53
+ console.log(chalk.blue("Files created:"));
54
+ console.log(` - AGENTS.md`);
55
+ console.log(` - .cursor/rules/*.md`);
56
+ }
57
+ async function installAgentsMd(targetDir, stack, rulesDir) {
58
+ const agentsMd = generateAgentsMd(stack, ".cursor/rules");
59
+ writeFile(join(targetDir, "AGENTS.md"), agentsMd);
60
+ console.log(chalk.green("Created AGENTS.md"));
61
+ }
62
+ async function installRules(targetDir, stack, rulesDir, force) {
63
+ ensureDir(rulesDir);
64
+ const source = getRulesSource();
65
+ const relevantRules = getRelevantRules(stack);
66
+ console.log(chalk.blue(`\nInstalling ${relevantRules.length} rule files from ${source.type} source...`));
67
+ for (const rule of relevantRules) {
68
+ const destPath = join(rulesDir, rule);
69
+ if (existsSync(destPath) && !force) {
70
+ console.log(chalk.yellow(` Skipping ${rule} (exists)`));
71
+ continue;
72
+ }
73
+ try {
74
+ if (source.type === "local") {
75
+ const srcPath = join(source.path, "rules", rule);
76
+ if (existsSync(srcPath)) {
77
+ copyFile(srcPath, destPath);
78
+ console.log(chalk.green(` Copied ${rule}`));
79
+ }
80
+ else {
81
+ console.log(chalk.yellow(` Rule not found: ${rule}`));
82
+ }
83
+ }
84
+ else {
85
+ const content = await fetchRemoteFile(`${source.path}/rules/${rule}`);
86
+ writeFile(destPath, content);
87
+ console.log(chalk.green(` Fetched ${rule}`));
88
+ }
89
+ }
90
+ catch (error) {
91
+ console.log(chalk.red(` Failed to install ${rule}: ${error}`));
92
+ }
93
+ }
94
+ }
95
+ //# sourceMappingURL=inject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject.js","sourceRoot":"","sources":["../../src/commands/inject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,IAAI,EAAW,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAgB,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAY,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAMhE,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAsB;IACxD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAEhC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;IAEhD,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IAErC,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,sFAAsF,CAAC,CAAC,CAAC;QAElH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC;YAC7B,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,+BAA+B;YACxC,OAAO,EAAE;gBACP,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,YAAY,EAAE;gBACpD,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;gBACpC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;aACjC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC;IACjC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,mBAAmB,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAEzI,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAErD,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC7C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC;YAC7B,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,sCAAsC;YAC/C,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,MAAM,eAAe,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,eAAe,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,YAAY,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAE9D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;AACxC,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,SAAiB,EAAE,KAAqC,EAAE,QAAgB;IACvG,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;IAC1D,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,QAAQ,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,SAAiB,EACjB,KAAqC,EACrC,QAAgB,EAChB,KAAc;IAEd,SAAS,CAAC,QAAQ,CAAC,CAAC;IAEpB,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAChC,MAAM,aAAa,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAE9C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,aAAa,CAAC,MAAM,oBAAoB,MAAM,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC;IAEzG,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAEtC,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,cAAc,IAAI,WAAW,CAAC,CAAC,CAAC;YACzD,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;gBACjD,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;oBACxB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;oBAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC/C,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC,CAAC;gBACzD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,GAAG,MAAM,CAAC,IAAI,UAAU,IAAI,EAAE,CAAC,CAAC;gBACtE,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,uBAAuB,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function updateCommand(): Promise<void>;
2
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAkBA,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAkHnD"}
@@ -0,0 +1,111 @@
1
+ import chalk from "chalk";
2
+ import prompts from "prompts";
3
+ import { existsSync } from "fs";
4
+ import { join } from "path";
5
+ import { listFiles, readFile, writeFile, fetchRemoteFile } from "../utils/file-ops.js";
6
+ import { getRulesSource } from "../utils/paths.js";
7
+ import crypto from "crypto";
8
+ const GITHUB_RAW_BASE = "https://raw.githubusercontent.com/your-org/dev-handbook/main";
9
+ export async function updateCommand() {
10
+ const targetDir = process.cwd();
11
+ const rulesDir = join(targetDir, ".cursor", "rules");
12
+ if (!existsSync(rulesDir)) {
13
+ console.log(chalk.red("No .cursor/rules/ directory found."));
14
+ console.log(chalk.yellow("Run 'dev-rules inject' first to install rules."));
15
+ process.exit(1);
16
+ }
17
+ console.log(chalk.blue("Checking for updates...\n"));
18
+ const localRules = listFiles(rulesDir).filter((f) => f.endsWith(".md"));
19
+ if (localRules.length === 0) {
20
+ console.log(chalk.yellow("No rule files found in .cursor/rules/"));
21
+ process.exit(0);
22
+ }
23
+ const source = getRulesSource();
24
+ const statuses = [];
25
+ for (const rule of localRules) {
26
+ const localPath = join(rulesDir, rule);
27
+ const localContent = readFile(localPath);
28
+ const localHash = hashContent(localContent);
29
+ let remoteHash = null;
30
+ let error;
31
+ try {
32
+ let remoteContent;
33
+ if (source.type === "local") {
34
+ const remotePath = join(source.path, "rules", rule);
35
+ if (existsSync(remotePath)) {
36
+ remoteContent = readFile(remotePath);
37
+ remoteHash = hashContent(remoteContent);
38
+ }
39
+ }
40
+ else {
41
+ remoteContent = await fetchRemoteFile(`${GITHUB_RAW_BASE}/rules/${rule}`);
42
+ remoteHash = hashContent(remoteContent);
43
+ }
44
+ }
45
+ catch (e) {
46
+ error = e instanceof Error ? e.message : "Unknown error";
47
+ }
48
+ statuses.push({
49
+ name: rule,
50
+ localHash,
51
+ remoteHash,
52
+ isOutdated: remoteHash !== null && localHash !== remoteHash,
53
+ error,
54
+ });
55
+ }
56
+ const outdated = statuses.filter((s) => s.isOutdated);
57
+ const upToDate = statuses.filter((s) => !s.isOutdated && !s.error);
58
+ const errors = statuses.filter((s) => s.error);
59
+ console.log(chalk.blue("Status:"));
60
+ for (const status of upToDate) {
61
+ console.log(chalk.green(` ✓ ${status.name} (up to date)`));
62
+ }
63
+ for (const status of outdated) {
64
+ console.log(chalk.yellow(` ↻ ${status.name} (outdated)`));
65
+ }
66
+ for (const status of errors) {
67
+ console.log(chalk.red(` ✗ ${status.name} (${status.error})`));
68
+ }
69
+ if (outdated.length === 0) {
70
+ console.log(chalk.green("\nAll rules are up to date!"));
71
+ return;
72
+ }
73
+ console.log(chalk.yellow(`\n${outdated.length} rule(s) have updates available.`));
74
+ const response = await prompts({
75
+ type: "multiselect",
76
+ name: "toUpdate",
77
+ message: "Select rules to update:",
78
+ choices: outdated.map((s) => ({
79
+ title: s.name,
80
+ value: s.name,
81
+ selected: true,
82
+ })),
83
+ });
84
+ if (!response.toUpdate || response.toUpdate.length === 0) {
85
+ console.log(chalk.yellow("No rules selected for update."));
86
+ return;
87
+ }
88
+ console.log(chalk.blue("\nUpdating selected rules..."));
89
+ for (const ruleName of response.toUpdate) {
90
+ const destPath = join(rulesDir, ruleName);
91
+ try {
92
+ let content;
93
+ if (source.type === "local") {
94
+ content = readFile(join(source.path, "rules", ruleName));
95
+ }
96
+ else {
97
+ content = await fetchRemoteFile(`${GITHUB_RAW_BASE}/rules/${ruleName}`);
98
+ }
99
+ writeFile(destPath, content);
100
+ console.log(chalk.green(` Updated ${ruleName}`));
101
+ }
102
+ catch (e) {
103
+ console.log(chalk.red(` Failed to update ${ruleName}: ${e}`));
104
+ }
105
+ }
106
+ console.log(chalk.green("\nUpdate complete!"));
107
+ }
108
+ function hashContent(content) {
109
+ return crypto.createHash("md5").update(content).digest("hex");
110
+ }
111
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { initCommand } from "./commands/init.js";
4
+ import { injectCommand } from "./commands/inject.js";
5
+ import { updateCommand } from "./commands/update.js";
6
+ const program = new Command();
7
+ program
8
+ .name("dev-rules")
9
+ .description("CLI tool to automate Senior Architect setup for projects")
10
+ .version("1.0.0");
11
+ program
12
+ .command("init <name>")
13
+ .description("Scaffold a new project with the latest standards")
14
+ .option("-t, --template <type>", "Project template (ts, python)", "ts")
15
+ .action(initCommand);
16
+ program
17
+ .command("inject")
18
+ .description("Add standards to the current directory")
19
+ .option("-f, --force", "Overwrite existing files", false)
20
+ .action(injectCommand);
21
+ program
22
+ .command("update")
23
+ .description("Check and update outdated rules from GitHub")
24
+ .action(updateCommand);
25
+ program.parse(process.argv);
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,0DAA0D,CAAC;KACvE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,kDAAkD,CAAC;KAC/D,MAAM,CAAC,uBAAuB,EAAE,+BAA+B,EAAE,IAAI,CAAC;KACtE,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,aAAa,EAAE,0BAA0B,EAAE,KAAK,CAAC;KACxD,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,6CAA6C,CAAC;KAC1D,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { DetectedStack } from "./stack-detector.js";
2
+ export declare function generateAgentsMd(stack: DetectedStack, rulesLocation: string): string;
3
+ //# sourceMappingURL=agents-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents-generator.d.ts","sourceRoot":"","sources":["../../src/utils/agents-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAiCpF"}
@@ -0,0 +1,59 @@
1
+ export function generateAgentsMd(stack, rulesLocation) {
2
+ const ruleActivation = buildRuleActivation(stack, rulesLocation);
3
+ return `# AGENTS.md
4
+
5
+ ## DEV STANDARDS (STRICT)
6
+
7
+ **Role:** Senior Engineer. **Manager:** User (Architect).
8
+ **Goal:** Production-Ready, Type-Safe, Modular.
9
+
10
+ ### HARD CONSTRAINTS
11
+ 1. **NO SPEC = NO CODE:** Demand \`SPEC.md\` before implementation.
12
+ 2. **ZERO TOLERANCE:** No lint errors. No type errors (no \`any\`). No failing tests.
13
+ 3. **ATOMICITY:** One feature at a time. No "while I'm here" refactoring.
14
+ 4. **SAFETY:** All I/O wrapped in \`try/catch\`. All Secrets via ENV.
15
+
16
+ ### RULE ACTIVATION
17
+ *You must strictly apply the following rules based on the task:*
18
+ ${ruleActivation}
19
+
20
+ ### ARCHITECTURE (3-LAYER)
21
+ 1. **Presentation:** CLI/UI only. No logic.
22
+ 2. **Service:** Pure business logic. No I/O context.
23
+ 3. **Data:** DB/API access only.
24
+ *Use DTOs (Zod/Pydantic) for all layer communication.*
25
+
26
+ ### WORKFLOW LOOP
27
+ 1. **READ:** Development Guidance + Spec.
28
+ 2. **PLAN:** Critically review spec for gaps.
29
+ 3. **TDD:** Write failing test -> Validate failure.
30
+ 4. **CODE:** Pass test -> Refactor -> Type Check.
31
+ 5. **HALT:** If lint/test fails, fix immediately.
32
+ `;
33
+ }
34
+ function buildRuleActivation(stack, rulesLocation) {
35
+ const lines = [];
36
+ lines.push(`- **All Projects:** \`${rulesLocation}/architecture.md\`, \`${rulesLocation}/workflow.md\``);
37
+ switch (stack.primary) {
38
+ case "typescript":
39
+ if (stack.hasReact) {
40
+ lines.push(`- **TypeScript/React:** \`${rulesLocation}/rules_ts.md\`, \`${rulesLocation}/rules_react.md\`, \`${rulesLocation}/logging.md\``);
41
+ }
42
+ else {
43
+ lines.push(`- **TypeScript:** \`${rulesLocation}/rules_ts.md\`, \`${rulesLocation}/logging.md\``);
44
+ }
45
+ break;
46
+ case "python":
47
+ lines.push(`- **Python:** \`${rulesLocation}/rules_python.md\`, \`${rulesLocation}/logging.md\``);
48
+ break;
49
+ case "rust":
50
+ lines.push(`- **Rust:** \`${rulesLocation}/rules_rust.md\``);
51
+ break;
52
+ }
53
+ if (stack.hasDatabase) {
54
+ lines.push(`- **Database/SQL:** \`${rulesLocation}/rules_sql.md\``);
55
+ }
56
+ lines.push(`- **API/Security:** \`${rulesLocation}/api_design.md\`, \`${rulesLocation}/security.md\``);
57
+ return lines.join("\n");
58
+ }
59
+ //# sourceMappingURL=agents-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents-generator.js","sourceRoot":"","sources":["../../src/utils/agents-generator.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gBAAgB,CAAC,KAAoB,EAAE,aAAqB;IAC1E,MAAM,cAAc,GAAG,mBAAmB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IAEjE,OAAO;;;;;;;;;;;;;;;EAeP,cAAc;;;;;;;;;;;;;;CAcf,CAAC;AACF,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAoB,EAAE,aAAqB;IACtE,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,yBAAyB,aAAa,yBAAyB,aAAa,gBAAgB,CAAC,CAAC;IAEzG,QAAQ,KAAK,CAAC,OAAO,EAAE,CAAC;QACtB,KAAK,YAAY;YACf,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACnB,KAAK,CAAC,IAAI,CAAC,6BAA6B,aAAa,qBAAqB,aAAa,wBAAwB,aAAa,eAAe,CAAC,CAAC;YAC/I,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC,uBAAuB,aAAa,qBAAqB,aAAa,eAAe,CAAC,CAAC;YACpG,CAAC;YACD,MAAM;QACR,KAAK,QAAQ;YACX,KAAK,CAAC,IAAI,CAAC,mBAAmB,aAAa,yBAAyB,aAAa,eAAe,CAAC,CAAC;YAClG,MAAM;QACR,KAAK,MAAM;YACT,KAAK,CAAC,IAAI,CAAC,iBAAiB,aAAa,kBAAkB,CAAC,CAAC;YAC7D,MAAM;IACV,CAAC;IAED,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,yBAAyB,aAAa,iBAAiB,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,yBAAyB,aAAa,uBAAuB,aAAa,gBAAgB,CAAC,CAAC;IAEvG,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare function ensureDir(dirPath: string): void;
2
+ export declare function readFile(filePath: string): string;
3
+ export declare function writeFile(filePath: string, content: string): void;
4
+ export declare function copyFile(src: string, dest: string): void;
5
+ export declare function listFiles(dirPath: string): string[];
6
+ export declare function fetchRemoteFile(url: string): Promise<string>;
7
+ //# sourceMappingURL=file-ops.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-ops.d.ts","sourceRoot":"","sources":["../../src/utils/file-ops.ts"],"names":[],"mappings":"AAKA,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAI/C;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAGjE;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAGxD;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAKnD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwB5D"}
@@ -0,0 +1,49 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, readdirSync } from "fs";
2
+ import { dirname } from "path";
3
+ import https from "https";
4
+ import http from "http";
5
+ export function ensureDir(dirPath) {
6
+ if (!existsSync(dirPath)) {
7
+ mkdirSync(dirPath, { recursive: true });
8
+ }
9
+ }
10
+ export function readFile(filePath) {
11
+ return readFileSync(filePath, "utf-8");
12
+ }
13
+ export function writeFile(filePath, content) {
14
+ ensureDir(dirname(filePath));
15
+ writeFileSync(filePath, content, "utf-8");
16
+ }
17
+ export function copyFile(src, dest) {
18
+ ensureDir(dirname(dest));
19
+ copyFileSync(src, dest);
20
+ }
21
+ export function listFiles(dirPath) {
22
+ if (!existsSync(dirPath)) {
23
+ return [];
24
+ }
25
+ return readdirSync(dirPath);
26
+ }
27
+ export function fetchRemoteFile(url) {
28
+ return new Promise((resolve, reject) => {
29
+ const protocol = url.startsWith("https") ? https : http;
30
+ protocol.get(url, (res) => {
31
+ if (res.statusCode === 301 || res.statusCode === 302) {
32
+ const redirectUrl = res.headers.location;
33
+ if (redirectUrl) {
34
+ fetchRemoteFile(redirectUrl).then(resolve).catch(reject);
35
+ return;
36
+ }
37
+ }
38
+ if (res.statusCode !== 200) {
39
+ reject(new Error(`Failed to fetch ${url}: ${res.statusCode}`));
40
+ return;
41
+ }
42
+ let data = "";
43
+ res.on("data", (chunk) => (data += chunk));
44
+ res.on("end", () => resolve(data));
45
+ res.on("error", reject);
46
+ }).on("error", reject);
47
+ });
48
+ }
49
+ //# sourceMappingURL=file-ops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-ops.js","sourceRoot":"","sources":["../../src/utils/file-ops.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AACnG,OAAO,EAAQ,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,QAAgB;IACvC,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,OAAe;IACzD,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7B,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,IAAY;IAChD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACzB,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QAExD,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;gBACrD,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACzC,IAAI,WAAW,EAAE,CAAC;oBAChB,eAAe,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;oBACzD,OAAO;gBACT,CAAC;YACH,CAAC;YAED,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;gBAC3B,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,GAAG,KAAK,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;gBAC/D,OAAO;YACT,CAAC;YAED,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC;YAC3C,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACnC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Determines the source of truth for rules:
3
+ * - If running from within the dev-handbook repo, uses local files
4
+ * - Otherwise, indicates rules should be fetched from GitHub
5
+ */
6
+ export declare function getRulesSource(): {
7
+ type: "local" | "remote";
8
+ path: string;
9
+ };
10
+ /**
11
+ * Get the path to rules directory
12
+ */
13
+ export declare function getRulesPath(): string;
14
+ /**
15
+ * Get the path to templates directory
16
+ */
17
+ export declare function getTemplatesPath(): string;
18
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,wBAAgB,cAAc,IAAI;IAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAgB3E;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAKrC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAKzC"}
@@ -0,0 +1,44 @@
1
+ import { existsSync } from "fs";
2
+ import { dirname, join, resolve } from "path";
3
+ import { fileURLToPath } from "url";
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = dirname(__filename);
6
+ /**
7
+ * Determines the source of truth for rules:
8
+ * - If running from within the dev-handbook repo, uses local files
9
+ * - Otherwise, indicates rules should be fetched from GitHub
10
+ */
11
+ export function getRulesSource() {
12
+ // Navigate from cli/dist/utils to repo root
13
+ const repoRoot = resolve(__dirname, "..", "..", "..");
14
+ const localRulesPath = join(repoRoot, "rules");
15
+ const localTemplatesPath = join(repoRoot, "templates");
16
+ // Check if we're running from within the dev-handbook repo
17
+ if (existsSync(localRulesPath) && existsSync(localTemplatesPath)) {
18
+ return { type: "local", path: repoRoot };
19
+ }
20
+ // Fall back to remote GitHub
21
+ return {
22
+ type: "remote",
23
+ path: "https://raw.githubusercontent.com/your-org/dev-handbook/main",
24
+ };
25
+ }
26
+ /**
27
+ * Get the path to rules directory
28
+ */
29
+ export function getRulesPath() {
30
+ const source = getRulesSource();
31
+ return source.type === "local"
32
+ ? join(source.path, "rules")
33
+ : `${source.path}/rules`;
34
+ }
35
+ /**
36
+ * Get the path to templates directory
37
+ */
38
+ export function getTemplatesPath() {
39
+ const source = getRulesSource();
40
+ return source.type === "local"
41
+ ? join(source.path, "templates")
42
+ : `${source.path}/templates`;
43
+ }
44
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,4CAA4C;IAC5C,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACtD,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,kBAAkB,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAEvD,2DAA2D;IAC3D,IAAI,UAAU,CAAC,cAAc,CAAC,IAAI,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACjE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC3C,CAAC;IAED,6BAA6B;IAC7B,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,8DAA8D;KACrE,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAChC,OAAO,MAAM,CAAC,IAAI,KAAK,OAAO;QAC5B,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC;QAC5B,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,QAAQ,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAChC,OAAO,MAAM,CAAC,IAAI,KAAK,OAAO;QAC5B,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC;QAChC,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,YAAY,CAAC;AACjC,CAAC"}
@@ -0,0 +1,9 @@
1
+ export type StackType = "typescript" | "python" | "rust" | "unknown";
2
+ export interface DetectedStack {
3
+ primary: StackType;
4
+ hasReact: boolean;
5
+ hasDatabase: boolean;
6
+ }
7
+ export declare function detectStack(targetDir: string): DetectedStack;
8
+ export declare function getRelevantRules(stack: DetectedStack): string[];
9
+ //# sourceMappingURL=stack-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack-detector.d.ts","sourceRoot":"","sources":["../../src/utils/stack-detector.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAErE,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,SAAS,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAqC5D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,EAAE,CAyB/D"}
@@ -0,0 +1,60 @@
1
+ import { existsSync } from "fs";
2
+ import { join } from "path";
3
+ export function detectStack(targetDir) {
4
+ const result = {
5
+ primary: "unknown",
6
+ hasReact: false,
7
+ hasDatabase: false,
8
+ };
9
+ const tsIndicators = ["package.json", "tsconfig.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"];
10
+ const pythonIndicators = ["pyproject.toml", "requirements.txt", "setup.py", "Pipfile"];
11
+ const rustIndicators = ["Cargo.toml", "Cargo.lock"];
12
+ const hasTs = tsIndicators.some((f) => existsSync(join(targetDir, f)));
13
+ const hasPython = pythonIndicators.some((f) => existsSync(join(targetDir, f)));
14
+ const hasRust = rustIndicators.some((f) => existsSync(join(targetDir, f)));
15
+ if (hasTs) {
16
+ result.primary = "typescript";
17
+ const packageJsonPath = join(targetDir, "package.json");
18
+ if (existsSync(packageJsonPath)) {
19
+ try {
20
+ const pkg = require(packageJsonPath);
21
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
22
+ result.hasReact = "react" in allDeps;
23
+ }
24
+ catch {
25
+ }
26
+ }
27
+ }
28
+ else if (hasPython) {
29
+ result.primary = "python";
30
+ }
31
+ else if (hasRust) {
32
+ result.primary = "rust";
33
+ }
34
+ const sqlIndicators = [".sql", "migrations", "prisma", "drizzle.config.ts", "knexfile.js"];
35
+ result.hasDatabase = sqlIndicators.some((f) => existsSync(join(targetDir, f)));
36
+ return result;
37
+ }
38
+ export function getRelevantRules(stack) {
39
+ const rules = ["architecture.md", "workflow.md", "security.md"];
40
+ switch (stack.primary) {
41
+ case "typescript":
42
+ rules.push("rules_ts.md", "logging.md", "testing.md");
43
+ if (stack.hasReact) {
44
+ rules.push("rules_react.md");
45
+ }
46
+ break;
47
+ case "python":
48
+ rules.push("rules_python.md", "logging.md", "testing.md");
49
+ break;
50
+ case "rust":
51
+ rules.push("rules_rust.md", "testing.md");
52
+ break;
53
+ }
54
+ if (stack.hasDatabase) {
55
+ rules.push("rules_sql.md");
56
+ }
57
+ rules.push("api_design.md", "documentation.md");
58
+ return rules;
59
+ }
60
+ //# sourceMappingURL=stack-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack-detector.js","sourceRoot":"","sources":["../../src/utils/stack-detector.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "dev-rules",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool to automate Senior Architect setup for new and existing projects",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "dev-rules": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "ts-node src/index.ts",
13
+ "start": "node dist/index.js",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "keywords": [
17
+ "cli",
18
+ "developer-tools",
19
+ "standards",
20
+ "architect",
21
+ "coding-standards"
22
+ ],
23
+ "author": "",
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "chalk": "^4.1.2",
27
+ "commander": "^12.1.0",
28
+ "prompts": "^2.4.2"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^20.14.0",
32
+ "@types/prompts": "^2.4.9",
33
+ "ts-node": "^10.9.2",
34
+ "typescript": "^5.4.5"
35
+ },
36
+ "engines": {
37
+ "node": ">=18.0.0"
38
+ },
39
+ "files": [
40
+ "dist",
41
+ "README.md"
42
+ ],
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/your-org/dev-handbook"
46
+ }
47
+ }