azcodr 1.5.2 → 2.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.
Files changed (136) hide show
  1. package/.agents/hooks.json +42 -42
  2. package/.agents/hooks.json.example +42 -42
  3. package/.agents/mcp_config.json.example +29 -29
  4. package/.agents/scripts/safety_guard.sh +143 -34
  5. package/.agents/scripts/verify_completion.sh +90 -27
  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 -402
  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 -173
  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 +419 -255
  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/workflows/ci.yml +167 -78
  33. package/.github/workflows/publish.yml +196 -0
  34. package/.gitignore +40 -25
  35. package/AGENTS.md +103 -102
  36. package/LICENSE +21 -21
  37. package/README.md +168 -165
  38. package/bin/azcodr.js +19 -228
  39. package/docs/knowledge/ubiquitous_language.md +31 -18
  40. package/docs/rules/agentic_configuration.md +259 -259
  41. package/docs/rules/api_architecture.md +179 -179
  42. package/docs/rules/authentication.md +76 -76
  43. package/docs/rules/authorization.md +75 -75
  44. package/docs/rules/caching.md +69 -69
  45. package/docs/rules/clean_code.md +62 -62
  46. package/docs/rules/cloud_native.md +41 -41
  47. package/docs/rules/cqrs.md +203 -203
  48. package/docs/rules/database_design.md +125 -125
  49. package/docs/rules/database_operations.md +69 -69
  50. package/docs/rules/design_patterns.md +98 -98
  51. package/docs/rules/devops_ci_cd.md +76 -76
  52. package/docs/rules/domain_driven_design.md +122 -122
  53. package/docs/rules/error_handling.md +54 -52
  54. package/docs/rules/feature_flags.md +59 -59
  55. package/docs/rules/frontend_architecture.md +157 -157
  56. package/docs/rules/multitenancy_architecture.md +98 -98
  57. package/docs/rules/product_ownership.md +127 -127
  58. package/docs/rules/project_management.md +49 -49
  59. package/docs/rules/relentless_questioning.md +52 -52
  60. package/docs/rules/requirements_engineering.md +98 -98
  61. package/docs/rules/security_compliance.md +53 -53
  62. package/docs/rules/server_driven_ui.md +88 -88
  63. package/docs/rules/test_driven_development.md +185 -185
  64. package/docs/rules/transactional_email.md +27 -27
  65. package/docs/rules/type_safety.md +65 -65
  66. package/docs/rules/ui_ux_architecture.md +150 -150
  67. package/docs/rules/workflow_state_machines.md +117 -117
  68. package/lib/cli-parse.d.ts +32 -0
  69. package/lib/cli-parse.d.ts.map +1 -0
  70. package/lib/cli-parse.js +55 -0
  71. package/lib/cli-parse.js.map +1 -0
  72. package/lib/cli-target.d.ts +66 -0
  73. package/lib/cli-target.d.ts.map +1 -0
  74. package/lib/cli-target.js +102 -0
  75. package/lib/cli-target.js.map +1 -0
  76. package/lib/cli.d.ts +40 -0
  77. package/lib/cli.d.ts.map +1 -0
  78. package/lib/cli.js +166 -0
  79. package/lib/cli.js.map +1 -0
  80. package/lib/errors.d.ts +39 -0
  81. package/lib/errors.d.ts.map +1 -0
  82. package/lib/errors.js +26 -0
  83. package/lib/errors.js.map +1 -0
  84. package/lib/git.d.ts +15 -0
  85. package/lib/git.d.ts.map +1 -0
  86. package/lib/git.js +32 -0
  87. package/lib/git.js.map +1 -0
  88. package/lib/guards.d.ts +35 -0
  89. package/lib/guards.d.ts.map +1 -0
  90. package/lib/guards.js +95 -0
  91. package/lib/guards.js.map +1 -0
  92. package/lib/index.d.ts +6 -134
  93. package/lib/index.d.ts.map +1 -0
  94. package/lib/index.js +4 -5
  95. package/lib/index.js.map +1 -0
  96. package/lib/links.d.ts +28 -0
  97. package/lib/links.d.ts.map +1 -0
  98. package/lib/links.js +129 -0
  99. package/lib/links.js.map +1 -0
  100. package/lib/permissions.d.ts +9 -0
  101. package/lib/permissions.d.ts.map +1 -0
  102. package/lib/permissions.js +44 -0
  103. package/lib/permissions.js.map +1 -0
  104. package/lib/repo.d.ts +20 -0
  105. package/lib/repo.d.ts.map +1 -0
  106. package/lib/repo.js +92 -0
  107. package/lib/repo.js.map +1 -0
  108. package/lib/scaffold.d.ts +80 -0
  109. package/lib/scaffold.d.ts.map +1 -0
  110. package/lib/scaffold.js +201 -448
  111. package/lib/scaffold.js.map +1 -0
  112. package/memory.md +135 -36
  113. package/package.json +75 -62
  114. package/scripts/test_coverage.js +66 -38
  115. package/scripts/validate/adr.js +155 -0
  116. package/scripts/validate/io.js +82 -0
  117. package/scripts/validate/links.js +166 -0
  118. package/scripts/validate/parity.js +122 -0
  119. package/scripts/validate/root.js +183 -0
  120. package/scripts/validate/rules.js +42 -0
  121. package/scripts/validate/skills.js +94 -0
  122. package/scripts/validate/text.js +27 -0
  123. package/scripts/validate-cli.js +12 -0
  124. package/scripts/validate.js +158 -258
  125. package/src/cli-parse.ts +77 -0
  126. package/src/cli-target.ts +167 -0
  127. package/src/cli.ts +240 -0
  128. package/src/errors.ts +35 -0
  129. package/src/git.ts +34 -0
  130. package/src/guards.ts +101 -0
  131. package/src/index.ts +39 -0
  132. package/src/links.ts +139 -0
  133. package/src/permissions.ts +42 -0
  134. package/src/repo.ts +94 -0
  135. package/src/scaffold.ts +273 -0
  136. package/.github/copilot-instructions.md +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-parse.js","sourceRoot":"","sources":["../src/cli-parse.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH,MAAM,UAAU,YAAY;IAC1B,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACvF,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAyB;IAC3D,CAAC,IAAI,EAAE,OAAO,CAAC;IACf,CAAC,SAAS,EAAE,OAAO,CAAC;IACpB,CAAC,UAAU,EAAE,OAAO,CAAC;IACrB,CAAC,IAAI,EAAE,QAAQ,CAAC;IAChB,CAAC,WAAW,EAAE,QAAQ,CAAC;IACvB,CAAC,IAAI,EAAE,QAAQ,CAAC;IAChB,CAAC,UAAU,EAAE,QAAQ,CAAC;CACvB,CAAC,CAAC;AAOH,MAAM,UAAU,QAAQ,CACtB,KAAqD,EACrD,GAAW;IAEX,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAClE,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,WAAW;QAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IACxE,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QACnB,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IACD,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,QAAQ,EAAE,cAAc;YACxB,OAAO,EAAE,qBAAqB,GAAG,mDAAmD;SACrF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QACrB,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC;QACtB,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,WAAW;QACrB,OAAO,EAAE,wBAAwB,GAAG,mDAAmD;KACxF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAA0B;IAClD,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACrC,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YAC9B,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QAC5E,CAAC;IACH,CAAC;IACD,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAC1D,CAAC;AAED,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC"}
