kaven-cli 0.3.5 → 0.4.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/dist/commands/config/features.js +1026 -0
- package/dist/commands/config/index.js +1 -34
- package/dist/commands/index.js +1 -0
- package/dist/commands/init/index.js +25 -37
- package/dist/commands/marketplace/browse.js +1 -34
- package/dist/commands/module/activate.js +206 -0
- package/dist/commands/module/publish.js +2 -35
- package/dist/commands/upgrade/index.js +6 -39
- package/dist/core/AuthService.js +2 -34
- package/dist/core/CacheManager.js +3 -0
- package/dist/core/ConfigManager.js +8 -7
- package/dist/core/ErrorRecovery.js +1 -0
- package/dist/core/LicenseService.js +3 -38
- package/dist/core/ModuleDoctor.js +3 -0
- package/dist/core/ModuleInstaller.js +5 -36
- package/dist/core/ProjectInitializer.js +15 -3
- package/dist/core/RegistryResolver.js +3 -2
- package/dist/core/SchemaActivator.js +270 -0
- package/dist/core/ScriptRunner.js +3 -2
- package/dist/core/index.js +1 -0
- package/dist/index.js +69 -2
- package/dist/infrastructure/Container.js +2 -4
- package/dist/infrastructure/MarketplaceClient.js +5 -3
- package/dist/infrastructure/TelemetryBuffer.js +3 -1
- package/dist/infrastructure/TransactionalFileSystem.js +4 -1
- package/dist/infrastructure/errors.js +2 -0
- package/dist/infrastructure/index.js +1 -0
- package/package.json +2 -1
|
@@ -11,7 +11,7 @@ const zod_1 = require("zod");
|
|
|
11
11
|
const CONFIG_DIR = path_1.default.join(os_1.default.homedir(), ".kaven");
|
|
12
12
|
const CONFIG_PATH = path_1.default.join(CONFIG_DIR, "config.json");
|
|
13
13
|
exports.configSchema = zod_1.z.object({
|
|
14
|
-
registry: zod_1.z.string().url().default("https://marketplace.kaven.
|
|
14
|
+
registry: zod_1.z.string().url().default("https://marketplace.kaven.site"),
|
|
15
15
|
telemetry: zod_1.z.boolean().default(true),
|
|
16
16
|
theme: zod_1.z.enum(["light", "dark"]).default("dark"),
|
|
17
17
|
locale: zod_1.z.string().default("en-US"),
|
|
@@ -29,9 +29,10 @@ exports.configSchema = zod_1.z.object({
|
|
|
29
29
|
.optional(),
|
|
30
30
|
});
|
|
31
31
|
class ConfigManager {
|
|
32
|
+
config;
|
|
32
33
|
constructor() {
|
|
33
34
|
this.config = {
|
|
34
|
-
registry: "https://marketplace.kaven.
|
|
35
|
+
registry: "https://marketplace.kaven.site",
|
|
35
36
|
telemetry: true,
|
|
36
37
|
theme: "dark",
|
|
37
38
|
locale: "en-US",
|
|
@@ -49,7 +50,7 @@ class ConfigManager {
|
|
|
49
50
|
else {
|
|
50
51
|
// If validation fails, use defaults
|
|
51
52
|
this.config = {
|
|
52
|
-
registry: "https://marketplace.kaven.
|
|
53
|
+
registry: "https://marketplace.kaven.site",
|
|
53
54
|
telemetry: true,
|
|
54
55
|
theme: "dark",
|
|
55
56
|
locale: "en-US",
|
|
@@ -59,7 +60,7 @@ class ConfigManager {
|
|
|
59
60
|
catch {
|
|
60
61
|
// If file is corrupted, start fresh
|
|
61
62
|
this.config = {
|
|
62
|
-
registry: "https://marketplace.kaven.
|
|
63
|
+
registry: "https://marketplace.kaven.site",
|
|
63
64
|
telemetry: true,
|
|
64
65
|
theme: "dark",
|
|
65
66
|
locale: "en-US",
|
|
@@ -69,7 +70,7 @@ class ConfigManager {
|
|
|
69
70
|
else {
|
|
70
71
|
// Initialize with defaults
|
|
71
72
|
this.config = {
|
|
72
|
-
registry: "https://marketplace.kaven.
|
|
73
|
+
registry: "https://marketplace.kaven.site",
|
|
73
74
|
telemetry: true,
|
|
74
75
|
theme: "dark",
|
|
75
76
|
locale: "en-US",
|
|
@@ -124,7 +125,7 @@ class ConfigManager {
|
|
|
124
125
|
*/
|
|
125
126
|
async reset() {
|
|
126
127
|
this.config = {
|
|
127
|
-
registry: "https://marketplace.kaven.
|
|
128
|
+
registry: "https://marketplace.kaven.site",
|
|
128
129
|
telemetry: true,
|
|
129
130
|
theme: "dark",
|
|
130
131
|
locale: "en-US",
|
|
@@ -142,7 +143,7 @@ class ConfigManager {
|
|
|
142
143
|
* Get registry URL (custom or default)
|
|
143
144
|
*/
|
|
144
145
|
getRegistry() {
|
|
145
|
-
return (this.config.customRegistry || this.config.registry || "https://marketplace.kaven.
|
|
146
|
+
return (this.config.customRegistry || this.config.registry || "https://marketplace.kaven.site");
|
|
146
147
|
}
|
|
147
148
|
/**
|
|
148
149
|
* Check if telemetry is enabled (can be overridden by env var)
|
|
@@ -1,37 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
4
|
};
|
|
@@ -43,9 +10,7 @@ const os_1 = __importDefault(require("os"));
|
|
|
43
10
|
const CACHE_FILE = path_1.default.join(os_1.default.homedir(), '.kaven', 'cache', 'licenses.json');
|
|
44
11
|
const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
|
|
45
12
|
class LicenseService {
|
|
46
|
-
|
|
47
|
-
this.cacheDir = path_1.default.join(os_1.default.homedir(), '.kaven', 'cache');
|
|
48
|
-
}
|
|
13
|
+
cacheDir = path_1.default.join(os_1.default.homedir(), '.kaven', 'cache');
|
|
49
14
|
/** Luhn mod-31 checksum format check (KAVEN-{TIER}-{8RANDOM}-{CHECKSUM}) */
|
|
50
15
|
isValidFormat(licenseKey) {
|
|
51
16
|
const pattern = /^KAVEN-(STARTER|COMPLETE|PRO|ENTERPRISE)-[A-Z0-9]{8}-[A-Z0-9]{2}$/;
|
|
@@ -90,7 +55,7 @@ class LicenseService {
|
|
|
90
55
|
throw new Error('Invalid license key format');
|
|
91
56
|
}
|
|
92
57
|
// 3. API validation
|
|
93
|
-
const { MarketplaceClient } = await
|
|
58
|
+
const { MarketplaceClient } = await import('../infrastructure/MarketplaceClient.js');
|
|
94
59
|
const client = new MarketplaceClient();
|
|
95
60
|
const result = await client.validateLicense(licenseKey, requiredTier);
|
|
96
61
|
// Cache on success
|
|
@@ -103,7 +68,7 @@ class LicenseService {
|
|
|
103
68
|
return { ...result, source: 'api' };
|
|
104
69
|
}
|
|
105
70
|
async getLicenseStatus(licenseKey) {
|
|
106
|
-
const { MarketplaceClient } = await
|
|
71
|
+
const { MarketplaceClient } = await import('../infrastructure/MarketplaceClient.js');
|
|
107
72
|
const client = new MarketplaceClient();
|
|
108
73
|
return client.getLicenseStatus(licenseKey);
|
|
109
74
|
}
|
|
@@ -8,6 +8,9 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const os_1 = __importDefault(require("os"));
|
|
10
10
|
class ModuleDoctor {
|
|
11
|
+
projectRoot;
|
|
12
|
+
markerService;
|
|
13
|
+
manifestParser;
|
|
11
14
|
constructor(projectRoot, markerService, manifestParser) {
|
|
12
15
|
this.projectRoot = projectRoot;
|
|
13
16
|
this.markerService = markerService;
|
|
@@ -1,37 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
4
|
};
|
|
@@ -43,6 +10,8 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
43
10
|
const path_1 = __importDefault(require("path"));
|
|
44
11
|
const chalk_1 = __importDefault(require("chalk"));
|
|
45
12
|
class ModuleInstaller {
|
|
13
|
+
projectRoot;
|
|
14
|
+
markerService;
|
|
46
15
|
constructor(projectRoot, markerService) {
|
|
47
16
|
this.projectRoot = projectRoot;
|
|
48
17
|
this.markerService = markerService;
|
|
@@ -73,7 +42,7 @@ class ModuleInstaller {
|
|
|
73
42
|
}
|
|
74
43
|
/** Find text-based project source files to check for markers. */
|
|
75
44
|
async findProjectFiles() {
|
|
76
|
-
const { glob } = await
|
|
45
|
+
const { glob } = await import("glob");
|
|
77
46
|
const patterns = ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"];
|
|
78
47
|
const ignore = ["**/node_modules/**", "**/.next/**", "**/dist/**", "**/build/**"];
|
|
79
48
|
const files = [];
|
|
@@ -112,7 +81,7 @@ class ModuleInstaller {
|
|
|
112
81
|
}
|
|
113
82
|
// Inject environment variables if defined in module.json
|
|
114
83
|
if (!options?.skipEnv && moduleJson?.env?.length) {
|
|
115
|
-
const { EnvManager } = await
|
|
84
|
+
const { EnvManager } = await import('./EnvManager.js');
|
|
116
85
|
const envManager = new EnvManager();
|
|
117
86
|
const envVarDefs = moduleJson.env.map((e) => ({
|
|
118
87
|
name: e.key,
|
|
@@ -141,7 +110,7 @@ class ModuleInstaller {
|
|
|
141
110
|
const filesToModify = Array.from(new Set(manifest.injections.map((inj) => inj.file)));
|
|
142
111
|
await tx.backup(filesToModify);
|
|
143
112
|
// Remove environment variables before removing files
|
|
144
|
-
const { EnvManager } = await
|
|
113
|
+
const { EnvManager } = await import('./EnvManager.js');
|
|
145
114
|
const envManager = new EnvManager();
|
|
146
115
|
envManager.removeEnvVars(manifest.name, {
|
|
147
116
|
projectDir: this.projectRoot,
|
|
@@ -40,9 +40,21 @@ class ProjectInitializer {
|
|
|
40
40
|
}
|
|
41
41
|
return { valid: true };
|
|
42
42
|
}
|
|
43
|
-
/** Clone the template
|
|
44
|
-
async cloneTemplate(targetDir) {
|
|
45
|
-
const
|
|
43
|
+
/** Clone the template (from Git or local path) into targetDir. */
|
|
44
|
+
async cloneTemplate(targetDir, templateSource) {
|
|
45
|
+
const source = templateSource || TEMPLATE_REPO;
|
|
46
|
+
console.log(`[INIT] Clone Source: ${source}`);
|
|
47
|
+
console.log(`[INIT] Target Dir: ${targetDir}`);
|
|
48
|
+
// If it's a local path that exists, copy it instead of cloning
|
|
49
|
+
if (await fs_extra_1.default.pathExists(source) && (source.startsWith("/") || source.startsWith("./") || source.startsWith("../"))) {
|
|
50
|
+
console.log(`[INIT] Local Path Detected. Copying...`);
|
|
51
|
+
await fs_extra_1.default.copy(source, targetDir, {
|
|
52
|
+
filter: (src) => !src.includes("node_modules") && !src.includes(".git") && !src.includes(".turbo")
|
|
53
|
+
});
|
|
54
|
+
console.log(`[INIT] Local Copy Done.`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const exitCode = await runCommand("git", ["clone", "--depth", "1", source, targetDir], process.cwd());
|
|
46
58
|
if (exitCode !== 0) {
|
|
47
59
|
throw new Error(`git clone failed with exit code ${exitCode}`);
|
|
48
60
|
}
|
|
@@ -8,6 +8,7 @@ const AuthService_1 = require("./AuthService");
|
|
|
8
8
|
* C2.5: Registry resolver — handles both official and custom registries
|
|
9
9
|
*/
|
|
10
10
|
class RegistryResolver {
|
|
11
|
+
authService;
|
|
11
12
|
constructor(authService) {
|
|
12
13
|
this.authService = authService || new AuthService_1.AuthService();
|
|
13
14
|
}
|
|
@@ -25,7 +26,7 @@ class RegistryResolver {
|
|
|
25
26
|
const registry = await this.getActiveRegistry();
|
|
26
27
|
const client = new MarketplaceClient_1.MarketplaceClient(this.authService);
|
|
27
28
|
// Set custom registry if configured
|
|
28
|
-
if (registry !== "https://marketplace.kaven.
|
|
29
|
+
if (registry !== "https://marketplace.kaven.site") {
|
|
29
30
|
client.baseUrl = registry;
|
|
30
31
|
}
|
|
31
32
|
return client;
|
|
@@ -85,7 +86,7 @@ class RegistryResolver {
|
|
|
85
86
|
await ConfigManager_1.configManager.initialize();
|
|
86
87
|
const config = ConfigManager_1.configManager.getAll();
|
|
87
88
|
return {
|
|
88
|
-
default: config.registry || "https://marketplace.kaven.
|
|
89
|
+
default: config.registry || "https://marketplace.kaven.site",
|
|
89
90
|
custom: config.customRegistry,
|
|
90
91
|
active: await this.getActiveRegistry(),
|
|
91
92
|
};
|
|
@@ -0,0 +1,270 @@
|
|
|
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.SchemaActivator = exports.KAVEN_MODULES = void 0;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
exports.KAVEN_MODULES = [
|
|
10
|
+
{
|
|
11
|
+
id: "auth",
|
|
12
|
+
label: "Auth & Identity",
|
|
13
|
+
description: "Gestão de usuários, permissões e sessões",
|
|
14
|
+
models: ["User", "Role", "Capability", "AuthSession", "AuditLog"],
|
|
15
|
+
enums: ["UserRole"],
|
|
16
|
+
dependsOn: [],
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: "billing",
|
|
20
|
+
label: "Billing",
|
|
21
|
+
description: "Faturamento, assinaturas e pagamentos",
|
|
22
|
+
models: ["Invoice", "Order", "Subscription", "Plan", "Payment", "Product"],
|
|
23
|
+
enums: [],
|
|
24
|
+
dependsOn: [],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "projects",
|
|
28
|
+
label: "Projects",
|
|
29
|
+
description: "Gestão de projetos e tasks",
|
|
30
|
+
models: ["Project", "Task"],
|
|
31
|
+
enums: ["ProjectStatus", "TaskStatus", "TaskPriority"],
|
|
32
|
+
dependsOn: [],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "notifications",
|
|
36
|
+
label: "Notifications",
|
|
37
|
+
description: "Notificações e preferências de usuário",
|
|
38
|
+
models: ["Notification", "UserPreference"],
|
|
39
|
+
enums: [],
|
|
40
|
+
dependsOn: [],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "marketing-tracking",
|
|
44
|
+
label: "Marketing Tracking",
|
|
45
|
+
description: "Observabilidade de anúncios, GTM, GA4 e Meta CAPI",
|
|
46
|
+
models: ["TrackingEvent"],
|
|
47
|
+
enums: ["TrackingSource"],
|
|
48
|
+
dependsOn: [],
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
// ============================================================
|
|
52
|
+
// Marcadores de seção no schema
|
|
53
|
+
// ============================================================
|
|
54
|
+
const BEGIN_MARKER = (moduleId) => `// [KAVEN_MODULE:${moduleId.toUpperCase()} BEGIN]`;
|
|
55
|
+
const END_MARKER = (moduleId) => `// [KAVEN_MODULE:${moduleId.toUpperCase()} END]`;
|
|
56
|
+
// ============================================================
|
|
57
|
+
// SchemaActivator — lê/escreve schema.extended.prisma
|
|
58
|
+
// ============================================================
|
|
59
|
+
class SchemaActivator {
|
|
60
|
+
schemaPath;
|
|
61
|
+
constructor(projectRoot) {
|
|
62
|
+
this.schemaPath = path_1.default.join(projectRoot, "packages", "database", "prisma", "schema.extended.prisma");
|
|
63
|
+
}
|
|
64
|
+
/** Verifica se o schema existe no projeto */
|
|
65
|
+
async exists() {
|
|
66
|
+
return fs_extra_1.default.pathExists(this.schemaPath);
|
|
67
|
+
}
|
|
68
|
+
/** Caminho absoluto do schema */
|
|
69
|
+
get path() {
|
|
70
|
+
return this.schemaPath;
|
|
71
|
+
}
|
|
72
|
+
/** Lê o conteúdo atual do schema */
|
|
73
|
+
async readSchema() {
|
|
74
|
+
return fs_extra_1.default.readFile(this.schemaPath, "utf-8");
|
|
75
|
+
}
|
|
76
|
+
/** Persiste o conteúdo no schema */
|
|
77
|
+
async writeSchema(content) {
|
|
78
|
+
await fs_extra_1.default.writeFile(this.schemaPath, content, "utf-8");
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Detecta se um módulo está ativo no schema.
|
|
82
|
+
*
|
|
83
|
+
* Estratégia:
|
|
84
|
+
* 1. Se existirem marcadores BEGIN/END: verifica se o conteúdo dentro
|
|
85
|
+
* dos marcadores NÃO está completamente comentado.
|
|
86
|
+
* 2. Se não houver marcadores: verifica se algum dos models principais
|
|
87
|
+
* do módulo está presente e não comentado no arquivo.
|
|
88
|
+
*/
|
|
89
|
+
async getModuleStatus(def) {
|
|
90
|
+
const content = await this.readSchema();
|
|
91
|
+
const begin = BEGIN_MARKER(def.id);
|
|
92
|
+
const end = END_MARKER(def.id);
|
|
93
|
+
const hasMarkers = content.includes(begin) && content.includes(end);
|
|
94
|
+
let active = false;
|
|
95
|
+
if (hasMarkers) {
|
|
96
|
+
const block = this.extractBlock(content, def.id);
|
|
97
|
+
active = block !== null && this.isBlockActive(block);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
// Sem marcadores: verifica presença de pelo menos um model descomentado
|
|
101
|
+
active = def.models.some((modelName) => this.isModelActive(content, modelName));
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
id: def.id,
|
|
105
|
+
label: def.label,
|
|
106
|
+
description: def.description,
|
|
107
|
+
models: def.models,
|
|
108
|
+
dependsOn: def.dependsOn,
|
|
109
|
+
active,
|
|
110
|
+
hasMarkers,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/** Ativa um módulo: se tem marcadores, descomenta o bloco; senão, injeta o bloco */
|
|
114
|
+
async activateModule(def) {
|
|
115
|
+
const content = await this.readSchema();
|
|
116
|
+
const begin = BEGIN_MARKER(def.id);
|
|
117
|
+
const end = END_MARKER(def.id);
|
|
118
|
+
if (content.includes(begin) && content.includes(end)) {
|
|
119
|
+
const updated = this.uncommentBlock(content, def.id);
|
|
120
|
+
await this.writeSchema(updated);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// Módulo não tem seção marcada — sem template para injetar
|
|
124
|
+
throw new Error(`O módulo "${def.id}" não possui uma seção marcada (BEGIN/END) no schema.\n` +
|
|
125
|
+
`Adicione o bloco do módulo manualmente com os marcadores:\n` +
|
|
126
|
+
` ${begin}\n` +
|
|
127
|
+
` ... models do módulo ...\n` +
|
|
128
|
+
` ${end}`);
|
|
129
|
+
}
|
|
130
|
+
/** Desativa um módulo: comenta todos os models do bloco */
|
|
131
|
+
async deactivateModule(def) {
|
|
132
|
+
const content = await this.readSchema();
|
|
133
|
+
const begin = BEGIN_MARKER(def.id);
|
|
134
|
+
const end = END_MARKER(def.id);
|
|
135
|
+
if (!content.includes(begin) || !content.includes(end)) {
|
|
136
|
+
throw new Error(`O módulo "${def.id}" não possui marcadores BEGIN/END no schema. ` +
|
|
137
|
+
`Não é possível desativar automaticamente.`);
|
|
138
|
+
}
|
|
139
|
+
const updated = this.commentBlock(content, def.id);
|
|
140
|
+
await this.writeSchema(updated);
|
|
141
|
+
}
|
|
142
|
+
// ──────────────────────────────────────────────
|
|
143
|
+
// Helpers de manipulação de blocos
|
|
144
|
+
// ──────────────────────────────────────────────
|
|
145
|
+
/**
|
|
146
|
+
* Extrai o conteúdo entre os marcadores BEGIN e END (exclusive).
|
|
147
|
+
* Retorna null se os marcadores não forem encontrados.
|
|
148
|
+
*/
|
|
149
|
+
extractBlock(content, moduleId) {
|
|
150
|
+
const begin = BEGIN_MARKER(moduleId);
|
|
151
|
+
const end = END_MARKER(moduleId);
|
|
152
|
+
const lines = content.split("\n");
|
|
153
|
+
let beginIdx = -1;
|
|
154
|
+
let endIdx = -1;
|
|
155
|
+
for (let i = 0; i < lines.length; i++) {
|
|
156
|
+
if (lines[i].includes(begin))
|
|
157
|
+
beginIdx = i;
|
|
158
|
+
if (lines[i].includes(end) && beginIdx !== -1) {
|
|
159
|
+
endIdx = i;
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (beginIdx === -1 || endIdx === -1)
|
|
164
|
+
return null;
|
|
165
|
+
return lines.slice(beginIdx + 1, endIdx).join("\n");
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Verifica se um bloco tem ao menos uma linha não-comentada relevante
|
|
169
|
+
* (ignora linhas vazias e comentários simples).
|
|
170
|
+
*/
|
|
171
|
+
isBlockActive(block) {
|
|
172
|
+
return block.split("\n").some((line) => {
|
|
173
|
+
const trimmed = line.trim();
|
|
174
|
+
return (trimmed.length > 0 &&
|
|
175
|
+
!trimmed.startsWith("//") &&
|
|
176
|
+
!trimmed.startsWith("/*") &&
|
|
177
|
+
!trimmed.startsWith("*"));
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Verifica se um model específico está ativo (não comentado) no schema.
|
|
182
|
+
* Procura pela linha `model ModelName {` sem `//` antes.
|
|
183
|
+
*/
|
|
184
|
+
isModelActive(content, modelName) {
|
|
185
|
+
const lines = content.split("\n");
|
|
186
|
+
for (const line of lines) {
|
|
187
|
+
const trimmed = line.trim();
|
|
188
|
+
if (trimmed.startsWith(`model ${modelName}`) &&
|
|
189
|
+
!line.trimStart().startsWith("//")) {
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Comenta todas as linhas não-comentadas dentro do bloco BEGIN/END.
|
|
197
|
+
*/
|
|
198
|
+
commentBlock(content, moduleId) {
|
|
199
|
+
const begin = BEGIN_MARKER(moduleId);
|
|
200
|
+
const end = END_MARKER(moduleId);
|
|
201
|
+
const lines = content.split("\n");
|
|
202
|
+
let inBlock = false;
|
|
203
|
+
const result = [];
|
|
204
|
+
for (const line of lines) {
|
|
205
|
+
if (line.includes(begin)) {
|
|
206
|
+
inBlock = true;
|
|
207
|
+
result.push(line);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (line.includes(end)) {
|
|
211
|
+
inBlock = false;
|
|
212
|
+
result.push(line);
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (inBlock) {
|
|
216
|
+
const trimmed = line.trim();
|
|
217
|
+
if (trimmed.length === 0) {
|
|
218
|
+
result.push(line);
|
|
219
|
+
}
|
|
220
|
+
else if (trimmed.startsWith("//")) {
|
|
221
|
+
result.push(line); // já comentado
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
result.push(`// ${line}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
result.push(line);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return result.join("\n");
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Remove `// ` do início das linhas dentro do bloco BEGIN/END.
|
|
235
|
+
*/
|
|
236
|
+
uncommentBlock(content, moduleId) {
|
|
237
|
+
const begin = BEGIN_MARKER(moduleId);
|
|
238
|
+
const end = END_MARKER(moduleId);
|
|
239
|
+
const lines = content.split("\n");
|
|
240
|
+
let inBlock = false;
|
|
241
|
+
const result = [];
|
|
242
|
+
for (const line of lines) {
|
|
243
|
+
if (line.includes(begin)) {
|
|
244
|
+
inBlock = true;
|
|
245
|
+
result.push(line);
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (line.includes(end)) {
|
|
249
|
+
inBlock = false;
|
|
250
|
+
result.push(line);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (inBlock) {
|
|
254
|
+
// Remove exatamente um nível de comentário preservando identação
|
|
255
|
+
const match = line.match(/^(\s*)\/\/\s?(.*)$/);
|
|
256
|
+
if (match) {
|
|
257
|
+
result.push(match[1] + match[2]);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
result.push(line);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
result.push(line);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return result.join("\n");
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
exports.SchemaActivator = SchemaActivator;
|
|
@@ -8,7 +8,8 @@ const child_process_1 = require("child_process");
|
|
|
8
8
|
const readline_1 = __importDefault(require("readline"));
|
|
9
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
10
|
class ScriptRunner {
|
|
11
|
-
|
|
11
|
+
timeoutMs;
|
|
12
|
+
constructor(timeoutMs = 60_000) {
|
|
12
13
|
this.timeoutMs = timeoutMs;
|
|
13
14
|
}
|
|
14
15
|
async runScript(script, label, skipConfirmation = false) {
|
|
@@ -37,7 +38,7 @@ class ScriptRunner {
|
|
|
37
38
|
child.kill('SIGTERM');
|
|
38
39
|
setTimeout(() => {
|
|
39
40
|
child.kill('SIGKILL');
|
|
40
|
-
},
|
|
41
|
+
}, 5_000);
|
|
41
42
|
}, this.timeoutMs);
|
|
42
43
|
child.on('close', (code) => {
|
|
43
44
|
clearTimeout(timer);
|
package/dist/core/index.js
CHANGED