create-justscale 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 JustScale
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # create-justscale
2
+
3
+ Project scaffolder for `pnpm create justscale` / `npm create justscale@latest` / `yarn create justscale`. Interactive prompt, detects your environment (OS, package manager, installed IDEs, AI tools, git hosting), then writes a minimal JustScale app with matching IDE + CI config.
4
+
5
+ Not a package you import — it's a CLI. Run it to bootstrap a new project.
6
+
7
+ ## Usage
8
+
9
+ ```bash
10
+ pnpm create justscale
11
+ # or
12
+ npm create justscale@latest
13
+ # or
14
+ yarn create justscale
15
+ ```
16
+
17
+ You can also invoke it directly:
18
+
19
+ ```bash
20
+ pnpm dlx create-justscale
21
+ ```
22
+
23
+ The CLI asks for a project name (default: current directory name). If the name matches the current directory, it scaffolds in place; otherwise it creates a subdirectory. It refuses to run in a directory that already has a `package.json` — use `just init` for that case.
24
+
25
+ ## What gets generated
26
+
27
+ Always:
28
+
29
+ - `package.json` with `@justscale/core` and `@justscale/typescript` pinned
30
+ - `tsconfig.json` (NodeNext, ES2022, strict)
31
+ - `justscale.config.ts` with `defineProject` and `serve` / `cli` mode entries
32
+ - `src/app.ts`, `src/serve.ts`, `src/cli.ts` stubs
33
+ - `.gitignore`
34
+
35
+ Based on detected environment:
36
+
37
+ - JetBrains IDE (WebStorm / IntelliJ): `.idea/typescript.xml` pointing at `@justscale/typescript`'s tsserver, plus `just dev` / `just build` / `just test` run configurations.
38
+ - VS Code / Cursor: `.vscode/settings.json` with `typescript.tsdk` pointed at the workspace JustScale TypeScript, plus a `launch.json` for `just dev`.
39
+ - Claude CLI on PATH: `.claude/settings.json` wiring the JustScale MCP server (`just mcp serve`) and a starter `CLAUDE.md`.
40
+ - GitHub remote: `.github/workflows/ci.yml` matching the detected package manager.
41
+ - GitLab remote: `.gitlab-ci.yml` equivalent.
42
+
43
+ After scaffolding, the CLI runs `<pm> install`, initialises git, and optionally opens your detected editor / Claude session.
44
+
45
+ ## Detection
46
+
47
+ Detection is best-effort and purely read-only:
48
+
49
+ - **OS / arch** from `process.platform`
50
+ - **Package manager** via `which pnpm` / `yarn` (falls back to `npm`)
51
+ - **IDEs** by scanning app locations on macOS/Linux plus `code` / `cursor` on PATH
52
+ - **AI tools** by `claude` / `cursor` on PATH
53
+ - **Git hosting** from `.git/config` (github.com, gitlab.com)
54
+
55
+ No network calls, no telemetry.
56
+
57
+ ## Starter app shape
58
+
59
+ The generated `app.ts` is intentionally empty — a `JustScale()` builder with comments showing where to `.add(...)` services / features:
60
+
61
+ ```ts
62
+ import JustScale from '@justscale/core'
63
+
64
+ export const app = JustScale()
65
+ // Add services, features, and adapters here
66
+ // .add(PostgresClient)
67
+ // .add(AuthFeature)
68
+ ```
69
+
70
+ `serve.ts` and `cli.ts` each `.build()` it for their respective modes; `justscale.config.ts` wires the modes together. From there you follow the docs to add controllers, features, and an adapter.
71
+
72
+ ## Next steps
73
+
74
+ ```bash
75
+ cd your-project-name
76
+ just dev # boots the app
77
+ just install <plugin> # installs and wires a JustScale plugin
78
+ ```
79
+
80
+ ## Docs
81
+
82
+ https://justscale.sh/overview/quick-start
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { main } from '../dist/index.js';
3
+ main();
@@ -0,0 +1,11 @@
1
+ export interface SystemInfo {
2
+ os: 'macos' | 'linux' | 'windows';
3
+ arch: string;
4
+ nodeVersion: string;
5
+ packageManager: 'pnpm' | 'yarn' | 'npm';
6
+ ides: ('jetbrains' | 'vscode' | 'cursor')[];
7
+ aiTools: ('claude' | 'cursor')[];
8
+ gitHosting: 'github' | 'gitlab' | null;
9
+ }
10
+ export declare function detectSystem(projectRoot: string): SystemInfo;
11
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAAA;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAA;IACvC,IAAI,EAAE,CAAC,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC,EAAE,CAAA;IAC3C,OAAO,EAAE,CAAC,QAAQ,GAAG,QAAQ,CAAC,EAAE,CAAA;IAChC,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAA;CACvC;AAYD,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,CAgD5D"}
package/dist/detect.js ADDED
@@ -0,0 +1,68 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ function which(bin) {
5
+ try {
6
+ const cmd = process.platform === 'win32' ? `where.exe ${bin}` : `which ${bin}`;
7
+ execSync(cmd, { stdio: 'ignore' });
8
+ return true;
9
+ }
10
+ catch {
11
+ return false;
12
+ }
13
+ }
14
+ export function detectSystem(projectRoot) {
15
+ const ides = [];
16
+ const aiTools = [];
17
+ // IDE detection
18
+ if (process.platform === 'darwin') {
19
+ if (existsSync(join(process.env.HOME ?? '', 'Library/Application Support/JetBrains/Toolbox')) ||
20
+ existsSync('/Applications/WebStorm.app') ||
21
+ existsSync('/Applications/IntelliJ IDEA.app')) {
22
+ ides.push('jetbrains');
23
+ }
24
+ }
25
+ else if (existsSync(join(process.env.HOME ?? '', '.local/share/JetBrains/Toolbox'))) {
26
+ ides.push('jetbrains');
27
+ }
28
+ if (which('code') || which('code-insiders'))
29
+ ides.push('vscode');
30
+ if (which('cursor'))
31
+ ides.push('cursor');
32
+ // AI tools
33
+ if (which('claude'))
34
+ aiTools.push('claude');
35
+ if (which('cursor'))
36
+ aiTools.push('cursor');
37
+ // Git hosting
38
+ let gitHosting = null;
39
+ const gitConfigPath = join(projectRoot, '.git', 'config');
40
+ if (existsSync(gitConfigPath)) {
41
+ try {
42
+ const config = readFileSync(gitConfigPath, 'utf-8');
43
+ if (config.includes('github.com'))
44
+ gitHosting = 'github';
45
+ else if (config.includes('gitlab.com'))
46
+ gitHosting = 'gitlab';
47
+ }
48
+ catch {
49
+ /* optional - unreadable git config means unknown hosting */
50
+ }
51
+ }
52
+ // Package manager
53
+ let packageManager = 'npm';
54
+ if (which('pnpm'))
55
+ packageManager = 'pnpm';
56
+ else if (which('yarn'))
57
+ packageManager = 'yarn';
58
+ return {
59
+ os: process.platform === 'darwin' ? 'macos' : process.platform === 'win32' ? 'windows' : 'linux',
60
+ arch: process.arch,
61
+ nodeVersion: process.version,
62
+ packageManager,
63
+ ides,
64
+ aiTools,
65
+ gitHosting,
66
+ };
67
+ }
68
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @justscale/install - project scaffolder
3
+ *
4
+ * Usage: npx @justscale/install
5
+ * pnpm dlx @justscale/install
6
+ */
7
+ export declare function main(): Promise<void>;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA+BH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ1C"}
package/dist/index.js ADDED
@@ -0,0 +1,157 @@
1
+ /**
2
+ * @justscale/install - project scaffolder
3
+ *
4
+ * Usage: npx @justscale/install
5
+ * pnpm dlx @justscale/install
6
+ */
7
+ import { createInterface } from 'node:readline';
8
+ import { execSync, execFileSync } from 'node:child_process';
9
+ import { basename, join, resolve, sep } from 'node:path';
10
+ import { existsSync, readdirSync } from 'node:fs';
11
+ import { detectSystem } from './detect.js';
12
+ import { scaffoldProject } from './scaffold.js';
13
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
14
+ function ask(question, defaultValue) {
15
+ const prompt = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
16
+ return new Promise((resolve) => {
17
+ rl.question(prompt, (answer) => {
18
+ resolve(answer.trim() || defaultValue || '');
19
+ });
20
+ });
21
+ }
22
+ function confirm(question, defaultYes = false) {
23
+ const hint = defaultYes ? '[Y/n]' : '[y/N]';
24
+ return new Promise((resolve) => {
25
+ rl.question(`${question} ${hint}: `, (answer) => {
26
+ const a = answer.trim().toLowerCase();
27
+ if (a === '')
28
+ resolve(defaultYes);
29
+ else
30
+ resolve(a === 'y' || a === 'yes');
31
+ });
32
+ });
33
+ }
34
+ export async function main() {
35
+ console.log('\n JustScale - Project Setup\n');
36
+ try {
37
+ await run();
38
+ }
39
+ finally {
40
+ rl.close();
41
+ }
42
+ }
43
+ async function run() {
44
+ const cwd = process.cwd();
45
+ const system = detectSystem(cwd);
46
+ console.log(' Detected:');
47
+ console.log(` OS: ${system.os} (${system.arch})`);
48
+ console.log(` Node: ${system.nodeVersion}`);
49
+ console.log(` Package manager: ${system.packageManager}`);
50
+ console.log(` IDEs: ${system.ides.length ? system.ides.join(', ') : 'none detected'}`);
51
+ console.log(` AI tools: ${system.aiTools.length ? system.aiTools.join(', ') : 'none detected'}`);
52
+ console.log(` Git hosting: ${system.gitHosting ?? 'not detected'}`);
53
+ console.log('');
54
+ const defaultName = basename(cwd) === '.' ? 'my-app' : basename(cwd);
55
+ const projectName = await ask(' Project name', defaultName);
56
+ // If the project name matches the current directory name, scaffold here. Otherwise create a subdirectory.
57
+ const scaffoldInPlace = projectName === basename(cwd);
58
+ const projectDir = scaffoldInPlace ? cwd : resolve(cwd, projectName);
59
+ // Refuse to scaffold outside cwd. Catches malicious or accidental project
60
+ // names like '../etc' or absolute paths.
61
+ if (!scaffoldInPlace && !projectDir.startsWith(cwd + sep)) {
62
+ console.log(`\n Project name "${projectName}" resolves outside the current directory. Refusing for safety.\n`);
63
+ process.exit(1);
64
+ }
65
+ if (existsSync(join(projectDir, 'package.json'))) {
66
+ console.log('\n Directory already has a package.json. Use \'just init\' to set up an existing project.\n');
67
+ process.exit(1);
68
+ }
69
+ // Refuse to silently overwrite a non-empty directory. Without this,
70
+ // scaffolding into a dir that already has a .gitignore / README /
71
+ // CLAUDE.md / .git would clobber files. The package.json check above
72
+ // catches the common case but not these.
73
+ if (existsSync(projectDir)) {
74
+ const existing = readdirSync(projectDir).filter(
75
+ // .git is fine to coexist (this is how `init in current dir`
76
+ // workflows look); other dotfiles and source files are not.
77
+ (n) => n !== '.git');
78
+ if (existing.length > 0) {
79
+ const sample = existing.slice(0, 5).join(', ');
80
+ const more = existing.length > 5 ? `, +${existing.length - 5} more` : '';
81
+ const proceed = await ask(` Directory ${projectDir} is not empty (${sample}${more}). Files may be overwritten. Continue? (y/N)`, 'N');
82
+ if (!/^y(es)?$/i.test(proceed.trim())) {
83
+ console.log('\n Aborted.\n');
84
+ process.exit(1);
85
+ }
86
+ }
87
+ }
88
+ console.log('\n Scaffolding project...');
89
+ const generated = scaffoldProject({
90
+ projectDir,
91
+ projectName,
92
+ system,
93
+ });
94
+ for (const file of generated) {
95
+ console.log(` [x] ${file}`);
96
+ }
97
+ console.log('\n Installing dependencies...');
98
+ try {
99
+ const pm = system.packageManager;
100
+ execSync(`${pm} install`, { cwd: projectDir, stdio: 'inherit' });
101
+ console.log(' [x] Dependencies installed');
102
+ }
103
+ catch {
104
+ console.log(' [!] Failed to install dependencies. Run it manually.');
105
+ }
106
+ if (!existsSync(join(projectDir, '.git'))) {
107
+ try {
108
+ execSync('git init', { cwd: projectDir, stdio: 'ignore' });
109
+ console.log(' [x] Git initialized');
110
+ }
111
+ catch {
112
+ /* optional - git init is a nicety; user can run it manually */
113
+ }
114
+ }
115
+ const relPath = projectDir === cwd ? '.' : projectName;
116
+ console.log('\n Done! Next steps:\n');
117
+ if (relPath !== '.') {
118
+ console.log(` cd ${relPath}`);
119
+ }
120
+ console.log(' just dev # Start development server');
121
+ console.log(' just install <pkg> # Add a plugin');
122
+ console.log('');
123
+ if (system.ides.includes('jetbrains')) {
124
+ const open = await confirm(' Open in WebStorm?', true);
125
+ if (open) {
126
+ try {
127
+ execFileSync('webstorm', [projectDir], { stdio: 'ignore' });
128
+ }
129
+ catch {
130
+ /* optional - editor launch is best-effort */
131
+ }
132
+ }
133
+ }
134
+ else if (system.ides.includes('vscode')) {
135
+ const open = await confirm(' Open in VS Code?', true);
136
+ if (open) {
137
+ try {
138
+ execFileSync('code', [projectDir], { stdio: 'ignore' });
139
+ }
140
+ catch {
141
+ /* optional - editor launch is best-effort */
142
+ }
143
+ }
144
+ }
145
+ if (system.aiTools.includes('claude')) {
146
+ const start = await confirm(' Start Claude Code in this project?', true);
147
+ if (start) {
148
+ try {
149
+ execFileSync('claude', [projectDir], { stdio: 'ignore' });
150
+ }
151
+ catch {
152
+ /* optional - AI tool launch is best-effort */
153
+ }
154
+ }
155
+ }
156
+ }
157
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAE7E,SAAS,GAAG,CAAC,QAAgB,EAAE,YAAqB;IAClD,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,QAAQ,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,CAAC;IAClF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;YAC7B,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,YAAY,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,OAAO,CAAC,QAAgB,EAAE,UAAU,GAAG,KAAK;IACnD,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IAC5C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,EAAE,CAAC,QAAQ,CAAC,GAAG,QAAQ,IAAI,IAAI,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE;YAC9C,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACtC,IAAI,CAAC,KAAK,EAAE;gBAAE,OAAO,CAAC,UAAU,CAAC,CAAC;;gBAC7B,OAAO,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI;IACxB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAE/C,IAAI,CAAC;QACH,MAAM,GAAG,EAAE,CAAC;IACd,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,KAAK,UAAU,GAAG;IAEhB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAEjC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,wBAAwB,MAAM,CAAC,EAAE,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,wBAAwB,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,wBAAwB,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,wBAAwB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;IACrG,OAAO,CAAC,GAAG,CAAC,wBAAwB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;IAC3G,OAAO,CAAC,GAAG,CAAC,wBAAwB,MAAM,CAAC,UAAU,IAAI,cAAc,EAAE,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACrE,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;IAE7D,0GAA0G;IAC1G,MAAM,eAAe,GAAG,WAAW,KAAK,QAAQ,CAAC,GAAG,CAAC,CAAC;IACtD,MAAM,UAAU,GAAG,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAErE,0EAA0E;IAC1E,yCAAyC;IACzC,IAAI,CAAC,eAAe,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,qBAAqB,WAAW,kEAAkE,CAAC,CAAC;QAChH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,8FAA8F,CAAC,CAAC;QAC5G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,oEAAoE;IACpE,kEAAkE;IAClE,qEAAqE;IACrE,yCAAyC;IACzC,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM;QAC7C,6DAA6D;QAC7D,4DAA4D;QAC5D,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,CACpB,CAAC;QACF,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACzE,MAAM,OAAO,GAAG,MAAM,GAAG,CACvB,eAAe,UAAU,kBAAkB,MAAM,GAAG,IAAI,8CAA8C,EACtG,GAAG,CACJ,CAAC;YACF,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;gBACtC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;gBAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,eAAe,CAAC;QAChC,UAAU;QACV,WAAW;QACX,MAAM;KACP,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAC9C,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,CAAC,cAAc,CAAC;QACjC,QAAQ,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QACjE,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC;YACH,QAAQ,CAAC,UAAU,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC3D,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;QACjE,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvC,IAAI,OAAO,KAAK,GAAG,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC;QACxD,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC;gBAAC,YAAY,CAAC,UAAU,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAC1E,6CAA6C;YAC/C,CAAC;QACH,CAAC;IACH,CAAC;SAAM,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC;QACvD,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC;gBAAC,YAAY,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBACtE,6CAA6C;YAC/C,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,sCAAsC,EAAE,IAAI,CAAC,CAAC;QAC1E,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC;gBAAC,YAAY,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBACxE,8CAA8C;YAChD,CAAC;QACH,CAAC;IACH,CAAC;AAEH,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { SystemInfo } from './detect.js';
2
+ export interface ScaffoldOptions {
3
+ projectDir: string;
4
+ projectName: string;
5
+ system: SystemInfo;
6
+ coreVersion?: string;
7
+ }
8
+ export declare function scaffoldProject(options: ScaffoldOptions): string[];
9
+ /**
10
+ * Defense-in-depth against a compromised template package: returns false
11
+ * for any entry whose name contains path separators, parent traversal, or
12
+ * is a hidden-dot reference. readdirSync should never return such names on
13
+ * a real filesystem, but if a malicious npm package or symlink injects one,
14
+ * a naive `join(dir, name, ...)` would escape the intended destination.
15
+ *
16
+ * Exported for unit-testing.
17
+ */
18
+ export declare function isSafePathSegment(name: string): boolean;
19
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAS9C,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,UAAU,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,EAAE,CAgHlE;AAgJD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOvD"}