@@ -0,0 +1,66 @@
1
+ export interface AskQuestionOptions {
2
+ input?: NodeJS.ReadableStream;
3
+ output?: NodeJS.WritableStream;
4
+ }
5
+ export declare function askQuestion(query: string, { input, output }?: AskQuestionOptions): Promise<string>;
6
+ export interface PromptIo {
7
+ stdin: NodeJS.ReadStream | (NodeJS.ReadableStream & {
8
+ isTTY?: boolean;
9
+ });
10
+ stdout: NodeJS.WriteStream | NodeJS.WritableStream;
11
+ }
12
+ export declare function promptForTargetDir(io: PromptIo): Promise<string>;
13
+ export declare function rejectBadTarget(resolvedTarget: string, templateDir: string): string | null;
14
+ export interface ResolveTargetIo extends PromptIo {
15
+ cwd: string;
16
+ templateDir: string;
17
+ }
18
+ export interface ResolveTargetResult {
19
+ resolvedTarget: string;
20
+ chosen: string;
21
+ error: string | null;
22
+ }
23
+ export declare function resolveTargetDir(targetDir: string | null, io: ResolveTargetIo): Promise<ResolveTargetResult>;
24
+ export type TargetDirectoryStatus = 'missing' | 'not-a-directory' | 'empty' | 'non-empty';
25
+ export interface TargetStatusResult {
26
+ status: TargetDirectoryStatus;
27
+ count: number;
28
+ }
29
+ export declare function targetStatus(resolvedTarget: string): TargetStatusResult;
30
+ export interface ConfirmOverwriteIo extends PromptIo {
31
+ out: (msg: string) => void;
32
+ }
33
+ export interface ConfirmOverwriteResult {
34
+ confirmed: boolean;
35
+ aborted: boolean;
36
+ }
37
+ export declare function confirmOverwrite(targetDir: string, count: number, io: ConfirmOverwriteIo): Promise<ConfirmOverwriteResult>;
38
+ export interface EnsureWritableOptions {
39
+ chosen: string;
40
+ resolvedTarget: string;
41
+ force: boolean;
42
+ io: ConfirmOverwriteIo & {
43
+ err: (msg: string) => void;
44
+ };
45
+ }
46
+ export interface EnsureWritableResult {
47
+ force?: boolean;
48
+ exitCode?: number;
49
+ message?: string | null;
50
+ }
51
+ /**
52
+ * Ensures the target may be written. Returns { force } on success or
53
+ * { exitCode, message? } when the CLI must stop before scaffolding.
54
+ */
55
+ export declare function ensureWritableTarget(options: EnsureWritableOptions): Promise<EnsureWritableResult>;
56
+ declare const _default: {
57
+ askQuestion: typeof askQuestion;
58
+ promptForTargetDir: typeof promptForTargetDir;
59
+ rejectBadTarget: typeof rejectBadTarget;
60
+ resolveTargetDir: typeof resolveTargetDir;
61
+ targetStatus: typeof targetStatus;
62
+ confirmOverwrite: typeof confirmOverwrite;
63
+ ensureWritableTarget: typeof ensureWritableTarget;
64
+ };
65
+ export default _default;
66
+ //# sourceMappingURL=cli-target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-target.d.ts","sourceRoot":"","sources":["../src/cli-target.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAChC;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,EAAE,KAAqB,EAAE,MAAuB,EAAE,GAAE,kBAAuB,GAC1E,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC,UAAU,GAAG,CAAC,MAAM,CAAC,cAAc,GAAG;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzE,MAAM,EAAE,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,cAAc,CAAC;CACpD;AAED,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAQtE;AAED,wBAAgB,eAAe,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ1F;AAED,MAAM,WAAW,eAAgB,SAAQ,QAAQ;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,EAAE,EAAE,eAAe,GAClB,OAAO,CAAC,mBAAmB,CAAC,CAO9B;AAED,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,iBAAiB,GAAG,OAAO,GAAG,WAAW,CAAC;AAE1F,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,kBAAkB,CAKvE;AAED,MAAM,WAAW,kBAAmB,SAAQ,QAAQ;IAClD,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,kBAAkB,GACrB,OAAO,CAAC,sBAAsB,CAAC,CAYjC;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;IACf,EAAE,EAAE,kBAAkB,GAAG;QAAE,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACzD;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAa/B;;;;;;;;;;AAED,wBAQE"}
@@ -0,0 +1,102 @@
1
+ import path from 'node:path';
2
+ import readline from 'node:readline';
3
+ import fs from 'node:fs';
4
+ import process from 'node:process';
5
+ import { isProtectedTarget } from './guards.js';
6
+ export function askQuestion(query, { input = process.stdin, output = process.stdout } = {}) {
7
+ const rl = readline.createInterface({ input, output });
8
+ return new Promise((resolve) => {
9
+ let resolved = false;
10
+ rl.question(query, (answer) => {
11
+ if (!resolved) {
12
+ resolved = true;
13
+ rl.close();
14
+ resolve(answer.trim());
15
+ }
16
+ });
17
+ rl.on('close', () => {
18
+ if (!resolved) {
19
+ resolved = true;
20
+ resolve('');
21
+ }
22
+ });
23
+ });
24
+ }
25
+ export async function promptForTargetDir(io) {
26
+ const { stdin, stdout } = io;
27
+ if (!stdin.isTTY)
28
+ return '.';
29
+ const answer = await askQuestion('? Where would you like to initialize your project? (./) ', {
30
+ input: stdin,
31
+ output: stdout
32
+ });
33
+ return answer || '.';
34
+ }
35
+ export function rejectBadTarget(resolvedTarget, templateDir) {
36
+ if (resolvedTarget === templateDir) {
37
+ return `Cannot scaffold into the template directory itself: ${resolvedTarget}`;
38
+ }
39
+ if (isProtectedTarget(resolvedTarget, { templateDir })) {
40
+ return `Refusing to scaffold into protected directory: ${resolvedTarget}. Choose a project subdirectory instead.`;
41
+ }
42
+ return null;
43
+ }
44
+ export async function resolveTargetDir(targetDir, io) {
45
+ const { cwd, templateDir } = io;
46
+ const chosen = targetDir || (await promptForTargetDir(io));
47
+ const resolvedTarget = path.resolve(cwd, chosen);
48
+ const rejection = rejectBadTarget(resolvedTarget, templateDir);
49
+ if (rejection !== null)
50
+ return { resolvedTarget, chosen, error: rejection };
51
+ return { resolvedTarget, chosen, error: null };
52
+ }
53
+ export function targetStatus(resolvedTarget) {
54
+ if (!fs.existsSync(resolvedTarget))
55
+ return { status: 'missing', count: 0 };
56
+ if (!fs.statSync(resolvedTarget).isDirectory())
57
+ return { status: 'not-a-directory', count: 0 };
58
+ const count = fs.readdirSync(resolvedTarget).length;
59
+ return { status: count === 0 ? 'empty' : 'non-empty', count };
60
+ }
61
+ export async function confirmOverwrite(targetDir, count, io) {
62
+ const { stdin, stdout, out } = io;
63
+ if (!stdin.isTTY)
64
+ return { confirmed: false, aborted: false };
65
+ const confirm = await askQuestion(`⚠️ Target directory '${targetDir}' is not empty (${count} items). Continue? (y/N) `, { input: stdin, output: stdout });
66
+ if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') {
67
+ out('Scaffolding aborted.');
68
+ return { confirmed: false, aborted: true };
69
+ }
70
+ return { confirmed: true, aborted: false };
71
+ }
72
+ /**
73
+ * Ensures the target may be written. Returns { force } on success or
74
+ * { exitCode, message? } when the CLI must stop before scaffolding.
75
+ */
76
+ export async function ensureWritableTarget(options) {
77
+ const { chosen, resolvedTarget, force, io } = options;
78
+ const { err } = io;
79
+ const { status, count } = targetStatus(resolvedTarget);
80
+ if (status === 'missing' || status === 'empty' || force)
81
+ return { force };
82
+ if (status === 'not-a-directory') {
83
+ return { exitCode: 1, message: `Target '${resolvedTarget}' already exists and is not a directory.` };
84
+ }
85
+ const { confirmed, aborted } = await confirmOverwrite(chosen, count, io);
86
+ if (aborted)
87
+ return { exitCode: 0, message: null };
88
+ if (confirmed)
89
+ return { force: true };
90
+ err(`Target directory '${resolvedTarget}' is not empty. Use --force to proceed.`);
91
+ return { exitCode: 1, message: null };
92
+ }
93
+ export default {
94
+ askQuestion,
95
+ promptForTargetDir,
96
+ rejectBadTarget,
97
+ resolveTargetDir,
98
+ targetStatus,
99
+ confirmOverwrite,
100
+ ensureWritableTarget
101
+ };
102
+ //# sourceMappingURL=cli-target.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-target.js","sourceRoot":"","sources":["../src/cli-target.ts"],"names":[],"mappings":"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"}
package/lib/cli.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ import type { ScaffoldOptions, ScaffoldResult } from './scaffold.js';
2
+ import { askQuestion } from './cli-target.js';
3
+ export declare function printHelp(out?: (msg: string) => void): void;
4
+ export declare function printVersion(out?: (msg: string) => void): void;
5
+ export interface CliIo {
6
+ out?: (msg: string) => void;
7
+ err?: (msg: string) => void;
8
+ exit?: (code: number) => void | number;
9
+ stdin?: NodeJS.ReadableStream & {
10
+ isTTY?: boolean;
11
+ };
12
+ stdout?: NodeJS.WritableStream;
13
+ cwd?: string;
14
+ templateDir?: string;
15
+ scaffold?: (options?: ScaffoldOptions) => ScaffoldResult;
16
+ }
17
+ export interface NormalizedCliIo {
18
+ out: (msg: string) => void;
19
+ err: (msg: string) => void;
20
+ exit: (code: number) => void | number;
21
+ stdin: NodeJS.ReadableStream & {
22
+ isTTY?: boolean;
23
+ };
24
+ stdout: NodeJS.WritableStream;
25
+ cwd: string;
26
+ templateDir: string;
27
+ scaffoldFn: (options?: ScaffoldOptions) => ScaffoldResult;
28
+ }
29
+ export declare function runCli(rawArgs?: string[], io?: CliIo): Promise<void | number>;
30
+ export declare function main(): Promise<void>;
31
+ export { askQuestion };
32
+ declare const _default: {
33
+ runCli: typeof runCli;
34
+ main: typeof main;
35
+ printHelp: typeof printHelp;
36
+ printVersion: typeof printVersion;
37
+ askQuestion: typeof askQuestion;
38
+ };
39
+ export default _default;
40
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGrE,OAAO,EAAE,WAAW,EAA0C,MAAM,iBAAiB,CAAC;AAatF,wBAAgB,SAAS,CAAC,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAkB,GAAG,IAAI,CAwBxE;AAED,wBAAgB,YAAY,CAAC,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAkB,GAAG,IAAI,CAE3E;AAED,MAAM,WAAW,KAAK;IACpB,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,GAAG;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,eAAe,KAAK,cAAc,CAAC;CAC1D;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC,cAAc,GAAG;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACnD,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE,eAAe,KAAK,cAAc,CAAC;CAC3D;AA6HD,wBAAsB,MAAM,CAC1B,OAAO,GAAE,MAAM,EAA0B,EACzC,EAAE,GAAE,KAAU,GACb,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAqBxB;AAED,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAO1C;AAED,OAAO,EAAE,WAAW,EAAE,CAAC;;;;;;;;AAEvB,wBAME"}
package/lib/cli.js ADDED
@@ -0,0 +1,166 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import process from 'node:process';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { scaffold, getTemplateDir } from './scaffold.js';
6
+ import { parseArgs } from './cli-parse.js';
7
+ import { askQuestion, resolveTargetDir, ensureWritableTarget } from './cli-target.js';
8
+ const pkg = JSON.parse(fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf-8'));
9
+ export function printHelp(out = console.log) {
10
+ out(`
11
+ azcodr v${pkg.version}
12
+ Enterprise Multi-Tenant Architecture & Agentic Engineering Starter Template
13
+
14
+ Usage:
15
+ npx azcodr [directory] [options]
16
+
17
+ Commands:
18
+ [directory] Scaffold azcodr template into directory (default: current directory)
19
+
20
+ Options:
21
+ -d, --dry-run Simulate scaffolding without modifying filesystem
22
+ -s, --silent Suppress console output messages
23
+ -f, --force Overwrite existing files in target directory without confirmation
24
+ --no-git Do not initialize a git repository
25
+ -v, --version Display version number
26
+ -h, --help Display this help message
27
+
28
+ Examples:
29
+ npx azcodr my-project
30
+ npx azcodr . --dry-run
31
+ npx azcodr . --force
32
+ `);
33
+ }
34
+ export function printVersion(out = console.log) {
35
+ out(pkg.version);
36
+ }
37
+ function normalizeIo(io = {}) {
38
+ const { out = console.log, err = console.error, exit = process.exit, stdin = process.stdin, stdout = process.stdout, cwd = process.cwd(), templateDir = getTemplateDir(), scaffold: scaffoldFn = scaffold } = io;
39
+ return { out, err, exit, stdin, stdout, cwd, templateDir, scaffoldFn };
40
+ }
41
+ function outBanner(fullIo) {
42
+ fullIo.out('\n🚀 azcodr - Enterprise Multi-Tenant Architecture & Agentic Engineering\n');
43
+ }
44
+ function handleTerminal(parsed, io) {
45
+ const { out, err, exit } = io;
46
+ if (parsed.terminal === 'help') {
47
+ printHelp(out);
48
+ return exit(0);
49
+ }
50
+ if (parsed.terminal === 'version') {
51
+ printVersion(out);
52
+ return exit(0);
53
+ }
54
+ err(`❌ Error: ${parsed.message}`);
55
+ return exit(1);
56
+ }
57
+ function reportDryRun(result, out) {
58
+ for (const action of result.actions) {
59
+ out(` [preview] ${action}`);
60
+ }
61
+ out('\n🎉 Dry run completed. 0 files modified on disk.\n');
62
+ }
63
+ function reportSuccess(result, targetDir, out) {
64
+ out(' ✅ Progressive disclosure rules copied (docs/rules/)');
65
+ out(' ✅ Workspace knowledge hub and ADR ledger copied (docs/knowledge/, memory.md)');
66
+ out(' ✅ Specialized agentic skills copied (.agents/skills/)');
67
+ out(' ✅ Editor formatting standards initialized (.editorconfig)');
68
+ out(' ✅ Agent directives and harness symlinks established (AGENTS.md, CLAUDE.md, agents.md, GEMINI.md, .cursorrules, .windsurfrules, .github/copilot-instructions.md)');
69
+ out(' ✅ Project configuration initialized (package.json)');
70
+ if (result.gitInitialized) {
71
+ out(' ✅ Git repository initialized');
72
+ }
73
+ out('\n🎉 azcodr initialized successfully!\n');
74
+ out('Next steps:');
75
+ let step = 1;
76
+ if (targetDir !== '.' && targetDir !== './') {
77
+ out(` ${step++}. cd ${targetDir}`);
78
+ }
79
+ out(` ${step++}. Open the project in your AI coding assistant (Antigravity, Claude Code, Cursor, OpenHands)`);
80
+ out(` ${step++}. Run /lets-build to start the architectural interview and scaffold your application stack!\n`);
81
+ }
82
+ function runScaffold(resolvedTarget, parsed, io) {
83
+ const { out, err, exit, templateDir, scaffoldFn } = io;
84
+ const banner = parsed.dryRun
85
+ ? `🔍 DRY RUN: Simulating azcodr scaffolding into: ${resolvedTarget}\n`
86
+ : `📦 Scaffolding azcodr into: ${resolvedTarget}`;
87
+ if (!parsed.silent)
88
+ out(banner);
89
+ try {
90
+ const result = scaffoldFn({
91
+ targetDir: resolvedTarget,
92
+ force: parsed.force,
93
+ noGit: parsed.noGit,
94
+ templateDir,
95
+ dryRun: parsed.dryRun,
96
+ silent: parsed.silent
97
+ });
98
+ if (!parsed.silent) {
99
+ if (parsed.dryRun)
100
+ reportDryRun(result, out);
101
+ else
102
+ reportSuccess(result, parsed.targetDir, out);
103
+ }
104
+ return exit(0);
105
+ }
106
+ catch (error) {
107
+ err(`\n❌ Scaffolding failed: ${error.message}\n`);
108
+ return exit(1);
109
+ }
110
+ }
111
+ async function resolvePhase(parsed, fullIo) {
112
+ const { resolvedTarget, chosen, error } = await resolveTargetDir(parsed.targetDir, fullIo);
113
+ if (error !== null) {
114
+ fullIo.err(`❌ Error: ${error}`);
115
+ return { exitCode: 1 };
116
+ }
117
+ return { resolvedTarget, chosen };
118
+ }
119
+ async function writablePhase(target, force, fullIo) {
120
+ const writable = await ensureWritableTarget({
121
+ chosen: target.chosen,
122
+ resolvedTarget: target.resolvedTarget,
123
+ force,
124
+ io: fullIo
125
+ });
126
+ if (writable.exitCode === undefined)
127
+ return { force: writable.force };
128
+ if (writable.message) {
129
+ fullIo.err(`❌ Error: ${writable.message}`);
130
+ }
131
+ return { exitCode: writable.exitCode };
132
+ }
133
+ export async function runCli(rawArgs = process.argv.slice(2), io = {}) {
134
+ const fullIo = normalizeIo(io);
135
+ const parsed = parseArgs(rawArgs);
136
+ if (parsed.terminal !== null)
137
+ return handleTerminal(parsed, fullIo);
138
+ if (!parsed.silent) {
139
+ outBanner(fullIo);
140
+ }
141
+ const target = await resolvePhase(parsed, fullIo);
142
+ if (target.exitCode !== undefined)
143
+ return fullIo.exit(target.exitCode);
144
+ const ready = await writablePhase(target, parsed.force, fullIo);
145
+ if (ready.exitCode !== undefined)
146
+ return fullIo.exit(ready.exitCode);
147
+ return runScaffold(target.resolvedTarget, { ...parsed, force: ready.force }, fullIo);
148
+ }
149
+ export async function main() {
150
+ try {
151
+ await runCli(process.argv.slice(2));
152
+ }
153
+ catch (err) {
154
+ console.error('Unexpected error:', err);
155
+ process.exit(1);
156
+ }
157
+ }
158
+ export { askQuestion };
159
+ export default {
160
+ runCli,
161
+ main,
162
+ printHelp,
163
+ printVersion,
164
+ askQuestion
165
+ };
166
+ //# sourceMappingURL=cli.js.map
package/lib/cli.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Machine-readable failure codes.
3
+ *
4
+ * Consumers branch on `err.code`, never on message text: a wording change must
5
+ * never be a breaking change (learned from typed-settings, where `docs/errors.md`
6
+ * explicitly tells users not to regex the message). Pinned by
7
+ * tests/error-codes.test.js.
8
+ */
9
+ export declare const ERROR_CODES: {
10
+ readonly E_TARGET_IS_TEMPLATE: "Cannot scaffold into the azcodr template directory itself";
11
+ readonly E_TARGET_NOT_EMPTY: "Target directory is not empty";
12
+ readonly E_TARGET_IS_PROTECTED: "Refusing to scaffold into a protected system directory";
13
+ readonly E_GIT_ARGS_INVALID: "runGit requires a non-empty argv array";
14
+ readonly E_GIT_BLOCKED: "Blocked git subcommand";
15
+ readonly E_PATH_ESCAPE: "Path escapes allowed root";
16
+ };
17
+ export type ScaffoldErrorCode = keyof typeof ERROR_CODES;
18
+ export interface ScaffoldErrorShape extends Error {
19
+ name: 'ScaffoldError';
20
+ code: ScaffoldErrorCode;
21
+ }
22
+ export declare class ScaffoldError extends Error implements ScaffoldErrorShape {
23
+ readonly name: 'ScaffoldError';
24
+ readonly code: ScaffoldErrorCode;
25
+ constructor(code: ScaffoldErrorCode, message: string);
26
+ }
27
+ declare const _default: {
28
+ ERROR_CODES: {
29
+ readonly E_TARGET_IS_TEMPLATE: "Cannot scaffold into the azcodr template directory itself";
30
+ readonly E_TARGET_NOT_EMPTY: "Target directory is not empty";
31
+ readonly E_TARGET_IS_PROTECTED: "Refusing to scaffold into a protected system directory";
32
+ readonly E_GIT_ARGS_INVALID: "runGit requires a non-empty argv array";
33
+ readonly E_GIT_BLOCKED: "Blocked git subcommand";
34
+ readonly E_PATH_ESCAPE: "Path escapes allowed root";
35
+ };
36
+ ScaffoldError: typeof ScaffoldError;
37
+ };
38
+ export default _default;
39
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;;;;;;;CAOd,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,WAAW,CAAC;AAEzD,MAAM,WAAW,kBAAmB,SAAQ,KAAK;IAC/C,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAED,qBAAa,aAAc,SAAQ,KAAM,YAAW,kBAAkB;IACpE,SAAkB,IAAI,EAAE,eAAe,CAAmB;IAC1D,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;gBAErB,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM;CAIrD;;;;;;;;;;;;AAED,wBAA8C"}
package/lib/errors.js ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Machine-readable failure codes.
3
+ *
4
+ * Consumers branch on `err.code`, never on message text: a wording change must
5
+ * never be a breaking change (learned from typed-settings, where `docs/errors.md`
6
+ * explicitly tells users not to regex the message). Pinned by
7
+ * tests/error-codes.test.js.
8
+ */
9
+ export const ERROR_CODES = {
10
+ E_TARGET_IS_TEMPLATE: 'Cannot scaffold into the azcodr template directory itself',
11
+ E_TARGET_NOT_EMPTY: 'Target directory is not empty',
12
+ E_TARGET_IS_PROTECTED: 'Refusing to scaffold into a protected system directory',
13
+ E_GIT_ARGS_INVALID: 'runGit requires a non-empty argv array',
14
+ E_GIT_BLOCKED: 'Blocked git subcommand',
15
+ E_PATH_ESCAPE: 'Path escapes allowed root'
16
+ };
17
+ export class ScaffoldError extends Error {
18
+ name = 'ScaffoldError';
19
+ code;
20
+ constructor(code, message) {
21
+ super(message);
22
+ this.code = code;
23
+ }
24
+ }
25
+ export default { ERROR_CODES, ScaffoldError };
26
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,oBAAoB,EAAE,2DAA2D;IACjF,kBAAkB,EAAE,+BAA+B;IACnD,qBAAqB,EAAE,wDAAwD;IAC/E,kBAAkB,EAAE,wCAAwC;IAC5D,aAAa,EAAE,wBAAwB;IACvC,aAAa,EAAE,2BAA2B;CAClC,CAAC;AASX,MAAM,OAAO,aAAc,SAAQ,KAAK;IACpB,IAAI,GAAoB,eAAe,CAAC;IACjD,IAAI,CAAoB;IAEjC,YAAY,IAAuB,EAAE,OAAe;QAClD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC"}
package/lib/git.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import cp from 'node:child_process';
2
+ /**
3
+ * Socket-hardened process boundary (Supply Chain: shell access).
4
+ * Scaffolder must spawn `git`, but never via a shell string.
5
+ * Uses execFileSync with argv (shell:false) and an explicit subcommand allowlist.
6
+ * No network, no env exfiltration; cwd is constrained to targetDir callers.
7
+ */
8
+ export declare const GIT_ALLOWED_SUBCOMMANDS: Set<string>;
9
+ export declare function runGit(args: string[], options?: cp.ExecFileSyncOptions): string;
10
+ declare const _default: {
11
+ GIT_ALLOWED_SUBCOMMANDS: Set<string>;
12
+ runGit: typeof runGit;
13
+ };
14
+ export default _default;
15
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAGpC;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,aAMlC,CAAC;AAEH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,EAAE,CAAC,mBAAwB,GAAG,MAAM,CAcnF;;;;;AAED,wBAAmD"}
package/lib/git.js ADDED
@@ -0,0 +1,32 @@
1
+ import cp from 'node:child_process';
2
+ import { ScaffoldError, ERROR_CODES } from './errors.js';
3
+ /**
4
+ * Socket-hardened process boundary (Supply Chain: shell access).
5
+ * Scaffolder must spawn `git`, but never via a shell string.
6
+ * Uses execFileSync with argv (shell:false) and an explicit subcommand allowlist.
7
+ * No network, no env exfiltration; cwd is constrained to targetDir callers.
8
+ */
9
+ export const GIT_ALLOWED_SUBCOMMANDS = new Set([
10
+ 'rev-parse',
11
+ 'init',
12
+ 'branch',
13
+ 'add',
14
+ 'commit'
15
+ ]);
16
+ export function runGit(args, options = {}) {
17
+ if (!Array.isArray(args) || args.length === 0) {
18
+ throw new ScaffoldError('E_GIT_ARGS_INVALID', ERROR_CODES.E_GIT_ARGS_INVALID);
19
+ }
20
+ const subcommand = args[0];
21
+ if (!subcommand || !GIT_ALLOWED_SUBCOMMANDS.has(subcommand)) {
22
+ throw new ScaffoldError('E_GIT_BLOCKED', `${ERROR_CODES.E_GIT_BLOCKED}: ${String(subcommand)}`);
23
+ }
24
+ return cp.execFileSync('git', args, {
25
+ encoding: 'utf-8',
26
+ stdio: 'pipe',
27
+ shell: false,
28
+ ...options
29
+ });
30
+ }
31
+ export default { GIT_ALLOWED_SUBCOMMANDS, runGit };
32
+ //# sourceMappingURL=git.js.map
package/lib/git.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC;IAC7C,WAAW;IACX,MAAM;IACN,QAAQ;IACR,KAAK;IACL,QAAQ;CACT,CAAC,CAAC;AAEH,MAAM,UAAU,MAAM,CAAC,IAAc,EAAE,UAAkC,EAAE;IACzE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,aAAa,CAAC,oBAAoB,EAAE,WAAW,CAAC,kBAAkB,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,UAAU,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,aAAa,CAAC,eAAe,EAAE,GAAG,WAAW,CAAC,aAAa,KAAK,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAClG,CAAC;IACD,OAAO,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE;QAClC,QAAQ,EAAE,OAAO;QACjB,KAAK,EAAE,MAAM;QACb,KAAK,EAAE,KAAK;QACZ,GAAG,OAAO;KACX,CAAW,CAAC;AACf,CAAC;AAED,eAAe,EAAE,uBAAuB,EAAE,MAAM,EAAE,CAAC"}
@@ -0,0 +1,35 @@
1
+ export interface ProtectedTargetOptions {
2
+ templateDir?: string;
3
+ force?: boolean;
4
+ dryRun?: boolean;
5
+ allowProtected?: boolean;
6
+ }
7
+ /**
8
+ * Filesystem scope guard (Supply Chain: filesystem access).
9
+ * Constrains all reads/writes to targetDir / templateDir.
10
+ */
11
+ export declare function assertInside(root: string, candidate: string, message?: string): void;
12
+ /**
13
+ * Normalizes a path for protected-target comparison. On Windows the filesystem
14
+ * is case-insensitive, so `C:\Users\Name` and `c:\users\name` are the same
15
+ * directory and must compare equal.
16
+ */
17
+ export declare function normalizeForComparison(p: string): string;
18
+ /**
19
+ * Returns true when `targetDir` is a location the scaffolder must never write
20
+ * into: the filesystem root, the user's home directory, the home directory's
21
+ * parent (e.g. /home, C:\Users -- scaffolding there affects every user), or an
22
+ * ancestor of the template itself (scaffolding into D:\projects would merge
23
+ * the template into its own parent).
24
+ *
25
+ * Lexical comparison is not enough: a symlink pointing at home must also be
26
+ * caught, so an existing target is resolved with realpath before comparing.
27
+ */
28
+ export declare function isProtectedTarget(targetDir: string, options?: ProtectedTargetOptions): boolean;
29
+ declare const _default: {
30
+ assertInside: typeof assertInside;
31
+ normalizeForComparison: typeof normalizeForComparison;
32
+ isProtectedTarget: typeof isProtectedTarget;
33
+ };
34
+ export default _default;
35
+ //# sourceMappingURL=guards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAOpF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAGxD;AAwCD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CASlG;;;;;;AAED,wBAIE"}