azcodr 1.5.0 → 1.5.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.
Files changed (75) hide show
  1. package/.agents/hooks.json +42 -0
  2. package/.agents/hooks.json.example +42 -42
  3. package/.agents/mcp_config.json.example +29 -24
  4. package/.agents/scripts/safety_guard.sh +34 -16
  5. package/.agents/scripts/verify_completion.sh +27 -13
  6. package/.agents/skills/agentic-architect/SKILL.md +125 -125
  7. package/.agents/skills/agentic-architect/references/agents_md_template.md +62 -62
  8. package/.agents/skills/agentic-architect/references/refinement_workflow.md +32 -32
  9. package/.agents/skills/agentic-architect/references/skill_architecture_inquiry.md +63 -63
  10. package/.agents/skills/agentic-architect/references/skill_template.md +56 -56
  11. package/.agents/skills/agentic-architect/scripts/validate_agentic_configs.sh +402 -362
  12. package/.agents/skills/clean-code-refactor/SKILL.md +91 -91
  13. package/.agents/skills/clean-code-refactor/references/clean_code_smells.md +27 -27
  14. package/.agents/skills/clean-code-refactor/references/design_patterns_ts.md +65 -65
  15. package/.agents/skills/compliance-audit/SKILL.md +120 -120
  16. package/.agents/skills/compliance-audit/references/owasp_top10_controls.md +16 -16
  17. package/.agents/skills/compliance-audit/references/soc2_iso_controls.md +28 -28
  18. package/.agents/skills/lets-build/SKILL.md +173 -172
  19. package/.agents/skills/lets-build/references/architecture_interview_matrix.md +115 -115
  20. package/.agents/skills/lets-build/references/hexagonal_bootstrap_scaffolds.md +160 -160
  21. package/.agents/skills/lets-build/references/project_readme_template.md +79 -79
  22. package/.agents/skills/lets-build/scripts/bootstrap_workspace.sh +255 -253
  23. package/.agents/skills/product-analyst/SKILL.md +154 -154
  24. package/.agents/skills/product-analyst/references/backlog_ordering_techniques.md +107 -107
  25. package/.agents/skills/product-analyst/references/gherkin_patterns.md +46 -46
  26. package/.agents/skills/product-analyst/references/invest_checklist.md +38 -38
  27. package/.agents/skills/product-analyst/references/okr_alignment_guide.md +76 -76
  28. package/.agents/skills/product-analyst/references/smart_tasks.md +59 -59
  29. package/.agents/skills/relentless-questioner/SKILL.md +128 -128
  30. package/.agents/skills/relentless-questioner/references/adaptive_question_trees.md +102 -102
  31. package/.editorconfig +19 -19
  32. package/.github/copilot-instructions.md +1 -0
  33. package/.github/workflows/ci.yml +78 -0
  34. package/.gitignore +25 -25
  35. package/AGENTS.md +102 -102
  36. package/LICENSE +21 -21
  37. package/README.md +165 -154
  38. package/bin/azcodr.js +228 -228
  39. package/data/.gitkeep +0 -0
  40. package/docs/knowledge/ubiquitous_language.md +18 -18
  41. package/docs/rules/agentic_configuration.md +259 -259
  42. package/docs/rules/api_architecture.md +179 -179
  43. package/docs/rules/authentication.md +76 -76
  44. package/docs/rules/authorization.md +75 -75
  45. package/docs/rules/caching.md +69 -69
  46. package/docs/rules/clean_code.md +62 -62
  47. package/docs/rules/cloud_native.md +41 -41
  48. package/docs/rules/cqrs.md +203 -203
  49. package/docs/rules/database_design.md +125 -125
  50. package/docs/rules/database_operations.md +69 -69
  51. package/docs/rules/design_patterns.md +98 -98
  52. package/docs/rules/devops_ci_cd.md +76 -76
  53. package/docs/rules/domain_driven_design.md +122 -122
  54. package/docs/rules/error_handling.md +52 -52
  55. package/docs/rules/feature_flags.md +59 -59
  56. package/docs/rules/frontend_architecture.md +157 -157
  57. package/docs/rules/multitenancy_architecture.md +98 -98
  58. package/docs/rules/product_ownership.md +127 -127
  59. package/docs/rules/project_management.md +49 -49
  60. package/docs/rules/relentless_questioning.md +52 -52
  61. package/docs/rules/requirements_engineering.md +98 -98
  62. package/docs/rules/security_compliance.md +53 -53
  63. package/docs/rules/server_driven_ui.md +88 -88
  64. package/docs/rules/test_driven_development.md +185 -185
  65. package/docs/rules/transactional_email.md +27 -27
  66. package/docs/rules/type_safety.md +65 -65
  67. package/docs/rules/ui_ux_architecture.md +150 -150
  68. package/docs/rules/workflow_state_machines.md +117 -117
  69. package/lib/index.d.ts +134 -123
  70. package/lib/index.js +5 -5
  71. package/lib/scaffold.js +448 -351
  72. package/memory.md +36 -36
  73. package/package.json +62 -59
  74. package/scripts/test_coverage.js +38 -0
  75. package/scripts/validate.js +258 -0
