rapidkit 0.41.0 → 0.41.1
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/README.md +12 -5
- package/contracts/extension-cli-compatibility.v1.json +1 -1
- package/contracts/workspace-intelligence/agent-action-outcome.v1.json +17 -1
- package/contracts/workspace-intelligence/workspace-dependency-graph.v1.json +61 -1
- package/dist/analyze-QYHMGLSG.js +1 -0
- package/dist/autopilot-release-AHMQEUFH.js +1 -0
- package/dist/{chunk-WA6JYVJM.js → chunk-33LR2QEM.js} +1 -1
- package/dist/{chunk-DMUEGR36.js → chunk-3PTJID76.js} +1 -1
- package/dist/chunk-46AGNYI7.js +50 -0
- package/dist/chunk-AQ4XZZC6.js +1 -0
- package/dist/{chunk-MGUJWRZA.js → chunk-BFEBZABL.js} +3 -3
- package/dist/chunk-CDPR2YKL.js +13 -0
- package/dist/{chunk-73IS6RIM.js → chunk-CKXJR3YT.js} +1 -1
- package/dist/chunk-E5ZVQL3C.js +13 -0
- package/dist/chunk-ELU3G6DQ.js +9 -0
- package/dist/chunk-EN6YCX36.js +1 -0
- package/dist/chunk-FMBSON6H.js +33 -0
- package/dist/chunk-GBJBQ43T.js +1 -0
- package/dist/{chunk-FPUNOIAR.js → chunk-ITJ6RKUW.js} +3 -3
- package/dist/{chunk-XOVB2ZP5.js → chunk-JU3VNLTY.js} +1 -1
- package/dist/chunk-JW2FSKT3.js +2 -0
- package/dist/{chunk-44GSDNPQ.js → chunk-KIUSCFHF.js} +1 -1
- package/dist/{chunk-AT3EQ2S7.js → chunk-LKX3L7TE.js} +1 -1
- package/dist/{chunk-KTQZUWAM.js → chunk-RSYUNEH7.js} +13 -13
- package/dist/chunk-TJN7G2MA.js +1 -0
- package/dist/{chunk-Y2SCTWL4.js → chunk-UQR6G7KH.js} +2 -2
- package/dist/chunk-WRMCPKGA.js +1 -0
- package/dist/{create-UGXMC4CT.js → create-RNP5ACQL.js} +1 -1
- package/dist/demo-kit-N5U3NGAE.js +149 -0
- package/dist/{doctor-LCKG5S76.js → doctor-XM6QDTDC.js} +1 -1
- package/dist/index.js +118 -117
- package/dist/{pipeline-MKNYPNGD.js → pipeline-DH6Z47O4.js} +1 -1
- package/dist/platform-capabilities-TSLK667K.js +1 -0
- package/dist/{pythonRapidkitExec-MNWRC4F2.js → pythonRapidkitExec-SGKW76XM.js} +1 -1
- package/dist/{workspace-FDMJD5XI.js → workspace-E554C5SM.js} +1 -1
- package/dist/{workspace-agent-sync-WJIZCZX5.js → workspace-agent-sync-2HRPM5ZD.js} +1 -1
- package/dist/{workspace-context-RYOQYGOP.js → workspace-context-VJTXW3K4.js} +1 -1
- package/dist/{workspace-contract-ITFCJCHI.js → workspace-contract-OO4GMENV.js} +1 -1
- package/dist/workspace-explain-3WSJLIJ6.js +1 -0
- package/dist/workspace-explain-contract-24RQ7KIW.js +1 -0
- package/dist/{workspace-foundation-SILFUKL5.js → workspace-foundation-LISDH53T.js} +1 -1
- package/dist/{workspace-intelligence-YOZQBAK5.js → workspace-intelligence-E3KXEZCM.js} +1 -1
- package/dist/workspace-mcp-serve-RFYDCA2L.js +3 -0
- package/dist/{workspace-model-VMMLHJWI.js → workspace-model-YL7W3573.js} +1 -1
- package/dist/workspace-registry-summary-X5WRUU3T.js +1 -0
- package/dist/workspace-run-GCIQD73R.js +1 -0
- package/dist/workspace-verify-NRYH7RNB.js +1 -0
- package/dist/{workspace-watch-3MEZRSEE.js → workspace-watch-H2AETGFI.js} +1 -1
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/OPEN_SOURCE_USER_SCENARIOS.md +1 -1
- package/docs/README.md +1 -1
- package/docs/commands-reference.md +10 -2
- package/package.json +7 -3
- package/scripts/enterprise-package-smoke.mjs +427 -0
- package/scripts/prepack-enterprise.mjs +40 -0
- package/templates/generator.js +175 -0
- package/templates/kits/fastapi-ddd/README.md.j2 +122 -0
- package/templates/kits/fastapi-ddd/common/env.example.j2 +10 -0
- package/templates/kits/fastapi-ddd/env.example.j2 +1 -0
- package/templates/kits/fastapi-ddd/pyproject.toml.j2 +64 -0
- package/templates/kits/fastapi-ddd/src/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-ddd/src/app/__init__.py.j2 +11 -0
- package/templates/kits/fastapi-ddd/src/app/application/__init__.py.j2 +5 -0
- package/templates/kits/fastapi-ddd/src/app/application/interfaces.py.j2 +43 -0
- package/templates/kits/fastapi-ddd/src/app/application/use_cases/__init__.py.j2 +6 -0
- package/templates/kits/fastapi-ddd/src/app/application/use_cases/health.py.j2 +14 -0
- package/templates/kits/fastapi-ddd/src/app/application/use_cases/notes.py.j2 +24 -0
- package/templates/kits/fastapi-ddd/src/app/config/__init__.py.j2 +16 -0
- package/templates/kits/fastapi-ddd/src/app/domain/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-ddd/src/app/domain/models/__init__.py.j2 +6 -0
- package/templates/kits/fastapi-ddd/src/app/domain/models/health.py.j2 +16 -0
- package/templates/kits/fastapi-ddd/src/app/domain/models/note.py.j2 +27 -0
- package/templates/kits/fastapi-ddd/src/app/infrastructure/__init__.py.j2 +5 -0
- package/templates/kits/fastapi-ddd/src/app/infrastructure/repositories/__init__.py.j2 +6 -0
- package/templates/kits/fastapi-ddd/src/app/infrastructure/repositories/health.py.j2 +17 -0
- package/templates/kits/fastapi-ddd/src/app/infrastructure/repositories/notes.py.j2 +28 -0
- package/templates/kits/fastapi-ddd/src/app/main.py.j2 +61 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/api/__init__.py.j2 +5 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/api/dependencies/__init__.py.j2 +19 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/api/router.py.j2 +10 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/api/routes/__init__.py.j2 +5 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/api/routes/health.py.j2 +27 -0
- package/templates/kits/fastapi-ddd/src/app/presentation/api/routes/notes.py.j2 +50 -0
- package/templates/kits/fastapi-ddd/src/app/shared/__init__.py.j2 +5 -0
- package/templates/kits/fastapi-ddd/src/app/shared/result.py.j2 +28 -0
- package/templates/kits/fastapi-ddd/src/cli.py.j2 +167 -0
- package/templates/kits/fastapi-ddd/src/main.py.j2 +35 -0
- package/templates/kits/fastapi-ddd/src/modules/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-ddd/src/routing/__init__.py.j2 +13 -0
- package/templates/kits/fastapi-ddd/src/routing/health.py.j2 +7 -0
- package/templates/kits/fastapi-ddd/src/routing/notes.py.j2 +7 -0
- package/templates/kits/fastapi-ddd/tests/__init__.py.j2 +1 -0
- package/templates/kits/fastapi-ddd/tests/test_app_factory.py.j2 +22 -0
- package/templates/kits/fastapi-ddd/tests/test_health.py.j2 +17 -0
- package/templates/kits/fastapi-ddd/tests/test_notes.py.j2 +27 -0
- package/templates/kits/fastapi-standard/README.md.j2 +145 -0
- package/templates/kits/fastapi-standard/common/env.example.j2 +10 -0
- package/templates/kits/fastapi-standard/env.example.j2 +1 -0
- package/templates/kits/fastapi-standard/pyproject.toml.j2 +64 -0
- package/templates/kits/fastapi-standard/src/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-standard/src/cli.py.j2 +168 -0
- package/templates/kits/fastapi-standard/src/main.py.j2 +66 -0
- package/templates/kits/fastapi-standard/src/modules/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-standard/src/routing/__init__.py.j2 +16 -0
- package/templates/kits/fastapi-standard/src/routing/examples.py.j2 +71 -0
- package/templates/kits/fastapi-standard/src/routing/health.py.j2 +22 -0
- package/templates/kits/fastapi-standard/tests/__init__.py.j2 +1 -0
- package/templates/kits/fastapi-standard/tests/test_examples.py.j2 +29 -0
- package/templates/kits/fastapi-standard/tests/test_health.py.j2 +17 -0
- package/templates/kits/nestjs-standard/Dockerfile.j2 +41 -0
- package/templates/kits/nestjs-standard/README.md.j2 +139 -0
- package/templates/kits/nestjs-standard/docker-compose.yml.j2 +94 -0
- package/templates/kits/nestjs-standard/docs/README.md.j2 +15 -0
- package/templates/kits/nestjs-standard/env.example.j2 +18 -0
- package/templates/kits/nestjs-standard/eslint.config.cjs.j2 +9 -0
- package/templates/kits/nestjs-standard/jest.config.ts.j2 +22 -0
- package/templates/kits/nestjs-standard/nest-cli.json.j2 +10 -0
- package/templates/kits/nestjs-standard/package.json.j2 +101 -0
- package/templates/kits/nestjs-standard/src/app.controller.ts.j2 +14 -0
- package/templates/kits/nestjs-standard/src/app.module.ts.j2 +26 -0
- package/templates/kits/nestjs-standard/src/app.service.ts.j2 +16 -0
- package/templates/kits/nestjs-standard/src/auth/auth.controller.ts.j2 +20 -0
- package/templates/kits/nestjs-standard/src/auth/auth.module.ts.j2 +13 -0
- package/templates/kits/nestjs-standard/src/auth/auth.service.ts.j2 +6 -0
- package/templates/kits/nestjs-standard/src/auth/entities/token.entity.ts.j2 +3 -0
- package/templates/kits/nestjs-standard/src/auth/entities/user.entity.ts.j2 +3 -0
- package/templates/kits/nestjs-standard/src/auth/entities/webauthn.entity.ts.j2 +3 -0
- package/templates/kits/nestjs-standard/src/config/configuration.ts.j2 +85 -0
- package/templates/kits/nestjs-standard/src/config/index.ts.j2 +2 -0
- package/templates/kits/nestjs-standard/src/config/validation.ts.j2 +21 -0
- package/templates/kits/nestjs-standard/src/examples/dto/create-note.dto.ts.j2 +11 -0
- package/templates/kits/nestjs-standard/src/examples/examples.controller.ts.j2 +24 -0
- package/templates/kits/nestjs-standard/src/examples/examples.module.ts.j2 +10 -0
- package/templates/kits/nestjs-standard/src/examples/examples.service.ts.j2 +33 -0
- package/templates/kits/nestjs-standard/src/main.ts.j2 +53 -0
- package/templates/kits/nestjs-standard/src/modules/index.ts.j2 +25 -0
- package/templates/kits/nestjs-standard/test/app.controller.spec.ts.j2 +24 -0
- package/templates/kits/nestjs-standard/test/app.e2e-spec.ts.j2 +60 -0
- package/templates/kits/nestjs-standard/test/examples.controller.spec.ts.j2 +28 -0
- package/templates/kits/nestjs-standard/test/jest-e2e.json.j2 +15 -0
- package/templates/kits/nestjs-standard/tsconfig.build.json.j2 +12 -0
- package/templates/kits/nestjs-standard/tsconfig.json.j2 +26 -0
- package/dist/analyze-JVMUCQ22.js +0 -1
- package/dist/autopilot-release-GM5ALPWO.js +0 -1
- package/dist/chunk-424B73UF.js +0 -1
- package/dist/chunk-56RL5OB6.js +0 -2
- package/dist/chunk-AO6PG3K2.js +0 -9
- package/dist/chunk-FVCZGUVX.js +0 -1
- package/dist/chunk-GX7UU7LL.js +0 -33
- package/dist/chunk-P5ODFWB2.js +0 -13
- package/dist/chunk-QN2LPLHO.js +0 -1
- package/dist/chunk-RIZCWYRR.js +0 -1
- package/dist/chunk-YOQ2546V.js +0 -50
- package/dist/chunk-Z5LKRG57.js +0 -1
- package/dist/chunk-ZQRFVFKK.js +0 -13
- package/dist/demo-kit-2VI4H6OJ.js +0 -141
- package/dist/workspace-explain-VKSUKP3O.js +0 -1
- package/dist/workspace-explain-contract-CLHQ3XEH.js +0 -1
- package/dist/workspace-mcp-serve-OOLITFCK.js +0 -3
- package/dist/workspace-registry-summary-ZXGKL2NT.js +0 -1
- package/dist/workspace-run-IHB2TPMD.js +0 -1
- package/dist/workspace-verify-3CAKAZIL.js +0 -1
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import process from 'node:process';
|
|
8
|
+
|
|
9
|
+
const repoRoot = process.cwd();
|
|
10
|
+
const cliPath = path.join(repoRoot, 'dist', 'index.js');
|
|
11
|
+
|
|
12
|
+
function fail(message) {
|
|
13
|
+
console.error(`[enterprise-package-smoke] ${message}`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function log(message) {
|
|
18
|
+
console.log(`[enterprise-package-smoke] ${message}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function cliEnv(extraEnv = {}) {
|
|
22
|
+
const env = { ...process.env, ...extraEnv };
|
|
23
|
+
delete env.NODE_ENV;
|
|
24
|
+
delete env.NODE_OPTIONS;
|
|
25
|
+
for (const key of Object.keys(env)) {
|
|
26
|
+
if (key.startsWith('VITEST')) {
|
|
27
|
+
delete env[key];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return env;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function commandExists(command, args = ['--version']) {
|
|
34
|
+
const result = spawnSync(command, args, { stdio: 'ignore' });
|
|
35
|
+
return result.status === 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function resolveNpmInvocation() {
|
|
39
|
+
const npmExecPath = process.env.npm_execpath;
|
|
40
|
+
if (npmExecPath && fs.existsSync(npmExecPath)) {
|
|
41
|
+
return { command: process.execPath, prefixArgs: [npmExecPath] };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (commandExists('corepack')) {
|
|
45
|
+
return { command: 'corepack', prefixArgs: ['npm'] };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (commandExists('npm')) {
|
|
49
|
+
return { command: 'npm', prefixArgs: [] };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fail('could not resolve npm. Install npm or enable corepack before packaging.');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function run(command, args, options = {}) {
|
|
56
|
+
const result = spawnSync(command, args, {
|
|
57
|
+
cwd: repoRoot,
|
|
58
|
+
encoding: 'utf8',
|
|
59
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
60
|
+
...options,
|
|
61
|
+
env: cliEnv(options.env),
|
|
62
|
+
});
|
|
63
|
+
if (result.status !== 0) {
|
|
64
|
+
fail(
|
|
65
|
+
`command failed (${result.status}): ${command} ${args.join(' ')}\n${result.stdout ?? ''}\n${result.stderr ?? ''}`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
return result.stdout ?? '';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function runToFile(command, args, options = {}) {
|
|
72
|
+
const outputPath = path.join(
|
|
73
|
+
os.tmpdir(),
|
|
74
|
+
`rapidkit-enterprise-command-${process.pid}-${Date.now()}-${Math.random()
|
|
75
|
+
.toString(16)
|
|
76
|
+
.slice(2)}.out`
|
|
77
|
+
);
|
|
78
|
+
const fd = fs.openSync(outputPath, 'w');
|
|
79
|
+
try {
|
|
80
|
+
const result = spawnSync(command, args, {
|
|
81
|
+
cwd: repoRoot,
|
|
82
|
+
encoding: 'utf8',
|
|
83
|
+
stdio: ['ignore', fd, 'pipe'],
|
|
84
|
+
...options,
|
|
85
|
+
env: cliEnv(options.env),
|
|
86
|
+
});
|
|
87
|
+
if (result.status !== 0) {
|
|
88
|
+
fail(
|
|
89
|
+
`command failed (${result.status}): ${command} ${args.join(' ')}\n${result.stderr ?? ''}`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
} finally {
|
|
93
|
+
fs.closeSync(fd);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
return fs.readFileSync(outputPath, 'utf8');
|
|
98
|
+
} finally {
|
|
99
|
+
fs.rmSync(outputPath, { force: true });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function runNpm(args) {
|
|
104
|
+
const npm = resolveNpmInvocation();
|
|
105
|
+
return runToFile(npm.command, [...npm.prefixArgs, ...args], {
|
|
106
|
+
env: {
|
|
107
|
+
...cliEnv(),
|
|
108
|
+
npm_config_user_agent: process.env.npm_config_user_agent || 'npm/10 rapidkit-smoke',
|
|
109
|
+
npm_config_cache:
|
|
110
|
+
process.env.npm_config_cache ||
|
|
111
|
+
path.join(os.tmpdir(), `rapidkit-enterprise-npm-cache-${process.pid}`),
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function runCli(args) {
|
|
117
|
+
const outputPath = path.join(
|
|
118
|
+
os.tmpdir(),
|
|
119
|
+
`rapidkit-enterprise-cli-${process.pid}-${Date.now()}-${Math.random()
|
|
120
|
+
.toString(16)
|
|
121
|
+
.slice(2)}.out`
|
|
122
|
+
);
|
|
123
|
+
const fd = fs.openSync(outputPath, 'w');
|
|
124
|
+
try {
|
|
125
|
+
const result = spawnSync(process.execPath, [cliPath, ...args], {
|
|
126
|
+
cwd: repoRoot,
|
|
127
|
+
encoding: 'utf8',
|
|
128
|
+
env: cliEnv(),
|
|
129
|
+
stdio: ['ignore', fd, 'pipe'],
|
|
130
|
+
});
|
|
131
|
+
if (result.status !== 0) {
|
|
132
|
+
fail(
|
|
133
|
+
`CLI command failed (${result.status}): node dist/index.js ${args.join(' ')}\n${
|
|
134
|
+
result.stderr ?? ''
|
|
135
|
+
}`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
} finally {
|
|
139
|
+
fs.closeSync(fd);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
return fs.readFileSync(outputPath, 'utf8');
|
|
144
|
+
} finally {
|
|
145
|
+
fs.rmSync(outputPath, { force: true });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function assertFile(relativePath) {
|
|
150
|
+
const absolutePath = path.join(repoRoot, relativePath);
|
|
151
|
+
if (!fs.existsSync(absolutePath)) {
|
|
152
|
+
fail(`missing required file: ${relativePath}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function parseTrailingJson(stdout) {
|
|
157
|
+
const trimmed = stdout.trim();
|
|
158
|
+
const start = trimmed.lastIndexOf('\n{');
|
|
159
|
+
const jsonText = start >= 0 ? trimmed.slice(start + 1) : trimmed;
|
|
160
|
+
try {
|
|
161
|
+
return JSON.parse(jsonText);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
fail(`failed to parse CLI JSON output: ${error instanceof Error ? error.message : error}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function assertPackContents() {
|
|
168
|
+
if (process.env.RAPIDKIT_ENTERPRISE_PREPACK === '1') {
|
|
169
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8'));
|
|
170
|
+
const files = packageJson.files ?? [];
|
|
171
|
+
const isPublished = (assetPath) =>
|
|
172
|
+
files.some(
|
|
173
|
+
(entry) => entry === assetPath || assetPath.startsWith(`${entry.replace(/\/$/, '')}/`)
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
for (const required of [
|
|
177
|
+
'dist/index.js',
|
|
178
|
+
'contracts/runtime-command-surface.v1.json',
|
|
179
|
+
'contracts/extension-cli-compatibility.v1.json',
|
|
180
|
+
'data/modules-embeddings.json',
|
|
181
|
+
'templates/kits/fastapi-standard/README.md.j2',
|
|
182
|
+
'templates/kits/fastapi-ddd/README.md.j2',
|
|
183
|
+
'templates/kits/nestjs-standard/package.json.j2',
|
|
184
|
+
'scripts/check-cli-resolution.cjs',
|
|
185
|
+
'scripts/enforce-package-manager.cjs',
|
|
186
|
+
]) {
|
|
187
|
+
if (!isPublished(required)) {
|
|
188
|
+
fail(`package.json#files does not publish ${required}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
log('verified package.json#files payload policy for prepack lifecycle');
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const output = runNpm(['pack', '--dry-run', '--json', '--ignore-scripts']);
|
|
197
|
+
let packuments;
|
|
198
|
+
try {
|
|
199
|
+
packuments = JSON.parse(output);
|
|
200
|
+
} catch (error) {
|
|
201
|
+
fail(`npm pack --dry-run did not return JSON: ${error instanceof Error ? error.message : error}`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const files = new Set(
|
|
205
|
+
(packuments?.[0]?.files ?? [])
|
|
206
|
+
.map((entry) => entry?.path)
|
|
207
|
+
.filter((entry) => typeof entry === 'string')
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
for (const required of [
|
|
211
|
+
'dist/index.js',
|
|
212
|
+
'contracts/runtime-command-surface.v1.json',
|
|
213
|
+
'contracts/extension-cli-compatibility.v1.json',
|
|
214
|
+
'data/modules-embeddings.json',
|
|
215
|
+
'templates/kits/fastapi-standard/README.md.j2',
|
|
216
|
+
'templates/kits/fastapi-ddd/README.md.j2',
|
|
217
|
+
'templates/kits/nestjs-standard/package.json.j2',
|
|
218
|
+
'scripts/check-cli-resolution.cjs',
|
|
219
|
+
'scripts/enforce-package-manager.cjs',
|
|
220
|
+
]) {
|
|
221
|
+
if (!files.has(required)) {
|
|
222
|
+
fail(`npm pack payload is missing ${required}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
for (const forbiddenPrefix of [
|
|
227
|
+
'node_modules/',
|
|
228
|
+
'.rapidkit/',
|
|
229
|
+
'.venv/',
|
|
230
|
+
'coverage/',
|
|
231
|
+
'test-results/',
|
|
232
|
+
'src/',
|
|
233
|
+
]) {
|
|
234
|
+
const leaked = [...files].find((entry) => entry.startsWith(forbiddenPrefix));
|
|
235
|
+
if (leaked) {
|
|
236
|
+
fail(`npm pack payload leaks dev/local artifact: ${leaked}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
log(`verified npm pack payload (${files.size} files)`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function assertCliContracts() {
|
|
244
|
+
const version = parseTrailingJson(runCli(['--version', '--json']));
|
|
245
|
+
if (version.schemaVersion !== 'rapidkit-version-v1') {
|
|
246
|
+
fail(`unexpected version schema: ${version.schemaVersion}`);
|
|
247
|
+
}
|
|
248
|
+
if (!version.contracts?.runtimeCommandSurface) {
|
|
249
|
+
fail('version contract does not advertise runtimeCommandSurface');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const commands = parseTrailingJson(runCli(['commands', '--json']));
|
|
253
|
+
if (commands.schemaVersion !== 'rapidkit-command-capabilities-v1') {
|
|
254
|
+
fail(`unexpected commands schema: ${commands.schemaVersion}`);
|
|
255
|
+
}
|
|
256
|
+
for (const topLevel of ['create', 'workspace', 'doctor', 'bootstrap']) {
|
|
257
|
+
if (!commands.commandMap?.[topLevel]) {
|
|
258
|
+
fail(`commands surface is missing top-level command: ${topLevel}`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
for (const subcommand of ['model', 'snapshot', 'diff', 'impact', 'verify', 'context', 'explain']) {
|
|
262
|
+
if (!commands.workspace?.intelligenceSubcommands?.includes(subcommand)) {
|
|
263
|
+
fail(`workspace intelligence surface is missing subcommand: ${subcommand}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
log(`verified CLI contract surfaces for v${version.version}`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function assertGeneratedProject(projectPath, expectedFiles) {
|
|
271
|
+
for (const relativePath of expectedFiles) {
|
|
272
|
+
const absolutePath = path.join(projectPath, relativePath);
|
|
273
|
+
if (!fs.existsSync(absolutePath)) {
|
|
274
|
+
fail(`generated project ${path.basename(projectPath)} is missing ${relativePath}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function smokeCreateNpmBackedKits() {
|
|
280
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rapidkit-enterprise-smoke-'));
|
|
281
|
+
const scenarios = [
|
|
282
|
+
{
|
|
283
|
+
kit: 'gofiber.standard',
|
|
284
|
+
name: 'enterprise-fiber',
|
|
285
|
+
extraArgs: [],
|
|
286
|
+
expectedFiles: ['go.mod', 'cmd/server/main.go', '.rapidkit/project.json', 'rapidkit'],
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
kit: 'gogin.standard',
|
|
290
|
+
name: 'enterprise-gin',
|
|
291
|
+
extraArgs: [],
|
|
292
|
+
expectedFiles: ['go.mod', 'cmd/server/main.go', '.rapidkit/project.json', 'rapidkit'],
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
kit: 'springboot.standard',
|
|
296
|
+
name: 'enterprise-spring',
|
|
297
|
+
extraArgs: ['--java-version', '21'],
|
|
298
|
+
expectedFiles: ['pom.xml', 'src/main/resources/application.yml', '.rapidkit/project.json', 'rapidkit'],
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
kit: 'dotnet.webapi.clean',
|
|
302
|
+
name: 'enterprise-dotnet',
|
|
303
|
+
extraArgs: ['--target-framework', 'net8.0'],
|
|
304
|
+
expectedFiles: ['src/Program.cs', 'src/enterprise-dotnet.csproj', '.rapidkit/project.json', 'rapidkit'],
|
|
305
|
+
},
|
|
306
|
+
];
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
for (const scenario of scenarios) {
|
|
310
|
+
const args = [
|
|
311
|
+
cliPath,
|
|
312
|
+
'create',
|
|
313
|
+
'project',
|
|
314
|
+
scenario.kit,
|
|
315
|
+
scenario.name,
|
|
316
|
+
'--output',
|
|
317
|
+
tempDir,
|
|
318
|
+
'--skip-git',
|
|
319
|
+
'--skip-install',
|
|
320
|
+
...scenario.extraArgs,
|
|
321
|
+
];
|
|
322
|
+
const result = spawnSync(process.execPath, args, {
|
|
323
|
+
cwd: tempDir,
|
|
324
|
+
encoding: 'utf8',
|
|
325
|
+
env: cliEnv(),
|
|
326
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
327
|
+
});
|
|
328
|
+
if (result.status !== 0) {
|
|
329
|
+
fail(
|
|
330
|
+
`${scenario.kit} smoke create failed with exit ${result.status}\n${result.stdout}\n${result.stderr}`
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
assertGeneratedProject(path.join(tempDir, scenario.name), scenario.expectedFiles);
|
|
334
|
+
}
|
|
335
|
+
} finally {
|
|
336
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
log(`verified ${scenarios.length} npm-backed create scenarios`);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function smokeCreateOfflineFallbackKits() {
|
|
343
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rapidkit-enterprise-fallback-'));
|
|
344
|
+
const scenarios = [
|
|
345
|
+
{
|
|
346
|
+
kit: 'fastapi.standard',
|
|
347
|
+
name: 'enterprise-fastapi',
|
|
348
|
+
expectedFiles: [
|
|
349
|
+
'pyproject.toml',
|
|
350
|
+
'src/main.py',
|
|
351
|
+
'src/routing/health.py',
|
|
352
|
+
'src/routing/examples.py',
|
|
353
|
+
'tests/test_health.py',
|
|
354
|
+
'tests/test_examples.py',
|
|
355
|
+
'.env.example',
|
|
356
|
+
'.rapidkit/project.json',
|
|
357
|
+
'rapidkit',
|
|
358
|
+
],
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
kit: 'nestjs.standard',
|
|
362
|
+
name: 'enterprise-nestjs',
|
|
363
|
+
expectedFiles: [
|
|
364
|
+
'package.json',
|
|
365
|
+
'src/main.ts',
|
|
366
|
+
'src/examples/examples.module.ts',
|
|
367
|
+
'.env.example',
|
|
368
|
+
'.rapidkit/project.json',
|
|
369
|
+
'rapidkit',
|
|
370
|
+
],
|
|
371
|
+
},
|
|
372
|
+
];
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
for (const scenario of scenarios) {
|
|
376
|
+
const result = spawnSync(
|
|
377
|
+
process.execPath,
|
|
378
|
+
[
|
|
379
|
+
cliPath,
|
|
380
|
+
'create',
|
|
381
|
+
'project',
|
|
382
|
+
scenario.kit,
|
|
383
|
+
scenario.name,
|
|
384
|
+
'--output',
|
|
385
|
+
tempDir,
|
|
386
|
+
'--skip-git',
|
|
387
|
+
'--skip-install',
|
|
388
|
+
],
|
|
389
|
+
{
|
|
390
|
+
cwd: tempDir,
|
|
391
|
+
encoding: 'utf8',
|
|
392
|
+
env: cliEnv({
|
|
393
|
+
RAPIDKIT_FORCE_OFFLINE_CREATE_FALLBACK: '1',
|
|
394
|
+
}),
|
|
395
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
396
|
+
}
|
|
397
|
+
);
|
|
398
|
+
if (result.status !== 0) {
|
|
399
|
+
fail(
|
|
400
|
+
`${scenario.kit} offline fallback smoke failed with exit ${result.status}\n${result.stdout}\n${result.stderr}`
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
assertGeneratedProject(path.join(tempDir, scenario.name), scenario.expectedFiles);
|
|
404
|
+
}
|
|
405
|
+
} finally {
|
|
406
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
log(`verified ${scenarios.length} offline fallback create scenarios`);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
for (const relativePath of [
|
|
413
|
+
'package.json',
|
|
414
|
+
'dist/index.js',
|
|
415
|
+
'contracts/runtime-command-surface.v1.json',
|
|
416
|
+
'contracts/extension-cli-compatibility.v1.json',
|
|
417
|
+
'data/modules-embeddings.json',
|
|
418
|
+
]) {
|
|
419
|
+
assertFile(relativePath);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
assertPackContents();
|
|
423
|
+
assertCliContracts();
|
|
424
|
+
smokeCreateNpmBackedKits();
|
|
425
|
+
smokeCreateOfflineFallbackKits();
|
|
426
|
+
|
|
427
|
+
log('enterprise package smoke passed');
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import process from 'node:process';
|
|
7
|
+
|
|
8
|
+
const repoRoot = process.cwd();
|
|
9
|
+
|
|
10
|
+
function fail(message) {
|
|
11
|
+
console.error(`[prepack-enterprise] ${message}`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function runNode(args, label, extraEnv = {}) {
|
|
16
|
+
console.log(`[prepack-enterprise] ${label}`);
|
|
17
|
+
execFileSync(process.execPath, args, {
|
|
18
|
+
cwd: repoRoot,
|
|
19
|
+
stdio: 'inherit',
|
|
20
|
+
env: {
|
|
21
|
+
...process.env,
|
|
22
|
+
...extraEnv,
|
|
23
|
+
npm_config_user_agent: process.env.npm_config_user_agent || 'npm/10 rapidkit-prepack',
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const tsupCli = path.join(repoRoot, 'node_modules', 'tsup', 'dist', 'cli-default.js');
|
|
29
|
+
if (!fs.existsSync(tsupCli)) {
|
|
30
|
+
fail(`missing tsup CLI at ${tsupCli}; run npm ci before packaging`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
runNode([tsupCli], 'building dist');
|
|
34
|
+
runNode(['scripts/prepare-mock-embeddings.mjs'], 'preparing packaged embeddings');
|
|
35
|
+
runNode(['scripts/verify-package-cli.mjs'], 'verifying bundled CLI command ownership');
|
|
36
|
+
runNode(['scripts/enterprise-package-smoke.mjs'], 'running enterprise package smoke', {
|
|
37
|
+
RAPIDKIT_ENTERPRISE_PREPACK: '1',
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
console.log('[prepack-enterprise] prepack checks passed');
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* RapidKit Project Generator
|
|
4
|
+
* This script is called by the rapidkit CLI to generate projects
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs').promises;
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { execSync } = require('child_process');
|
|
10
|
+
|
|
11
|
+
const TEMPLATES_DIR = path.join(__dirname, 'templates');
|
|
12
|
+
|
|
13
|
+
async function generateProject(projectPath, template, useDefaults, skipGit, skipInstall) {
|
|
14
|
+
const projectName = path.basename(projectPath);
|
|
15
|
+
const templateDir = template === 'nestjs' ? 'nestjs-standard' : 'fastapi-standard';
|
|
16
|
+
const templatePath = path.join(TEMPLATES_DIR, templateDir);
|
|
17
|
+
|
|
18
|
+
// Check template exists
|
|
19
|
+
try {
|
|
20
|
+
await fs.access(templatePath);
|
|
21
|
+
} catch {
|
|
22
|
+
console.error('❌ Template not found:', templateDir);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Create project directory
|
|
27
|
+
await fs.mkdir(projectPath, { recursive: true });
|
|
28
|
+
|
|
29
|
+
// Build context
|
|
30
|
+
const context = {
|
|
31
|
+
project_name: template === 'nestjs'
|
|
32
|
+
? projectName.replace(/_/g, '-').toLowerCase()
|
|
33
|
+
: projectName.replace(/-/g, '_').toLowerCase(),
|
|
34
|
+
author: process.env.USER || 'RapidKit User',
|
|
35
|
+
description: template === 'nestjs'
|
|
36
|
+
? 'NestJS application generated with RapidKit'
|
|
37
|
+
: 'FastAPI service generated with RapidKit',
|
|
38
|
+
app_version: '0.1.0',
|
|
39
|
+
license: 'MIT',
|
|
40
|
+
package_manager: 'npm',
|
|
41
|
+
created_at: new Date().toISOString(),
|
|
42
|
+
rapidkit_version: require('./config.json').rapidkit_version || '0.12.0',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Copy and render template files
|
|
46
|
+
await copyTemplateDir(templatePath, projectPath, context);
|
|
47
|
+
|
|
48
|
+
console.log('✅ Project files created!');
|
|
49
|
+
|
|
50
|
+
// Git initialization
|
|
51
|
+
if (!skipGit) {
|
|
52
|
+
try {
|
|
53
|
+
execSync('git init', { cwd: projectPath, stdio: 'pipe' });
|
|
54
|
+
execSync('git add .', { cwd: projectPath, stdio: 'pipe' });
|
|
55
|
+
const commitMsg = 'Initial commit: ' + (template === 'nestjs' ? 'NestJS' : 'FastAPI') + ' project via RapidKit';
|
|
56
|
+
execSync(`git commit -m "${commitMsg}"`, { cwd: projectPath, stdio: 'pipe' });
|
|
57
|
+
console.log('✅ Git repository initialized');
|
|
58
|
+
} catch (e) {
|
|
59
|
+
console.log('⚠️ Could not initialize git');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Install dependencies
|
|
64
|
+
if (!skipInstall) {
|
|
65
|
+
if (template === 'nestjs') {
|
|
66
|
+
console.log('📦 Installing dependencies...');
|
|
67
|
+
try {
|
|
68
|
+
execSync('npm install', { cwd: projectPath, stdio: 'inherit' });
|
|
69
|
+
console.log('✅ Dependencies installed');
|
|
70
|
+
} catch {
|
|
71
|
+
console.log('⚠️ Could not install dependencies. Run npm install manually.');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Success message
|
|
77
|
+
const templateName = template === 'nestjs' ? 'NestJS' : 'FastAPI';
|
|
78
|
+
console.log('');
|
|
79
|
+
console.log('✨ ' + templateName + ' project created successfully!');
|
|
80
|
+
console.log('');
|
|
81
|
+
console.log('🚀 Get started:');
|
|
82
|
+
console.log(' cd ' + projectName);
|
|
83
|
+
if (template === 'fastapi') {
|
|
84
|
+
console.log(' rapidkit init # poetry install');
|
|
85
|
+
console.log(' rapidkit dev # Start dev server');
|
|
86
|
+
} else {
|
|
87
|
+
if (skipInstall) {
|
|
88
|
+
console.log(' rapidkit init # npm install');
|
|
89
|
+
}
|
|
90
|
+
console.log(' cp .env.example .env');
|
|
91
|
+
console.log(' rapidkit dev # Start dev server');
|
|
92
|
+
}
|
|
93
|
+
console.log('');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function renderTemplate(content, context) {
|
|
97
|
+
let result = content;
|
|
98
|
+
|
|
99
|
+
for (const [key, value] of Object.entries(context)) {
|
|
100
|
+
// Simple variable replacement: {{ key }}
|
|
101
|
+
const simpleRegex = new RegExp(`\\{\\{\\s*${key}\\s*\\}\\}`, 'g');
|
|
102
|
+
result = result.replace(simpleRegex, String(value));
|
|
103
|
+
|
|
104
|
+
// With replace filter: {{ key | replace('a', 'b') }}
|
|
105
|
+
const replaceRegex = new RegExp(
|
|
106
|
+
`\\{\\{\\s*${key}\\s*\\|\\s*replace\\s*\\(\\s*['"]([^'"]+)['"]\\s*,\\s*['"]([^'"]*)['"]\\s*\\)\\s*\\}\\}`,
|
|
107
|
+
'g'
|
|
108
|
+
);
|
|
109
|
+
result = result.replace(replaceRegex, (match, from, to) => {
|
|
110
|
+
return String(value).replace(new RegExp(from, 'g'), to);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// With lower filter: {{ key | lower }}
|
|
114
|
+
const lowerRegex = new RegExp(`\\{\\{\\s*${key}\\s*\\|\\s*lower\\s*\\}\\}`, 'g');
|
|
115
|
+
result = result.replace(lowerRegex, String(value).toLowerCase());
|
|
116
|
+
|
|
117
|
+
// Combined: {{ key | replace('a', 'b') | lower }}
|
|
118
|
+
const combinedRegex = new RegExp(
|
|
119
|
+
`\\{\\{\\s*${key}\\s*\\|\\s*replace\\s*\\(\\s*['"]([^'"]+)['"]\\s*,\\s*['"]([^'"]*)['"]\\s*\\)\\s*\\|\\s*lower\\s*\\}\\}`,
|
|
120
|
+
'g'
|
|
121
|
+
);
|
|
122
|
+
result = result.replace(combinedRegex, (match, from, to) => {
|
|
123
|
+
return String(value).replace(new RegExp(from, 'g'), to).toLowerCase();
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function copyTemplateDir(src, dest, context) {
|
|
131
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
132
|
+
|
|
133
|
+
for (const entry of entries) {
|
|
134
|
+
const srcPath = path.join(src, entry.name);
|
|
135
|
+
const destName = entry.name.replace(/\.j2$/, '');
|
|
136
|
+
const destPath = path.join(dest, destName);
|
|
137
|
+
|
|
138
|
+
if (entry.isDirectory()) {
|
|
139
|
+
await fs.mkdir(destPath, { recursive: true });
|
|
140
|
+
await copyTemplateDir(srcPath, destPath, context);
|
|
141
|
+
} else {
|
|
142
|
+
let content = await fs.readFile(srcPath, 'utf-8');
|
|
143
|
+
|
|
144
|
+
// Render template if it's a .j2 file
|
|
145
|
+
if (entry.name.endsWith('.j2')) {
|
|
146
|
+
content = renderTemplate(content, context);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
await fs.writeFile(destPath, content);
|
|
150
|
+
|
|
151
|
+
// Make scripts executable
|
|
152
|
+
if (destName === 'rapidkit' || (destName.endsWith('.py') && destPath.includes('.rapidkit'))) {
|
|
153
|
+
await fs.chmod(destPath, 0o755);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Main
|
|
160
|
+
const args = process.argv.slice(2);
|
|
161
|
+
const projectPath = args[0];
|
|
162
|
+
const template = args[1] || 'fastapi';
|
|
163
|
+
const useDefaults = args.includes('--yes');
|
|
164
|
+
const skipGit = args.includes('--skip-git');
|
|
165
|
+
const skipInstall = args.includes('--skip-install');
|
|
166
|
+
|
|
167
|
+
if (!projectPath) {
|
|
168
|
+
console.error('Usage: node generator.js <project-path> <template> [--yes] [--skip-git] [--skip-install]');
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
generateProject(projectPath, template, useDefaults, skipGit, skipInstall).catch(err => {
|
|
173
|
+
console.error('Error:', err);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
});
|