kaven-cli 0.4.1-alpha.0 → 0.4.2-alpha.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/README.md +181 -207
- package/dist/EnvManager-NMS3NMIE.js +15 -0
- package/dist/MarketplaceClient-YCFH2VU4.js +1 -0
- package/dist/chunk-JHLQ46NG.js +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +242 -304
- package/dist/tier-table-DQMPQSI2.js +6 -0
- package/package.json +26 -11
- package/dist/EnvManager-GQMEZ6NV.js +0 -158
- package/dist/MarketplaceClient-IJGRQRC4.js +0 -7
- package/dist/chunk-3RG5ZIWI.js +0 -10
- package/dist/chunk-GHZX5OAA.js +0 -455
- package/dist/commands/aiox/index.js +0 -20
- package/dist/commands/auth/login.js +0 -122
- package/dist/commands/auth/logout.js +0 -23
- package/dist/commands/auth/whoami.js +0 -36
- package/dist/commands/cache/index.js +0 -43
- package/dist/commands/config/features.js +0 -161
- package/dist/commands/config/index.js +0 -95
- package/dist/commands/index.js +0 -2
- package/dist/commands/init/aiox-bootstrap.js +0 -83
- package/dist/commands/init/index.js +0 -210
- package/dist/commands/init-ci/index.js +0 -153
- package/dist/commands/license/index.js +0 -10
- package/dist/commands/license/status.js +0 -44
- package/dist/commands/license/tier-table.js +0 -46
- package/dist/commands/marketplace/browse.js +0 -186
- package/dist/commands/marketplace/install.js +0 -263
- package/dist/commands/marketplace/list.js +0 -122
- package/dist/commands/module/activate.js +0 -245
- package/dist/commands/module/add.js +0 -69
- package/dist/commands/module/doctor.js +0 -175
- package/dist/commands/module/list.js +0 -51
- package/dist/commands/module/publish.js +0 -258
- package/dist/commands/module/remove.js +0 -58
- package/dist/commands/telemetry/view.js +0 -27
- package/dist/commands/upgrade/check.js +0 -162
- package/dist/commands/upgrade/index.js +0 -185
- package/dist/core/AuthService.js +0 -222
- package/dist/core/CacheManager.js +0 -154
- package/dist/core/ConfigManager.js +0 -166
- package/dist/core/EnvManager.js +0 -196
- package/dist/core/ErrorRecovery.js +0 -192
- package/dist/core/LicenseService.js +0 -83
- package/dist/core/ManifestParser.js +0 -52
- package/dist/core/MarkerService.js +0 -62
- package/dist/core/ModuleDoctor.js +0 -451
- package/dist/core/ModuleInstaller.js +0 -169
- package/dist/core/ProjectInitializer.js +0 -183
- package/dist/core/RegistryResolver.js +0 -95
- package/dist/core/SchemaActivator.js +0 -278
- package/dist/core/ScriptRunner.js +0 -73
- package/dist/core/SignatureVerifier.js +0 -75
- package/dist/core/index.js +0 -2
- package/dist/infrastructure/Container.js +0 -37
- package/dist/infrastructure/MarketplaceClient.js +0 -425
- package/dist/infrastructure/TelemetryBuffer.js +0 -73
- package/dist/infrastructure/TransactionalFileSystem.js +0 -77
- package/dist/infrastructure/errors.js +0 -63
- package/dist/infrastructure/index.js +0 -2
- package/dist/lib/capabilities-catalog.js +0 -73
- package/dist/lib/module-registry.js +0 -47
- package/dist/lib/schema-modifier.js +0 -40
- package/dist/tier-table-LAL6PAVW.js +0 -52
- package/dist/types/auth.js +0 -2
- package/dist/types/manifest.js +0 -45
- package/dist/types/markers.js +0 -10
- package/dist/types/marketplace.js +0 -2
|
@@ -1,451 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ModuleDoctor = void 0;
|
|
7
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const os_1 = __importDefault(require("os"));
|
|
10
|
-
class ModuleDoctor {
|
|
11
|
-
projectRoot;
|
|
12
|
-
markerService;
|
|
13
|
-
manifestParser;
|
|
14
|
-
constructor(projectRoot, markerService, manifestParser) {
|
|
15
|
-
this.projectRoot = projectRoot;
|
|
16
|
-
this.markerService = markerService;
|
|
17
|
-
this.manifestParser = manifestParser;
|
|
18
|
-
}
|
|
19
|
-
async checkAll() {
|
|
20
|
-
const results = [];
|
|
21
|
-
results.push(...(await this.checkAnchors()));
|
|
22
|
-
results.push(...(await this.checkMarkers()));
|
|
23
|
-
results.push(...(await this.checkDependencies()));
|
|
24
|
-
results.push(...(await this.checkSchemaMerge()));
|
|
25
|
-
results.push(...(await this.checkEnvCompleteness()));
|
|
26
|
-
results.push(...(await this.checkLicense()));
|
|
27
|
-
results.push(...(await this.checkFrameworkVersion()));
|
|
28
|
-
results.push(...(await this.checkPrismaClientSync()));
|
|
29
|
-
return results;
|
|
30
|
-
}
|
|
31
|
-
async checkAnchors() {
|
|
32
|
-
const results = [];
|
|
33
|
-
const expectedAnchors = [
|
|
34
|
-
{ file: "apps/api/src/app.ts", anchor: "// [KAVEN_MODULE_IMPORTS]" },
|
|
35
|
-
{ file: "apps/api/src/app.ts", anchor: "// [KAVEN_MODULE_HOOKS]" },
|
|
36
|
-
{ file: "apps/api/src/app.ts", anchor: "// [KAVEN_MODULE_REGISTRATION]" },
|
|
37
|
-
];
|
|
38
|
-
for (const { file, anchor } of expectedAnchors) {
|
|
39
|
-
const filePath = path_1.default.join(this.projectRoot, file);
|
|
40
|
-
if (!(await fs_extra_1.default.pathExists(filePath))) {
|
|
41
|
-
results.push({
|
|
42
|
-
type: "anchor",
|
|
43
|
-
severity: "warning",
|
|
44
|
-
message: `File not found: ${file}`,
|
|
45
|
-
file,
|
|
46
|
-
fixable: false,
|
|
47
|
-
});
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
const content = await fs_extra_1.default.readFile(filePath, "utf-8");
|
|
51
|
-
if (!content.includes(anchor)) {
|
|
52
|
-
results.push({
|
|
53
|
-
type: "anchor",
|
|
54
|
-
severity: "error",
|
|
55
|
-
message: `Missing anchor: ${anchor}`,
|
|
56
|
-
file,
|
|
57
|
-
fixable: false,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return results;
|
|
62
|
-
}
|
|
63
|
-
async checkMarkers() {
|
|
64
|
-
const results = [];
|
|
65
|
-
const config = await this.readKavenConfig();
|
|
66
|
-
const installedModules = config.modules.filter((m) => m.installed);
|
|
67
|
-
for (const module of installedModules) {
|
|
68
|
-
const manifestPath = path_1.default.join(this.projectRoot, ".kaven/modules", module.name, "module.json");
|
|
69
|
-
if (!(await fs_extra_1.default.pathExists(manifestPath))) {
|
|
70
|
-
results.push({
|
|
71
|
-
type: "marker",
|
|
72
|
-
severity: "error",
|
|
73
|
-
message: `Manifest not found for installed module: ${module.name}`,
|
|
74
|
-
fixable: false,
|
|
75
|
-
});
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
try {
|
|
79
|
-
const manifest = await this.manifestParser.parse(manifestPath);
|
|
80
|
-
for (const injection of manifest.injections) {
|
|
81
|
-
const filePath = path_1.default.join(this.projectRoot, injection.file);
|
|
82
|
-
if (!(await fs_extra_1.default.pathExists(filePath))) {
|
|
83
|
-
results.push({
|
|
84
|
-
type: "marker",
|
|
85
|
-
severity: "error",
|
|
86
|
-
message: `Injection target not found: ${injection.file}`,
|
|
87
|
-
file: injection.file,
|
|
88
|
-
fixable: false,
|
|
89
|
-
});
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
const content = await fs_extra_1.default.readFile(filePath, "utf-8");
|
|
93
|
-
const moduleName = injection.moduleName || module.name;
|
|
94
|
-
const detection = this.markerService.detectMarkers(content, moduleName);
|
|
95
|
-
if (!detection.found) {
|
|
96
|
-
results.push({
|
|
97
|
-
type: "marker",
|
|
98
|
-
severity: "error",
|
|
99
|
-
message: `Module ${module.name} not injected in ${injection.file}`,
|
|
100
|
-
file: injection.file,
|
|
101
|
-
fixable: true,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
results.push({
|
|
108
|
-
type: "marker",
|
|
109
|
-
severity: "error",
|
|
110
|
-
message: `Invalid manifest for module ${module.name}: ${error instanceof Error ? error.message : String(error)}`,
|
|
111
|
-
fixable: false,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return results;
|
|
116
|
-
}
|
|
117
|
-
async checkDependencies() {
|
|
118
|
-
const results = [];
|
|
119
|
-
const config = await this.readKavenConfig();
|
|
120
|
-
const installedModules = config.modules.filter((m) => m.installed);
|
|
121
|
-
const packageJsonPath = path_1.default.join(this.projectRoot, "package.json");
|
|
122
|
-
if (!(await fs_extra_1.default.pathExists(packageJsonPath))) {
|
|
123
|
-
results.push({
|
|
124
|
-
type: "dependency",
|
|
125
|
-
severity: "error",
|
|
126
|
-
message: "package.json not found",
|
|
127
|
-
fixable: false,
|
|
128
|
-
});
|
|
129
|
-
return results;
|
|
130
|
-
}
|
|
131
|
-
const packageJson = await fs_extra_1.default.readJSON(packageJsonPath);
|
|
132
|
-
for (const module of installedModules) {
|
|
133
|
-
const manifestPath = path_1.default.join(this.projectRoot, ".kaven/modules", module.name, "module.json");
|
|
134
|
-
if (!(await fs_extra_1.default.pathExists(manifestPath)))
|
|
135
|
-
continue;
|
|
136
|
-
try {
|
|
137
|
-
const manifest = await this.manifestParser.parse(manifestPath);
|
|
138
|
-
for (const dep of manifest.dependencies.npm) {
|
|
139
|
-
const [name] = dep.split("@");
|
|
140
|
-
const hasInDeps = packageJson.dependencies?.[name];
|
|
141
|
-
const hasInDevDeps = packageJson.devDependencies?.[name];
|
|
142
|
-
if (!hasInDeps && !hasInDevDeps) {
|
|
143
|
-
results.push({
|
|
144
|
-
type: "dependency",
|
|
145
|
-
severity: "warning",
|
|
146
|
-
message: `Missing npm dependency: ${dep}`,
|
|
147
|
-
fixable: true,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
catch {
|
|
153
|
-
// Ignorar erros de manifest aqui, já tratados em checkMarkers
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return results;
|
|
157
|
-
}
|
|
158
|
-
// ──────────────────────────────────────────────────────────
|
|
159
|
-
// C2.4: New enhanced checks
|
|
160
|
-
// ──────────────────────────────────────────────────────────
|
|
161
|
-
/** Check that the base Prisma schema exists and has no merge conflicts. */
|
|
162
|
-
async checkSchemaMerge() {
|
|
163
|
-
const results = [];
|
|
164
|
-
const baseSchemaPath = path_1.default.join(this.projectRoot, "packages/database/prisma/schema.base.prisma");
|
|
165
|
-
if (!(await fs_extra_1.default.pathExists(baseSchemaPath))) {
|
|
166
|
-
results.push({
|
|
167
|
-
type: "dependency",
|
|
168
|
-
severity: "warning",
|
|
169
|
-
message: "Prisma base schema not found: packages/database/prisma/schema.base.prisma",
|
|
170
|
-
file: "packages/database/prisma/schema.base.prisma",
|
|
171
|
-
fixable: false,
|
|
172
|
-
});
|
|
173
|
-
return results;
|
|
174
|
-
}
|
|
175
|
-
// Check for git merge conflict markers
|
|
176
|
-
const schemaDir = path_1.default.dirname(baseSchemaPath);
|
|
177
|
-
try {
|
|
178
|
-
const schemaFiles = await fs_extra_1.default.readdir(schemaDir);
|
|
179
|
-
for (const schemaFile of schemaFiles) {
|
|
180
|
-
if (!schemaFile.endsWith(".prisma"))
|
|
181
|
-
continue;
|
|
182
|
-
const filePath = path_1.default.join(schemaDir, schemaFile);
|
|
183
|
-
const content = await fs_extra_1.default.readFile(filePath, "utf-8");
|
|
184
|
-
if (content.includes("<<<<<<<")) {
|
|
185
|
-
results.push({
|
|
186
|
-
type: "marker",
|
|
187
|
-
severity: "error",
|
|
188
|
-
message: `Merge conflict detected in schema file: ${schemaFile}`,
|
|
189
|
-
file: path_1.default.join("packages/database/prisma", schemaFile),
|
|
190
|
-
fixable: false,
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
catch {
|
|
196
|
-
// Non-critical
|
|
197
|
-
}
|
|
198
|
-
if (results.length === 0) {
|
|
199
|
-
results.push({
|
|
200
|
-
type: "dependency",
|
|
201
|
-
severity: "info",
|
|
202
|
-
message: "Prisma schema integrity OK",
|
|
203
|
-
fixable: false,
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
return results;
|
|
207
|
-
}
|
|
208
|
-
/** Check that .env has all keys defined in .env.example (non-optional). */
|
|
209
|
-
async checkEnvCompleteness() {
|
|
210
|
-
const results = [];
|
|
211
|
-
const envExamplePath = path_1.default.join(this.projectRoot, ".env.example");
|
|
212
|
-
const envPath = path_1.default.join(this.projectRoot, ".env");
|
|
213
|
-
if (!(await fs_extra_1.default.pathExists(envExamplePath))) {
|
|
214
|
-
results.push({
|
|
215
|
-
type: "dependency",
|
|
216
|
-
severity: "info",
|
|
217
|
-
message: ".env.example not found — skipping env completeness check",
|
|
218
|
-
fixable: false,
|
|
219
|
-
});
|
|
220
|
-
return results;
|
|
221
|
-
}
|
|
222
|
-
if (!(await fs_extra_1.default.pathExists(envPath))) {
|
|
223
|
-
results.push({
|
|
224
|
-
type: "dependency",
|
|
225
|
-
severity: "warning",
|
|
226
|
-
message: ".env file not found. Copy .env.example to .env and fill in values",
|
|
227
|
-
file: ".env",
|
|
228
|
-
fixable: false,
|
|
229
|
-
});
|
|
230
|
-
return results;
|
|
231
|
-
}
|
|
232
|
-
const exampleContent = await fs_extra_1.default.readFile(envExamplePath, "utf-8");
|
|
233
|
-
const envContent = await fs_extra_1.default.readFile(envPath, "utf-8");
|
|
234
|
-
// Parse keys: lines that are KEY=VALUE (not comments, not blank)
|
|
235
|
-
const parseKeys = (content) => {
|
|
236
|
-
const keys = new Set();
|
|
237
|
-
for (const line of content.split("\n")) {
|
|
238
|
-
const trimmed = line.trim();
|
|
239
|
-
if (trimmed.startsWith("#") || !trimmed.includes("="))
|
|
240
|
-
continue;
|
|
241
|
-
const key = trimmed.split("=")[0].trim();
|
|
242
|
-
if (key)
|
|
243
|
-
keys.add(key);
|
|
244
|
-
}
|
|
245
|
-
return keys;
|
|
246
|
-
};
|
|
247
|
-
const exampleKeys = parseKeys(exampleContent);
|
|
248
|
-
const envKeys = parseKeys(envContent);
|
|
249
|
-
const missingKeys = [];
|
|
250
|
-
for (const key of exampleKeys) {
|
|
251
|
-
if (!envKeys.has(key)) {
|
|
252
|
-
missingKeys.push(key);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
if (missingKeys.length > 0) {
|
|
256
|
-
results.push({
|
|
257
|
-
type: "dependency",
|
|
258
|
-
severity: "warning",
|
|
259
|
-
message: `Missing env vars in .env: ${missingKeys.join(", ")}`,
|
|
260
|
-
file: ".env",
|
|
261
|
-
fixable: true,
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
results.push({
|
|
266
|
-
type: "dependency",
|
|
267
|
-
severity: "info",
|
|
268
|
-
message: "Env vars completeness OK",
|
|
269
|
-
fixable: false,
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
return results;
|
|
273
|
-
}
|
|
274
|
-
/** Check if the stored license is present and not expired. */
|
|
275
|
-
async checkLicense() {
|
|
276
|
-
const results = [];
|
|
277
|
-
const licensePath = path_1.default.join(os_1.default.homedir(), ".kaven", "license.json");
|
|
278
|
-
if (!(await fs_extra_1.default.pathExists(licensePath))) {
|
|
279
|
-
results.push({
|
|
280
|
-
type: "dependency",
|
|
281
|
-
severity: "warning",
|
|
282
|
-
message: "No license found at ~/.kaven/license.json. Run 'kaven license status' to set up.",
|
|
283
|
-
fixable: false,
|
|
284
|
-
});
|
|
285
|
-
return results;
|
|
286
|
-
}
|
|
287
|
-
try {
|
|
288
|
-
const licenseData = await fs_extra_1.default.readJson(licensePath);
|
|
289
|
-
if (licenseData.expiresAt) {
|
|
290
|
-
const expiresAt = new Date(licenseData.expiresAt).getTime();
|
|
291
|
-
if (Date.now() > expiresAt) {
|
|
292
|
-
results.push({
|
|
293
|
-
type: "dependency",
|
|
294
|
-
severity: "error",
|
|
295
|
-
message: `License expired on ${licenseData.expiresAt}. Run 'kaven upgrade' to renew.`,
|
|
296
|
-
fixable: false,
|
|
297
|
-
});
|
|
298
|
-
return results;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
results.push({
|
|
302
|
-
type: "dependency",
|
|
303
|
-
severity: "info",
|
|
304
|
-
message: `License valid (tier: ${licenseData.tier || "unknown"})`,
|
|
305
|
-
fixable: false,
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
catch {
|
|
309
|
-
results.push({
|
|
310
|
-
type: "dependency",
|
|
311
|
-
severity: "warning",
|
|
312
|
-
message: "Could not read license file. Try 'kaven license status'.",
|
|
313
|
-
fixable: false,
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
return results;
|
|
317
|
-
}
|
|
318
|
-
/** Check if the framework version in package.json is compatible. */
|
|
319
|
-
async checkFrameworkVersion() {
|
|
320
|
-
const results = [];
|
|
321
|
-
const packageJsonPath = path_1.default.join(this.projectRoot, "package.json");
|
|
322
|
-
if (!(await fs_extra_1.default.pathExists(packageJsonPath))) {
|
|
323
|
-
results.push({
|
|
324
|
-
type: "dependency",
|
|
325
|
-
severity: "info",
|
|
326
|
-
message: "package.json not found — skipping framework version check",
|
|
327
|
-
fixable: false,
|
|
328
|
-
});
|
|
329
|
-
return results;
|
|
330
|
-
}
|
|
331
|
-
try {
|
|
332
|
-
const packageJson = await fs_extra_1.default.readJSON(packageJsonPath);
|
|
333
|
-
const kavenCoreVersion = packageJson.dependencies?.["@kaven/core"] ||
|
|
334
|
-
packageJson.devDependencies?.["@kaven/core"];
|
|
335
|
-
if (!kavenCoreVersion) {
|
|
336
|
-
results.push({
|
|
337
|
-
type: "dependency",
|
|
338
|
-
severity: "info",
|
|
339
|
-
message: "@kaven/core not found in dependencies — not a Kaven framework project",
|
|
340
|
-
fixable: false,
|
|
341
|
-
});
|
|
342
|
-
return results;
|
|
343
|
-
}
|
|
344
|
-
// Minimum required semver range
|
|
345
|
-
const MINIMUM_VERSION = "1.0.0";
|
|
346
|
-
const versionStr = kavenCoreVersion.replace(/[\^~>=<]/, "").split(" ")[0];
|
|
347
|
-
const parts = versionStr.split(".").map(Number);
|
|
348
|
-
const minParts = MINIMUM_VERSION.split(".").map(Number);
|
|
349
|
-
let compatible = true;
|
|
350
|
-
for (let i = 0; i < 3; i++) {
|
|
351
|
-
if ((parts[i] || 0) > (minParts[i] || 0))
|
|
352
|
-
break;
|
|
353
|
-
if ((parts[i] || 0) < (minParts[i] || 0)) {
|
|
354
|
-
compatible = false;
|
|
355
|
-
break;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
if (!compatible) {
|
|
359
|
-
results.push({
|
|
360
|
-
type: "dependency",
|
|
361
|
-
severity: "warning",
|
|
362
|
-
message: `@kaven/core version ${kavenCoreVersion} may be outdated. Minimum: ^${MINIMUM_VERSION}`,
|
|
363
|
-
fixable: false,
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
|
-
results.push({
|
|
368
|
-
type: "dependency",
|
|
369
|
-
severity: "info",
|
|
370
|
-
message: `Framework version OK (${kavenCoreVersion})`,
|
|
371
|
-
fixable: false,
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
catch {
|
|
376
|
-
results.push({
|
|
377
|
-
type: "dependency",
|
|
378
|
-
severity: "info",
|
|
379
|
-
message: "Could not determine framework version",
|
|
380
|
-
fixable: false,
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
return results;
|
|
384
|
-
}
|
|
385
|
-
/** Check if Prisma client is generated and up-to-date. */
|
|
386
|
-
async checkPrismaClientSync() {
|
|
387
|
-
const results = [];
|
|
388
|
-
const prismaClientPath = path_1.default.join(this.projectRoot, "node_modules/@prisma/client");
|
|
389
|
-
const schemaPath = path_1.default.join(this.projectRoot, "prisma/schema.prisma");
|
|
390
|
-
if (!(await fs_extra_1.default.pathExists(prismaClientPath))) {
|
|
391
|
-
results.push({
|
|
392
|
-
type: "dependency",
|
|
393
|
-
severity: "warning",
|
|
394
|
-
message: "@prisma/client not found. Run 'npx prisma generate' to generate the client.",
|
|
395
|
-
fixable: true,
|
|
396
|
-
});
|
|
397
|
-
return results;
|
|
398
|
-
}
|
|
399
|
-
if (!(await fs_extra_1.default.pathExists(schemaPath))) {
|
|
400
|
-
results.push({
|
|
401
|
-
type: "dependency",
|
|
402
|
-
severity: "info",
|
|
403
|
-
message: "prisma/schema.prisma not found — skipping Prisma sync check",
|
|
404
|
-
fixable: false,
|
|
405
|
-
});
|
|
406
|
-
return results;
|
|
407
|
-
}
|
|
408
|
-
try {
|
|
409
|
-
const schemaStat = await fs_extra_1.default.stat(schemaPath);
|
|
410
|
-
const clientStat = await fs_extra_1.default.stat(prismaClientPath);
|
|
411
|
-
if (schemaStat.mtime > clientStat.mtime) {
|
|
412
|
-
results.push({
|
|
413
|
-
type: "dependency",
|
|
414
|
-
severity: "warning",
|
|
415
|
-
message: "Prisma schema was modified after client generation. Run 'npx prisma generate'.",
|
|
416
|
-
fixable: true,
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
else {
|
|
420
|
-
results.push({
|
|
421
|
-
type: "dependency",
|
|
422
|
-
severity: "info",
|
|
423
|
-
message: "Prisma client is up to date",
|
|
424
|
-
fixable: false,
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
catch {
|
|
429
|
-
results.push({
|
|
430
|
-
type: "dependency",
|
|
431
|
-
severity: "info",
|
|
432
|
-
message: "Could not compare Prisma schema and client timestamps",
|
|
433
|
-
fixable: false,
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
return results;
|
|
437
|
-
}
|
|
438
|
-
async readKavenConfig() {
|
|
439
|
-
const configPath = path_1.default.join(this.projectRoot, "kaven.json");
|
|
440
|
-
if (!(await fs_extra_1.default.pathExists(configPath))) {
|
|
441
|
-
return { modules: [] };
|
|
442
|
-
}
|
|
443
|
-
try {
|
|
444
|
-
return await fs_extra_1.default.readJSON(configPath);
|
|
445
|
-
}
|
|
446
|
-
catch {
|
|
447
|
-
return { modules: [] };
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
exports.ModuleDoctor = ModuleDoctor;
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ModuleInstaller = void 0;
|
|
7
|
-
const TransactionalFileSystem_1 = require("../infrastructure/TransactionalFileSystem");
|
|
8
|
-
const ScriptRunner_js_1 = require("./ScriptRunner.js");
|
|
9
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
-
class ModuleInstaller {
|
|
13
|
-
projectRoot;
|
|
14
|
-
markerService;
|
|
15
|
-
constructor(projectRoot, markerService) {
|
|
16
|
-
this.projectRoot = projectRoot;
|
|
17
|
-
this.markerService = markerService;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Check whether the given module slug is already installed by scanning
|
|
21
|
-
* project files for its begin/end markers.
|
|
22
|
-
*/
|
|
23
|
-
async isModuleInstalled(moduleName) {
|
|
24
|
-
try {
|
|
25
|
-
const filesToCheck = await this.findProjectFiles();
|
|
26
|
-
for (const filePath of filesToCheck) {
|
|
27
|
-
try {
|
|
28
|
-
const content = await fs_extra_1.default.readFile(filePath, "utf-8");
|
|
29
|
-
if (this.markerService.hasModule(content, moduleName)) {
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
// Skip unreadable files
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
/** Find text-based project source files to check for markers. */
|
|
44
|
-
async findProjectFiles() {
|
|
45
|
-
const { glob } = await import("glob");
|
|
46
|
-
const patterns = ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"];
|
|
47
|
-
const ignore = ["**/node_modules/**", "**/.next/**", "**/dist/**", "**/build/**"];
|
|
48
|
-
const files = [];
|
|
49
|
-
for (const pattern of patterns) {
|
|
50
|
-
const found = await glob(pattern, {
|
|
51
|
-
cwd: this.projectRoot,
|
|
52
|
-
absolute: true,
|
|
53
|
-
ignore,
|
|
54
|
-
});
|
|
55
|
-
files.push(...found);
|
|
56
|
-
}
|
|
57
|
-
return [...new Set(files)];
|
|
58
|
-
}
|
|
59
|
-
async install(manifest, options) {
|
|
60
|
-
const tx = new TransactionalFileSystem_1.TransactionalFileSystem(this.projectRoot);
|
|
61
|
-
try {
|
|
62
|
-
const filesToModify = Array.from(new Set(manifest.injections.map((inj) => inj.file)));
|
|
63
|
-
await tx.backup(filesToModify);
|
|
64
|
-
for (const injection of manifest.injections) {
|
|
65
|
-
await this.injectCode(injection);
|
|
66
|
-
}
|
|
67
|
-
await tx.commit();
|
|
68
|
-
// Run postInstall lifecycle scripts if defined in module.json
|
|
69
|
-
const moduleJson = await this.readManifest(this.projectRoot);
|
|
70
|
-
if (moduleJson?.scripts?.postInstall?.length) {
|
|
71
|
-
const runner = new ScriptRunner_js_1.ScriptRunner();
|
|
72
|
-
try {
|
|
73
|
-
await runner.runScripts(moduleJson.scripts.postInstall.map((s) => ({ ...s, cwd: this.projectRoot })), 'postInstall', false);
|
|
74
|
-
}
|
|
75
|
-
catch (err) {
|
|
76
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
77
|
-
console.warn(chalk_1.default.yellow(`
|
|
78
|
-
⚠ PostInstall script failed: ${errMsg}`));
|
|
79
|
-
console.warn(chalk_1.default.dim(' The module is installed. Run the script manually if needed.'));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
// Inject environment variables if defined in module.json
|
|
83
|
-
if (!options?.skipEnv && moduleJson?.env?.length) {
|
|
84
|
-
const { EnvManager } = await import('./EnvManager.js');
|
|
85
|
-
const envManager = new EnvManager();
|
|
86
|
-
const envVarDefs = moduleJson.env.map((e) => ({
|
|
87
|
-
name: e.key,
|
|
88
|
-
description: e.example ?? e.key,
|
|
89
|
-
required: e.required ?? false,
|
|
90
|
-
}));
|
|
91
|
-
await envManager.injectEnvVars(manifest.name, envVarDefs, {
|
|
92
|
-
projectDir: this.projectRoot,
|
|
93
|
-
envFile: options?.envFile,
|
|
94
|
-
skipEnv: options?.skipEnv,
|
|
95
|
-
skipConfirmation: options?.yes,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
catch (error) {
|
|
100
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
101
|
-
console.error(`❌ Installation failed: ${errorMessage}`);
|
|
102
|
-
console.log(`🔄 Rolling back...`);
|
|
103
|
-
await tx.rollback();
|
|
104
|
-
throw error;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
async uninstall(manifest, options) {
|
|
108
|
-
const tx = new TransactionalFileSystem_1.TransactionalFileSystem(this.projectRoot);
|
|
109
|
-
try {
|
|
110
|
-
const filesToModify = Array.from(new Set(manifest.injections.map((inj) => inj.file)));
|
|
111
|
-
await tx.backup(filesToModify);
|
|
112
|
-
// Remove environment variables before removing files
|
|
113
|
-
const { EnvManager } = await import('./EnvManager.js');
|
|
114
|
-
const envManager = new EnvManager();
|
|
115
|
-
envManager.removeEnvVars(manifest.name, {
|
|
116
|
-
projectDir: this.projectRoot,
|
|
117
|
-
skipEnv: options?.skipEnv,
|
|
118
|
-
});
|
|
119
|
-
// Run preRemove lifecycle scripts if defined in module.json
|
|
120
|
-
const moduleJson = await this.readManifest(this.projectRoot);
|
|
121
|
-
if (moduleJson?.scripts?.preRemove?.length) {
|
|
122
|
-
const runner = new ScriptRunner_js_1.ScriptRunner();
|
|
123
|
-
try {
|
|
124
|
-
await runner.runScripts(moduleJson.scripts.preRemove.map((s) => ({ ...s, cwd: this.projectRoot })), 'preRemove', false);
|
|
125
|
-
}
|
|
126
|
-
catch (err) {
|
|
127
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
128
|
-
console.warn(chalk_1.default.yellow(`
|
|
129
|
-
⚠ PreRemove script failed: ${errMsg}`));
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
// Na desinstalação, removemos por arquivo para evitar múltiplas tentativas
|
|
133
|
-
// de remover marcadores que o regex global já removeu.
|
|
134
|
-
for (const fileName of filesToModify) {
|
|
135
|
-
await this.removeCode(fileName, manifest.name);
|
|
136
|
-
}
|
|
137
|
-
await tx.commit();
|
|
138
|
-
}
|
|
139
|
-
catch (error) {
|
|
140
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
141
|
-
console.error(`❌ Removal failed: ${errorMessage}`);
|
|
142
|
-
console.log(`🔄 Rolling back...`);
|
|
143
|
-
await tx.rollback();
|
|
144
|
-
throw error;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
async injectCode(injection) {
|
|
148
|
-
const filePath = path_1.default.join(this.projectRoot, injection.file);
|
|
149
|
-
const content = await fs_extra_1.default.readFile(filePath, "utf-8");
|
|
150
|
-
const updated = this.markerService.injectModule(content, injection.anchor, injection.moduleName || "unnamed", injection.code);
|
|
151
|
-
await fs_extra_1.default.writeFile(filePath, updated);
|
|
152
|
-
}
|
|
153
|
-
async removeCode(fileName, moduleName) {
|
|
154
|
-
const filePath = path_1.default.join(this.projectRoot, fileName);
|
|
155
|
-
const content = await fs_extra_1.default.readFile(filePath, "utf-8");
|
|
156
|
-
const updated = this.markerService.removeModule(content, moduleName);
|
|
157
|
-
await fs_extra_1.default.writeFile(filePath, updated);
|
|
158
|
-
}
|
|
159
|
-
async readManifest(dir) {
|
|
160
|
-
try {
|
|
161
|
-
const raw = await fs_extra_1.default.readFile(path_1.default.join(dir, 'module.json'), 'utf-8');
|
|
162
|
-
return JSON.parse(raw);
|
|
163
|
-
}
|
|
164
|
-
catch {
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
exports.ModuleInstaller = ModuleInstaller;
|