azcodr 2.0.0 → 2.2.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/.agents/hooks.json +3 -3
- package/.github/workflows/ci.yml +1 -0
- package/.github/workflows/publish.yml +0 -4
- package/AGENTS.md +1 -1
- package/bin/azcodr.js +11 -4
- package/lib/cli-parse.d.ts +32 -0
- package/lib/cli-parse.d.ts.map +1 -0
- package/lib/cli-parse.js +45 -41
- package/lib/cli-parse.js.map +1 -0
- package/lib/cli-target.d.ts +66 -0
- package/lib/cli-target.d.ts.map +1 -0
- package/lib/cli-target.js +89 -96
- package/lib/cli-target.js.map +1 -0
- package/lib/cli.d.ts +40 -0
- package/lib/cli.d.ts.map +1 -0
- package/lib/cli.js +122 -136
- package/lib/cli.js.map +1 -0
- package/lib/errors.d.ts +54 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +25 -18
- package/lib/errors.js.map +1 -0
- package/lib/git.d.ts +23 -0
- package/lib/git.d.ts.map +1 -0
- package/lib/git.js +33 -22
- package/lib/git.js.map +1 -0
- package/lib/guards.d.ts +50 -0
- package/lib/guards.d.ts.map +1 -0
- package/lib/guards.js +75 -64
- package/lib/guards.js.map +1 -0
- package/lib/index.d.ts +14 -188
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +17 -5
- package/lib/index.js.map +1 -0
- package/lib/links.d.ts +42 -0
- package/lib/links.d.ts.map +1 -0
- package/lib/links.js +116 -99
- package/lib/links.js.map +1 -0
- package/lib/permissions.d.ts +13 -0
- package/lib/permissions.d.ts.map +1 -0
- package/lib/permissions.js +40 -36
- package/lib/permissions.js.map +1 -0
- package/lib/repo.d.ts +30 -0
- package/lib/repo.d.ts.map +1 -0
- package/lib/repo.js +80 -71
- package/lib/repo.js.map +1 -0
- package/lib/scaffold.d.ts +109 -0
- package/lib/scaffold.d.ts.map +1 -0
- package/lib/scaffold.js +165 -197
- package/lib/scaffold.js.map +1 -0
- package/memory.md +24 -0
- package/package.json +14 -5
- package/scripts/validate/adr.js +11 -7
- package/scripts/validate/io.js +7 -9
- package/scripts/validate/links.js +6 -7
- package/scripts/validate/parity.js +5 -7
- package/scripts/validate/root.js +6 -7
- package/scripts/validate/rules.js +7 -9
- package/scripts/validate/skills.js +8 -10
- package/scripts/validate/text.js +3 -5
- package/scripts/validate-cli.js +1 -2
- package/scripts/validate.js +37 -19
- package/src/cli-parse.ts +77 -0
- package/src/cli-target.ts +167 -0
- package/src/cli.ts +240 -0
- package/src/errors.ts +50 -0
- package/src/git.ts +42 -0
- package/src/guards.ts +116 -0
- package/src/index.ts +60 -0
- package/src/links.ts +153 -0
- package/src/permissions.ts +46 -0
- package/src/repo.ts +104 -0
- package/src/scaffold.ts +282 -0
- package/scripts/test_coverage.js +0 -66
package/lib/cli.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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(`
|
|
10
11
|
azcodr v${pkg.version}
|
|
11
12
|
Enterprise Multi-Tenant Architecture & Agentic Engineering Starter Template
|
|
12
13
|
|
|
@@ -30,151 +31,136 @@ Examples:
|
|
|
30
31
|
npx azcodr . --force
|
|
31
32
|
`);
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
out(pkg.version);
|
|
34
|
+
export function printVersion(out = console.log) {
|
|
35
|
+
out(pkg.version);
|
|
36
36
|
}
|
|
37
|
-
|
|
38
37
|
function normalizeIo(io = {}) {
|
|
39
|
-
|
|
40
|
-
out
|
|
41
|
-
err = console.error,
|
|
42
|
-
exit = process.exit,
|
|
43
|
-
stdin = process.stdin,
|
|
44
|
-
stdout = process.stdout,
|
|
45
|
-
cwd = process.cwd(),
|
|
46
|
-
templateDir = getTemplateDir(),
|
|
47
|
-
scaffold: scaffoldFn = scaffold
|
|
48
|
-
} = io;
|
|
49
|
-
return { out, err, exit, stdin, stdout, cwd, templateDir, scaffoldFn };
|
|
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 };
|
|
50
40
|
}
|
|
51
|
-
|
|
52
41
|
function outBanner(fullIo) {
|
|
53
|
-
|
|
42
|
+
fullIo.out('\n🚀 azcodr - Enterprise Multi-Tenant Architecture & Agentic Engineering\n');
|
|
54
43
|
}
|
|
55
|
-
|
|
56
44
|
function handleTerminal(parsed, io) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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);
|
|
68
56
|
}
|
|
69
|
-
|
|
70
57
|
function reportDryRun(result, out) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
58
|
+
for (const action of result.actions) {
|
|
59
|
+
out(` [preview] ${action}`);
|
|
60
|
+
}
|
|
61
|
+
out('\n🎉 Dry run completed. 0 files modified on disk.\n');
|
|
75
62
|
}
|
|
76
|
-
|
|
77
63
|
function reportSuccess(result, targetDir, out) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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`);
|
|
95
81
|
}
|
|
96
|
-
|
|
97
82
|
function runScaffold(resolvedTarget, parsed, io) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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);
|
|
115
109
|
}
|
|
116
|
-
return exit(0);
|
|
117
|
-
} catch (error) {
|
|
118
|
-
err(`\n❌ Scaffolding failed: ${error.message}\n`);
|
|
119
|
-
return exit(1);
|
|
120
|
-
}
|
|
121
110
|
}
|
|
122
|
-
|
|
123
111
|
async function resolvePhase(parsed, fullIo) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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 };
|
|
130
118
|
}
|
|
131
|
-
|
|
132
119
|
async function writablePhase(target, force, fullIo) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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 };
|
|
144
132
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (ready.exitCode !== undefined) return fullIo.exit(ready.exitCode);
|
|
161
|
-
|
|
162
|
-
return runScaffold(target.resolvedTarget, { ...parsed, force: ready.force }, fullIo);
|
|
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);
|
|
163
148
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
+
}
|
|
172
157
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
158
|
+
export { askQuestion };
|
|
159
|
+
export default {
|
|
160
|
+
runCli,
|
|
161
|
+
main,
|
|
162
|
+
printHelp,
|
|
163
|
+
printVersion,
|
|
164
|
+
askQuestion
|
|
180
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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"}
|
package/lib/errors.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
/**
|
|
18
|
+
* Union of valid machine-readable error codes for scaffolding failures.
|
|
19
|
+
*/
|
|
20
|
+
export type ScaffoldErrorCode = keyof typeof ERROR_CODES;
|
|
21
|
+
/**
|
|
22
|
+
* Structural interface contract for errors thrown by the scaffolder.
|
|
23
|
+
*/
|
|
24
|
+
export interface ScaffoldErrorShape extends Error {
|
|
25
|
+
name: 'ScaffoldError';
|
|
26
|
+
code: ScaffoldErrorCode;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Custom error class thrown by scaffolding operations, carrying a machine-readable code.
|
|
30
|
+
*/
|
|
31
|
+
export declare class ScaffoldError extends Error implements ScaffoldErrorShape {
|
|
32
|
+
readonly name: 'ScaffoldError';
|
|
33
|
+
readonly code: ScaffoldErrorCode;
|
|
34
|
+
/**
|
|
35
|
+
* Constructs a new ScaffoldError instance.
|
|
36
|
+
*
|
|
37
|
+
* @param code - Machine-readable error code.
|
|
38
|
+
* @param message - Human-readable explanation of the error.
|
|
39
|
+
*/
|
|
40
|
+
constructor(code: ScaffoldErrorCode, message: string);
|
|
41
|
+
}
|
|
42
|
+
declare const _default: {
|
|
43
|
+
ERROR_CODES: {
|
|
44
|
+
readonly E_TARGET_IS_TEMPLATE: "Cannot scaffold into the azcodr template directory itself";
|
|
45
|
+
readonly E_TARGET_NOT_EMPTY: "Target directory is not empty";
|
|
46
|
+
readonly E_TARGET_IS_PROTECTED: "Refusing to scaffold into a protected system directory";
|
|
47
|
+
readonly E_GIT_ARGS_INVALID: "runGit requires a non-empty argv array";
|
|
48
|
+
readonly E_GIT_BLOCKED: "Blocked git subcommand";
|
|
49
|
+
readonly E_PATH_ESCAPE: "Path escapes allowed root";
|
|
50
|
+
};
|
|
51
|
+
ScaffoldError: typeof ScaffoldError;
|
|
52
|
+
};
|
|
53
|
+
export default _default;
|
|
54
|
+
//# 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;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,WAAW,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,kBAAmB,SAAQ,KAAK;IAC/C,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAM,YAAW,kBAAkB;IACpE,SAAkB,IAAI,EAAE,eAAe,CAAmB;IAC1D,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IAEjC;;;;;OAKG;gBACS,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM;CAIrD;;;;;;;;;;;;AAED,wBAA8C"}
|
package/lib/errors.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Machine-readable failure codes.
|
|
5
3
|
*
|
|
@@ -8,21 +6,30 @@
|
|
|
8
6
|
* explicitly tells users not to regex the message). Pinned by
|
|
9
7
|
* tests/error-codes.test.js.
|
|
10
8
|
*/
|
|
11
|
-
const ERROR_CODES = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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'
|
|
18
16
|
};
|
|
19
|
-
|
|
20
|
-
class
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Custom error class thrown by scaffolding operations, carrying a machine-readable code.
|
|
19
|
+
*/
|
|
20
|
+
export class ScaffoldError extends Error {
|
|
21
|
+
name = 'ScaffoldError';
|
|
22
|
+
code;
|
|
23
|
+
/**
|
|
24
|
+
* Constructs a new ScaffoldError instance.
|
|
25
|
+
*
|
|
26
|
+
* @param code - Machine-readable error code.
|
|
27
|
+
* @param message - Human-readable explanation of the error.
|
|
28
|
+
*/
|
|
29
|
+
constructor(code, message) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.code = code;
|
|
32
|
+
}
|
|
26
33
|
}
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
export default { ERROR_CODES, ScaffoldError };
|
|
35
|
+
//# 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;AAeX;;GAEG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACpB,IAAI,GAAoB,eAAe,CAAC;IACjD,IAAI,CAAoB;IAEjC;;;;;OAKG;IACH,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,23 @@
|
|
|
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
|
+
/**
|
|
10
|
+
* Safely executes an allowlisted git subcommand using execFileSync with an argument array and shell disabled.
|
|
11
|
+
*
|
|
12
|
+
* @param args - Subcommand and arguments array to pass to git.
|
|
13
|
+
* @param options - Child process execution options.
|
|
14
|
+
* @returns Standard output from git as a string.
|
|
15
|
+
* @throws {ScaffoldError} When args is empty or the subcommand is not in GIT_ALLOWED_SUBCOMMANDS.
|
|
16
|
+
*/
|
|
17
|
+
export declare function runGit(args: string[], options?: cp.ExecFileSyncOptions): string;
|
|
18
|
+
declare const _default: {
|
|
19
|
+
GIT_ALLOWED_SUBCOMMANDS: Set<string>;
|
|
20
|
+
runGit: typeof runGit;
|
|
21
|
+
};
|
|
22
|
+
export default _default;
|
|
23
|
+
//# sourceMappingURL=git.d.ts.map
|
package/lib/git.d.ts.map
ADDED
|
@@ -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;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,EAAE,CAAC,mBAAwB,GAAG,MAAM,CAcnF;;;;;AAED,wBAAmD"}
|
package/lib/git.js
CHANGED
|
@@ -1,29 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const cp = require('node:child_process');
|
|
4
|
-
const { ScaffoldError, ERROR_CODES } = require('./errors.js');
|
|
5
|
-
|
|
1
|
+
import cp from 'node:child_process';
|
|
2
|
+
import { ScaffoldError, ERROR_CODES } from './errors.js';
|
|
6
3
|
/**
|
|
7
4
|
* Socket-hardened process boundary (Supply Chain: shell access).
|
|
8
5
|
* Scaffolder must spawn `git`, but never via a shell string.
|
|
9
6
|
* Uses execFileSync with argv (shell:false) and an explicit subcommand allowlist.
|
|
10
7
|
* No network, no env exfiltration; cwd is constrained to targetDir callers.
|
|
11
8
|
*/
|
|
12
|
-
const GIT_ALLOWED_SUBCOMMANDS = new Set([
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
9
|
+
export const GIT_ALLOWED_SUBCOMMANDS = new Set([
|
|
10
|
+
'rev-parse',
|
|
11
|
+
'init',
|
|
12
|
+
'branch',
|
|
13
|
+
'add',
|
|
14
|
+
'commit'
|
|
15
|
+
]);
|
|
16
|
+
/**
|
|
17
|
+
* Safely executes an allowlisted git subcommand using execFileSync with an argument array and shell disabled.
|
|
18
|
+
*
|
|
19
|
+
* @param args - Subcommand and arguments array to pass to git.
|
|
20
|
+
* @param options - Child process execution options.
|
|
21
|
+
* @returns Standard output from git as a string.
|
|
22
|
+
* @throws {ScaffoldError} When args is empty or the subcommand is not in GIT_ALLOWED_SUBCOMMANDS.
|
|
23
|
+
*/
|
|
24
|
+
export function runGit(args, options = {}) {
|
|
25
|
+
if (!Array.isArray(args) || args.length === 0) {
|
|
26
|
+
throw new ScaffoldError('E_GIT_ARGS_INVALID', ERROR_CODES.E_GIT_ARGS_INVALID);
|
|
27
|
+
}
|
|
28
|
+
const subcommand = args[0];
|
|
29
|
+
if (!subcommand || !GIT_ALLOWED_SUBCOMMANDS.has(subcommand)) {
|
|
30
|
+
throw new ScaffoldError('E_GIT_BLOCKED', `${ERROR_CODES.E_GIT_BLOCKED}: ${String(subcommand)}`);
|
|
31
|
+
}
|
|
32
|
+
return cp.execFileSync('git', args, {
|
|
33
|
+
encoding: 'utf-8',
|
|
34
|
+
stdio: 'pipe',
|
|
35
|
+
shell: false,
|
|
36
|
+
...options
|
|
37
|
+
});
|
|
27
38
|
}
|
|
28
|
-
|
|
29
|
-
|
|
39
|
+
export default { GIT_ALLOWED_SUBCOMMANDS, runGit };
|
|
40
|
+
//# 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;;;;;;;GAOG;AACH,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"}
|
package/lib/guards.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for configuring protected target verification.
|
|
3
|
+
*/
|
|
4
|
+
export interface ProtectedTargetOptions {
|
|
5
|
+
templateDir?: string;
|
|
6
|
+
force?: boolean;
|
|
7
|
+
dryRun?: boolean;
|
|
8
|
+
allowProtected?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Filesystem scope guard (Supply Chain: filesystem access).
|
|
12
|
+
* Constrains all reads/writes to targetDir / templateDir, throwing if candidate escapes root.
|
|
13
|
+
*
|
|
14
|
+
* @param root - Absolute base directory.
|
|
15
|
+
* @param candidate - Candidate file or directory path to check.
|
|
16
|
+
* @param message - Optional custom error message.
|
|
17
|
+
* @throws {ScaffoldError} When candidate path escapes root directory.
|
|
18
|
+
*/
|
|
19
|
+
export declare function assertInside(root: string, candidate: string, message?: string): void;
|
|
20
|
+
/**
|
|
21
|
+
* Normalizes a path for protected-target comparison. On Windows the filesystem
|
|
22
|
+
* is case-insensitive, so `C:\Users\Name` and `c:\users\name` are the same
|
|
23
|
+
* directory and must compare equal.
|
|
24
|
+
*
|
|
25
|
+
* @param p - File or directory path to normalize.
|
|
26
|
+
* @returns Normalized path string.
|
|
27
|
+
*/
|
|
28
|
+
export declare function normalizeForComparison(p: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Returns true when `targetDir` is a location the scaffolder must never write
|
|
31
|
+
* into: the filesystem root, the user's home directory, the home directory's
|
|
32
|
+
* parent (e.g. /home, C:\Users -- scaffolding there affects every user), or an
|
|
33
|
+
* ancestor of the template itself (scaffolding into D:\projects would merge
|
|
34
|
+
* the template into its own parent).
|
|
35
|
+
*
|
|
36
|
+
* Lexical comparison is not enough: a symlink pointing at home must also be
|
|
37
|
+
* caught, so an existing target is resolved with realpath before comparing.
|
|
38
|
+
*
|
|
39
|
+
* @param targetDir - The target directory path to evaluate.
|
|
40
|
+
* @param options - Optional configuration for protected target evaluation.
|
|
41
|
+
* @returns True if target is a protected location, false otherwise.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isProtectedTarget(targetDir: string, options?: ProtectedTargetOptions): boolean;
|
|
44
|
+
declare const _default: {
|
|
45
|
+
assertInside: typeof assertInside;
|
|
46
|
+
normalizeForComparison: typeof normalizeForComparison;
|
|
47
|
+
isProtectedTarget: typeof isProtectedTarget;
|
|
48
|
+
};
|
|
49
|
+
export default _default;
|
|
50
|
+
//# sourceMappingURL=guards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,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;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAOpF;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAGxD;AAwCD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CASlG;;;;;;AAED,wBAIE"}
|