package/bin/azcodr.js CHANGED
@@ -1,228 +1,228 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const path = require('node:path');
5
- const readline = require('node:readline');
6
- const fs = require('node:fs');
7
- const { scaffold, getTemplateDir } = require('../lib/scaffold.js');
8
- const pkg = require('../package.json');
9
-
10
- function printHelp(out = console.log) {
11
- out(`
12
- azcodr v${pkg.version}
13
- Enterprise Multi-Tenant Architecture & Agentic Engineering Starter Template
14
-
15
- Usage:
16
- npx azcodr [directory] [options]
17
-
18
- Commands:
19
- [directory] Scaffold azcodr template into directory (default: current directory)
20
-
21
- Options:
22
- -d, --dry-run Simulate scaffolding without modifying filesystem
23
- -s, --silent Suppress console output messages
24
- -f, --force Overwrite existing files in target directory without confirmation
25
- --no-git Do not initialize a git repository
26
- -v, --version Display version number
27
- -h, --help Display this help message
28
-
29
- Examples:
30
- npx azcodr my-project
31
- npx azcodr . --dry-run
32
- npx azcodr . --force
33
- `);
34
- }
35
-
36
- function printVersion(out = console.log) {
37
- out(pkg.version);
38
- }
39
-
40
- function askQuestion(query, { input = process.stdin, output = process.stdout } = {}) {
41
- const rl = readline.createInterface({ input, output });
42
-
43
- return new Promise((resolve) => {
44
- let resolved = false;
45
- rl.question(query, (answer) => {
46
- if (!resolved) {
47
- resolved = true;
48
- rl.close();
49
- resolve(answer.trim());
50
- }
51
- });
52
- rl.on('close', () => {
53
- if (!resolved) {
54
- resolved = true;
55
- resolve('');
56
- }
57
- });
58
- });
59
- }
60
-
61
- async function runCli(rawArgs = process.argv.slice(2), io = {}) {
62
- const {
63
- out = console.log,
64
- err = console.error,
65
- exit = process.exit,
66
- stdin = process.stdin,
67
- stdout = process.stdout,
68
- cwd = process.cwd(),
69
- templateDir = getTemplateDir(),
70
- scaffold: scaffoldFn = scaffold
71
- } = io;
72
-
73
- let targetDir = null;
74
- let force = false;
75
- let noGit = false;
76
- let dryRun = false;
77
- let silent = false;
78
-
79
- for (let i = 0; i < rawArgs.length; i++) {
80
- const arg = rawArgs[i];
81
- if (arg === '-h' || arg === '--help') {
82
- printHelp(out);
83
- return exit(0);
84
- } else if (arg === '-v' || arg === '--version') {
85
- printVersion(out);
86
- return exit(0);
87
- } else if (arg === '-f' || arg === '--force') {
88
- force = true;
89
- } else if (arg === '--no-git') {
90
- noGit = true;
91
- } else if (arg === '-d' || arg === '--dry-run') {
92
- dryRun = true;
93
- } else if (arg === '-s' || arg === '--silent') {
94
- silent = true;
95
- } else if (arg.startsWith('-')) {
96
- err(`❌ Error: Unknown argument '${arg}'. Run 'npx azcodr --help' for available options.`);
97
- return exit(1);
98
- } else if (!targetDir) {
99
- targetDir = arg;
100
- } else {
101
- err(`❌ Error: Unexpected argument '${arg}'. Run 'npx azcodr --help' for available options.`);
102
- return exit(1);
103
- }
104
- }
105
-
106
- if (!silent) {
107
- out('\n🚀 azcodr - Enterprise Multi-Tenant Architecture & Agentic Engineering\n');
108
- }
109
-
110
- if (!targetDir) {
111
- if (stdin.isTTY) {
112
- const answer = await askQuestion('? Where would you like to initialize your project? (./) ', {
113
- input: stdin,
114
- output: stdout
115
- });
116
- targetDir = answer || '.';
117
- } else {
118
- targetDir = '.';
119
- }
120
- }
121
-
122
- const resolvedTarget = path.resolve(cwd, targetDir);
123
-
124
- if (resolvedTarget === templateDir) {
125
- err(`❌ Error: Cannot scaffold into the template directory itself: ${resolvedTarget}`);
126
- return exit(1);
127
- }
128
-
129
- if (fs.existsSync(resolvedTarget)) {
130
- const stat = fs.statSync(resolvedTarget);
131
- if (!stat.isDirectory()) {
132
- err(`❌ Error: Target '${resolvedTarget}' already exists and is not a directory.`);
133
- return exit(1);
134
- }
135
- const entries = fs.readdirSync(resolvedTarget);
136
- if (entries.length > 0 && !force) {
137
- if (stdin.isTTY) {
138
- const confirm = await askQuestion(
139
- `⚠️ Target directory '${targetDir}' is not empty (${entries.length} items). Continue? (y/N) `,
140
- { input: stdin, output: stdout }
141
- );
142
- if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') {
143
- out('Scaffolding aborted.');
144
- return exit(0);
145
- }
146
- force = true;
147
- } else {
148
- err(`❌ Error: Target directory '${resolvedTarget}' is not empty. Use --force to proceed.`);
149
- return exit(1);
150
- }
151
- }
152
- }
153
-
154
- if (dryRun) {
155
- if (!silent) {
156
- out(`🔍 DRY RUN: Simulating azcodr scaffolding into: ${resolvedTarget}\n`);
157
- }
158
- } else if (!silent) {
159
- out(`📦 Scaffolding azcodr into: ${resolvedTarget}`);
160
- }
161
-
162
- try {
163
- const result = scaffoldFn({
164
- targetDir: resolvedTarget,
165
- force,
166
- noGit,
167
- templateDir,
168
- dryRun,
169
- silent
170
- });
171
-
172
- if (dryRun) {
173
- if (!silent) {
174
- for (const action of result.actions) {
175
- out(` [preview] ${action}`);
176
- }
177
- out('\n🎉 Dry run completed. 0 files modified on disk.\n');
178
- }
179
- return exit(0);
180
- }
181
-
182
- if (!silent) {
183
- out(' ✅ Progressive disclosure rules copied (docs/rules/)');
184
- out(' ✅ Workspace knowledge hub and ADR ledger copied (docs/knowledge/, memory.md)');
185
- out(' ✅ Specialized agentic skills copied (.agents/skills/)');
186
- out(' ✅ Editor formatting standards initialized (.editorconfig)');
187
- out(' ✅ Agent directives and harness symlinks established (AGENTS.md, CLAUDE.md, agents.md, GEMINI.md, .cursorrules, .windsurfrules, .github/copilot-instructions.md)');
188
- out(' ✅ Project configuration initialized (package.json)');
189
- if (result.gitInitialized) {
190
- out(' ✅ Git repository initialized');
191
- }
192
-
193
- out('\n🎉 azcodr initialized successfully!\n');
194
- out('Next steps:');
195
- let step = 1;
196
- if (targetDir !== '.' && targetDir !== './') {
197
- out(` ${step++}. cd ${targetDir}`);
198
- }
199
- out(` ${step++}. Open the project in your AI coding assistant (Antigravity, Claude Code, Cursor, OpenHands)`);
200
- out(` ${step++}. Run /lets-build to start the architectural interview and scaffold your application stack!\n`);
201
- }
202
- return exit(0);
203
- } catch (error) {
204
- err(`\n❌ Scaffolding failed: ${error.message}\n`);
205
- return exit(1);
206
- }
207
- }
208
-
209
- async function main() {
210
- try {
211
- await runCli(process.argv.slice(2));
212
- } catch (err) {
213
- console.error('Unexpected error:', err);
214
- process.exit(1);
215
- }
216
- }
217
-
218
- if (require.main === module) {
219
- main();
220
- }
221
-
222
- module.exports = {
223
- runCli,
224
- askQuestion,
225
- printHelp,
226
- printVersion,
227
- main
228
- };
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const path = require('node:path');
5
+ const readline = require('node:readline');
6
+ const fs = require('node:fs');
7
+ const { scaffold, getTemplateDir } = require('../lib/scaffold.js');
8
+ const pkg = require('../package.json');
9
+
10
+ function printHelp(out = console.log) {
11
+ out(`
12
+ azcodr v${pkg.version}
13
+ Enterprise Multi-Tenant Architecture & Agentic Engineering Starter Template
14
+
15
+ Usage:
16
+ npx azcodr [directory] [options]
17
+
18
+ Commands:
19
+ [directory] Scaffold azcodr template into directory (default: current directory)
20
+
21
+ Options:
22
+ -d, --dry-run Simulate scaffolding without modifying filesystem
23
+ -s, --silent Suppress console output messages
24
+ -f, --force Overwrite existing files in target directory without confirmation
25
+ --no-git Do not initialize a git repository
26
+ -v, --version Display version number
27
+ -h, --help Display this help message
28
+
29
+ Examples:
30
+ npx azcodr my-project
31
+ npx azcodr . --dry-run
32
+ npx azcodr . --force
33
+ `);
34
+ }
35
+
36
+ function printVersion(out = console.log) {
37
+ out(pkg.version);
38
+ }
39
+
40
+ function askQuestion(query, { input = process.stdin, output = process.stdout } = {}) {
41
+ const rl = readline.createInterface({ input, output });
42
+
43
+ return new Promise((resolve) => {
44
+ let resolved = false;
45
+ rl.question(query, (answer) => {
46
+ if (!resolved) {
47
+ resolved = true;
48
+ rl.close();
49
+ resolve(answer.trim());
50
+ }
51
+ });
52
+ rl.on('close', () => {
53
+ if (!resolved) {
54
+ resolved = true;
55
+ resolve('');
56
+ }
57
+ });
58
+ });
59
+ }
60
+
61
+ async function runCli(rawArgs = process.argv.slice(2), io = {}) {
62
+ const {
63
+ out = console.log,
64
+ err = console.error,
65
+ exit = process.exit,
66
+ stdin = process.stdin,
67
+ stdout = process.stdout,
68
+ cwd = process.cwd(),
69
+ templateDir = getTemplateDir(),
70
+ scaffold: scaffoldFn = scaffold
71
+ } = io;
72
+
73
+ let targetDir = null;
74
+ let force = false;
75
+ let noGit = false;
76
+ let dryRun = false;
77
+ let silent = false;
78
+
79
+ for (let i = 0; i < rawArgs.length; i++) {
80
+ const arg = rawArgs[i];
81
+ if (arg === '-h' || arg === '--help') {
82
+ printHelp(out);
83
+ return exit(0);
84
+ } else if (arg === '-v' || arg === '--version') {
85
+ printVersion(out);
86
+ return exit(0);
87
+ } else if (arg === '-f' || arg === '--force') {
88
+ force = true;
89
+ } else if (arg === '--no-git') {
90
+ noGit = true;
91
+ } else if (arg === '-d' || arg === '--dry-run') {
92
+ dryRun = true;
93
+ } else if (arg === '-s' || arg === '--silent') {
94
+ silent = true;
95
+ } else if (arg.startsWith('-')) {
96
+ err(`❌ Error: Unknown argument '${arg}'. Run 'npx azcodr --help' for available options.`);
97
+ return exit(1);
98
+ } else if (!targetDir) {
99
+ targetDir = arg;
100
+ } else {
101
+ err(`❌ Error: Unexpected argument '${arg}'. Run 'npx azcodr --help' for available options.`);
102
+ return exit(1);
103
+ }
104
+ }
105
+
106
+ if (!silent) {
107
+ out('\n🚀 azcodr - Enterprise Multi-Tenant Architecture & Agentic Engineering\n');
108
+ }
109
+
110
+ if (!targetDir) {
111
+ if (stdin.isTTY) {
112
+ const answer = await askQuestion('? Where would you like to initialize your project? (./) ', {
113
+ input: stdin,
114
+ output: stdout
115
+ });
116
+ targetDir = answer || '.';
117
+ } else {
118
+ targetDir = '.';
119
+ }
120
+ }
121
+
122
+ const resolvedTarget = path.resolve(cwd, targetDir);
123
+
124
+ if (resolvedTarget === templateDir) {
125
+ err(`❌ Error: Cannot scaffold into the template directory itself: ${resolvedTarget}`);
126
+ return exit(1);
127
+ }
128
+
129
+ if (fs.existsSync(resolvedTarget)) {
130
+ const stat = fs.statSync(resolvedTarget);
131
+ if (!stat.isDirectory()) {
132
+ err(`❌ Error: Target '${resolvedTarget}' already exists and is not a directory.`);
133
+ return exit(1);
134
+ }
135
+ const entries = fs.readdirSync(resolvedTarget);
136
+ if (entries.length > 0 && !force) {
137
+ if (stdin.isTTY) {
138
+ const confirm = await askQuestion(
139
+ `⚠️ Target directory '${targetDir}' is not empty (${entries.length} items). Continue? (y/N) `,
140
+ { input: stdin, output: stdout }
141
+ );
142
+ if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') {
143
+ out('Scaffolding aborted.');
144
+ return exit(0);
145
+ }
146
+ force = true;
147
+ } else {
148
+ err(`❌ Error: Target directory '${resolvedTarget}' is not empty. Use --force to proceed.`);
149
+ return exit(1);
150
+ }
151
+ }
152
+ }
153
+
154
+ if (dryRun) {
155
+ if (!silent) {
156
+ out(`🔍 DRY RUN: Simulating azcodr scaffolding into: ${resolvedTarget}\n`);
157
+ }
158
+ } else if (!silent) {
159
+ out(`📦 Scaffolding azcodr into: ${resolvedTarget}`);
160
+ }
161
+
162
+ try {
163
+ const result = scaffoldFn({
164
+ targetDir: resolvedTarget,
165
+ force,
166
+ noGit,
167
+ templateDir,
168
+ dryRun,
169
+ silent
170
+ });
171
+
172
+ if (dryRun) {
173
+ if (!silent) {
174
+ for (const action of result.actions) {
175
+ out(` [preview] ${action}`);
176
+ }
177
+ out('\n🎉 Dry run completed. 0 files modified on disk.\n');
178
+ }
179
+ return exit(0);
180
+ }
181
+
182
+ if (!silent) {
183
+ out(' ✅ Progressive disclosure rules copied (docs/rules/)');
184
+ out(' ✅ Workspace knowledge hub and ADR ledger copied (docs/knowledge/, memory.md)');
185
+ out(' ✅ Specialized agentic skills copied (.agents/skills/)');
186
+ out(' ✅ Editor formatting standards initialized (.editorconfig)');
187
+ out(' ✅ Agent directives and harness symlinks established (AGENTS.md, CLAUDE.md, agents.md, GEMINI.md, .cursorrules, .windsurfrules, .github/copilot-instructions.md)');
188
+ out(' ✅ Project configuration initialized (package.json)');
189
+ if (result.gitInitialized) {
190
+ out(' ✅ Git repository initialized');
191
+ }
192
+
193
+ out('\n🎉 azcodr initialized successfully!\n');
194
+ out('Next steps:');
195
+ let step = 1;
196
+ if (targetDir !== '.' && targetDir !== './') {
197
+ out(` ${step++}. cd ${targetDir}`);
198
+ }
199
+ out(` ${step++}. Open the project in your AI coding assistant (Antigravity, Claude Code, Cursor, OpenHands)`);
200
+ out(` ${step++}. Run /lets-build to start the architectural interview and scaffold your application stack!\n`);
201
+ }
202
+ return exit(0);
203
+ } catch (error) {
204
+ err(`\n❌ Scaffolding failed: ${error.message}\n`);
205
+ return exit(1);
206
+ }
207
+ }
208
+
209
+ async function main() {
210
+ try {
211
+ await runCli(process.argv.slice(2));
212
+ } catch (err) {
213
+ console.error('Unexpected error:', err);
214
+ process.exit(1);
215
+ }
216
+ }
217
+
218
+ if (require.main === module) {
219
+ main();
220
+ }
221
+
222
+ module.exports = {
223
+ runCli,
224
+ askQuestion,
225
+ printHelp,
226
+ printVersion,
227
+ main
228
+ };
package/data/.gitkeep ADDED
File without changes
@@ -1,18 +1,18 @@
1
- # Living Ubiquitous Language Glossary Template
2
-
3
- > **Source of Truth:** Authoritative terminology dictionary binding domain concepts, business definitions, and exact code identifiers. Customize this glossary per project.
4
-
5
- ---
6
-
7
- ## Canonical Domain Vocabulary Matrix
8
-
9
- | Canonical Term | Business Definition | Bounded Context | Forbidden Synonyms | Code & Database Identifiers |
10
- |---|---|---|---|---|
11
- | *(No domain terms defined yet)* | *Define business meaning during Phase 1 Domain Discovery.* | *e.g. Core Domain* | *Synonyms strictly forbidden across code & UI.* | *Exact type, class, or table name.* |
12
-
13
- ---
14
-
15
- ## Linguistic Invariants & Rules
16
- 1. **The Single Name Rule:** Every domain concept has exactly one authoritative name. Synonyms are strictly forbidden across code, schemas, and UI.
17
- 2. **Contextual Boundaries:** If a word has multiple meanings across business departments, isolate the terms within dedicated Bounded Contexts.
18
- 3. **Continuous Updating:** When domain experts establish or rename a term, update this glossary immediately, record an ADR in `memory.md`, and refactor all occurrences.
1
+ # Living Ubiquitous Language Glossary Template
2
+
3
+ > **Source of Truth:** Authoritative terminology dictionary binding domain concepts, business definitions, and exact code identifiers. Customize this glossary per project.
4
+
5
+ ---
6
+
7
+ ## Canonical Domain Vocabulary Matrix
8
+
9
+ | Canonical Term | Business Definition | Bounded Context | Forbidden Synonyms | Code & Database Identifiers |
10
+ |---|---|---|---|---|
11
+ | *(No domain terms defined yet)* | *Define business meaning during Phase 1 Domain Discovery.* | *e.g. Core Domain* | *Synonyms strictly forbidden across code & UI.* | *Exact type, class, or table name.* |
12
+
13
+ ---
14
+
15
+ ## Linguistic Invariants & Rules
16
+ 1. **The Single Name Rule:** Every domain concept has exactly one authoritative name. Synonyms are strictly forbidden across code, schemas, and UI.
17
+ 2. **Contextual Boundaries:** If a word has multiple meanings across business departments, isolate the terms within dedicated Bounded Contexts.
18
+ 3. **Continuous Updating:** When domain experts establish or rename a term, update this glossary immediately, record an ADR in `memory.md`, and refactor all occurrences.