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 +21 -0
- package/README.md +82 -0
- package/bin/create-justscale.js +3 -0
- package/dist/detect.d.ts +11 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +68 -0
- package/dist/detect.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +157 -0
- package/dist/index.js.map +1 -0
- package/dist/scaffold.d.ts +19 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +324 -0
- package/dist/scaffold.js.map +1 -0
- package/package.json +35 -0
- package/templates/skills/audit-domain-purity/SKILL.md +124 -0
- package/templates/skills/justscale-concepts/SKILL.md +191 -0
- package/templates/skills/multi-instance-test/SKILL.md +185 -0
- package/templates/skills/new-process/SKILL.md +119 -0
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
|
package/dist/detect.d.ts
ADDED
|
@@ -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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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":"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"}
|
|
@@ -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"}
|