kaven-cli 0.1.0-alpha.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/LICENSE +201 -0
- package/README.md +93 -0
- package/dist/commands/auth/login.js +44 -0
- package/dist/commands/auth/logout.js +25 -0
- package/dist/commands/auth/whoami.js +35 -0
- package/dist/commands/index.js +1 -0
- package/dist/commands/marketplace/install.js +59 -0
- package/dist/commands/marketplace/list.js +44 -0
- package/dist/commands/module/add.js +69 -0
- package/dist/commands/module/doctor.js +70 -0
- package/dist/commands/module/remove.js +58 -0
- package/dist/commands/modules/add.js +53 -0
- package/dist/commands/modules/list.js +40 -0
- package/dist/commands/modules/remove.js +54 -0
- package/dist/commands/telemetry/view.js +27 -0
- package/dist/core/AuthService.js +61 -0
- package/dist/core/ManifestParser.js +52 -0
- package/dist/core/MarkerService.js +62 -0
- package/dist/core/ModuleDoctor.js +162 -0
- package/dist/core/ModuleInstaller.js +66 -0
- package/dist/core/api/KavenApiClient.js +61 -0
- package/dist/core/auth/AuthManager.js +91 -0
- package/dist/core/index.js +1 -0
- package/dist/core/modules/Injector.js +86 -0
- package/dist/core/modules/ModuleInstaller.js +63 -0
- package/dist/core/modules/ModuleManager.js +59 -0
- package/dist/core/modules/ModuleRemover.js +60 -0
- package/dist/index.js +91 -0
- package/dist/infrastructure/Container.js +39 -0
- package/dist/infrastructure/MarketplaceClient.js +73 -0
- package/dist/infrastructure/TelemetryBuffer.js +71 -0
- package/dist/infrastructure/TransactionalFileSystem.js +74 -0
- package/dist/infrastructure/index.js +1 -0
- package/dist/lib/config.js +66 -0
- package/dist/lib/errors.js +32 -0
- package/dist/lib/logger.js +70 -0
- package/dist/types/manifest.js +45 -0
- package/dist/types/markers.js +10 -0
- package/dist/types/module.js +49 -0
- package/package.json +64 -0
|
@@ -0,0 +1,71 @@
|
|
|
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.TelemetryBuffer = 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 TelemetryBuffer {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.buffer = [];
|
|
13
|
+
this.logPath = path_1.default.join(os_1.default.homedir(), ".kaven", "telemetry.log");
|
|
14
|
+
}
|
|
15
|
+
static getInstance() {
|
|
16
|
+
if (!TelemetryBuffer.instance) {
|
|
17
|
+
TelemetryBuffer.instance = new TelemetryBuffer();
|
|
18
|
+
}
|
|
19
|
+
return TelemetryBuffer.instance;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Captura um evento de telemetria
|
|
23
|
+
*/
|
|
24
|
+
capture(event, metadata, duration) {
|
|
25
|
+
const telemetryEvent = {
|
|
26
|
+
event,
|
|
27
|
+
timestamp: new Date().toISOString(),
|
|
28
|
+
metadata,
|
|
29
|
+
duration,
|
|
30
|
+
};
|
|
31
|
+
this.buffer.push(telemetryEvent);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Persiste os eventos do buffer no arquivo local
|
|
35
|
+
*/
|
|
36
|
+
async flush() {
|
|
37
|
+
if (this.buffer.length === 0)
|
|
38
|
+
return;
|
|
39
|
+
try {
|
|
40
|
+
const logDir = path_1.default.dirname(this.logPath);
|
|
41
|
+
await fs_extra_1.default.ensureDir(logDir);
|
|
42
|
+
const lines = this.buffer.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
43
|
+
await fs_extra_1.default.appendFile(this.logPath, lines, "utf8");
|
|
44
|
+
this.buffer = [];
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
// Falha silenciosa na telemetria para não interromper fluxo principal
|
|
48
|
+
console.debug("Erro ao gravar telemetria:", error);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Recupera os últimos eventos registrados
|
|
53
|
+
*/
|
|
54
|
+
async getRecentEvents(limit = 20) {
|
|
55
|
+
if (!(await fs_extra_1.default.pathExists(this.logPath)))
|
|
56
|
+
return [];
|
|
57
|
+
try {
|
|
58
|
+
const content = await fs_extra_1.default.readFile(this.logPath, "utf8");
|
|
59
|
+
return content
|
|
60
|
+
.trim()
|
|
61
|
+
.split("\n")
|
|
62
|
+
.reverse()
|
|
63
|
+
.slice(0, limit)
|
|
64
|
+
.map((line) => JSON.parse(line));
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.TelemetryBuffer = TelemetryBuffer;
|
|
@@ -0,0 +1,74 @@
|
|
|
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.TransactionalFileSystem = void 0;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const glob_1 = require("glob");
|
|
10
|
+
class TransactionalFileSystem {
|
|
11
|
+
constructor(projectRoot, backupDir = ".agent/backups") {
|
|
12
|
+
this.projectRoot = projectRoot;
|
|
13
|
+
this.filesToBackup = [];
|
|
14
|
+
this.backupDir = path_1.default.join(projectRoot, backupDir);
|
|
15
|
+
this.backupId = `backup_${Date.now()}`;
|
|
16
|
+
}
|
|
17
|
+
async backup(filePaths) {
|
|
18
|
+
const backupPath = path_1.default.join(this.backupDir, this.backupId);
|
|
19
|
+
await fs_extra_1.default.ensureDir(backupPath);
|
|
20
|
+
for (const file of filePaths) {
|
|
21
|
+
const absolutePath = path_1.default.resolve(this.projectRoot, file);
|
|
22
|
+
if (!(await fs_extra_1.default.pathExists(absolutePath))) {
|
|
23
|
+
throw new Error(`File not found for backup: ${file}`);
|
|
24
|
+
}
|
|
25
|
+
const relativePath = path_1.default.relative(this.projectRoot, absolutePath);
|
|
26
|
+
const backupFile = path_1.default.join(backupPath, relativePath);
|
|
27
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(backupFile));
|
|
28
|
+
await fs_extra_1.default.copy(absolutePath, backupFile);
|
|
29
|
+
this.filesToBackup.push(absolutePath);
|
|
30
|
+
}
|
|
31
|
+
console.log(`📦 Backup created: ${this.backupId}`);
|
|
32
|
+
}
|
|
33
|
+
async rollback() {
|
|
34
|
+
const backupPath = path_1.default.join(this.backupDir, this.backupId);
|
|
35
|
+
if (!(await fs_extra_1.default.pathExists(backupPath))) {
|
|
36
|
+
throw new Error(`Backup not found: ${this.backupId}`);
|
|
37
|
+
}
|
|
38
|
+
const files = await (0, glob_1.glob)(`${backupPath}/**/*`, { nodir: true });
|
|
39
|
+
for (const backupFile of files) {
|
|
40
|
+
const relativePath = path_1.default.relative(backupPath, backupFile);
|
|
41
|
+
const targetFile = path_1.default.join(this.projectRoot, relativePath);
|
|
42
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(targetFile));
|
|
43
|
+
await fs_extra_1.default.copy(backupFile, targetFile, { overwrite: true });
|
|
44
|
+
}
|
|
45
|
+
console.log(`♻️ Rollback complete: ${this.backupId}`);
|
|
46
|
+
}
|
|
47
|
+
async commit() {
|
|
48
|
+
const backupPath = path_1.default.join(this.backupDir, this.backupId);
|
|
49
|
+
if (await fs_extra_1.default.pathExists(backupPath)) {
|
|
50
|
+
await fs_extra_1.default.remove(backupPath);
|
|
51
|
+
}
|
|
52
|
+
console.log(`✅ Transaction committed`);
|
|
53
|
+
}
|
|
54
|
+
getBackupId() {
|
|
55
|
+
return this.backupId;
|
|
56
|
+
}
|
|
57
|
+
async cleanup() {
|
|
58
|
+
if (!(await fs_extra_1.default.pathExists(this.backupDir)))
|
|
59
|
+
return;
|
|
60
|
+
const backups = await fs_extra_1.default.readdir(this.backupDir);
|
|
61
|
+
const now = Date.now();
|
|
62
|
+
const weekInMs = 7 * 24 * 60 * 60 * 1000;
|
|
63
|
+
for (const backup of backups) {
|
|
64
|
+
const match = backup.match(/backup_(\d+)/);
|
|
65
|
+
if (match) {
|
|
66
|
+
const timestamp = parseInt(match[1]);
|
|
67
|
+
if (now - timestamp > weekInMs) {
|
|
68
|
+
await fs_extra_1.default.remove(path_1.default.join(this.backupDir, backup));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.TransactionalFileSystem = TransactionalFileSystem;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1,66 @@
|
|
|
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.ConfigManager = exports.KavenConfigSchema = void 0;
|
|
7
|
+
const zod_1 = require("zod");
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const errors_1 = require("./errors");
|
|
11
|
+
exports.KavenConfigSchema = zod_1.z.object({
|
|
12
|
+
name: zod_1.z.string(),
|
|
13
|
+
version: zod_1.z.string(),
|
|
14
|
+
kaven: zod_1.z.object({
|
|
15
|
+
version: zod_1.z.string(),
|
|
16
|
+
features: zod_1.z.object({
|
|
17
|
+
multiTenant: zod_1.z.boolean().default(true),
|
|
18
|
+
database: zod_1.z.enum(['postgresql', 'mysql']).default('postgresql'),
|
|
19
|
+
payment: zod_1.z.enum(['stripe', 'paddle', 'pix', 'none']).default('none').optional(),
|
|
20
|
+
}),
|
|
21
|
+
modules: zod_1.z.object({
|
|
22
|
+
core: zod_1.z.record(zod_1.z.boolean()).default({}),
|
|
23
|
+
optional: zod_1.z.record(zod_1.z.boolean()).default({}),
|
|
24
|
+
}),
|
|
25
|
+
customizations: zod_1.z.object({
|
|
26
|
+
addedModules: zod_1.z.array(zod_1.z.string()).default([]),
|
|
27
|
+
removedModules: zod_1.z.array(zod_1.z.string()).default([]),
|
|
28
|
+
}).default({
|
|
29
|
+
addedModules: [],
|
|
30
|
+
removedModules: [],
|
|
31
|
+
}),
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
const CONFIG_FILENAME = 'kaven.config.json';
|
|
35
|
+
class ConfigManager {
|
|
36
|
+
static async load(projectRoot) {
|
|
37
|
+
const configPath = path_1.default.join(projectRoot, CONFIG_FILENAME);
|
|
38
|
+
if (!await fs_extra_1.default.pathExists(configPath)) {
|
|
39
|
+
throw new errors_1.ConfigError(`Configuration file not found at ${configPath}`);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const content = await fs_extra_1.default.readJson(configPath);
|
|
43
|
+
return exports.KavenConfigSchema.parse(content);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error instanceof zod_1.z.ZodError) {
|
|
47
|
+
throw new errors_1.ConfigError(`Invalid configuration: ${error.issues.map(e => `${e.path.join('.')}: ${e.message}`).join(', ')}`);
|
|
48
|
+
}
|
|
49
|
+
throw new errors_1.ConfigError(`Failed to read configuration: ${error}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
static async save(projectRoot, config) {
|
|
53
|
+
const configPath = path_1.default.join(projectRoot, CONFIG_FILENAME);
|
|
54
|
+
try {
|
|
55
|
+
const validated = exports.KavenConfigSchema.parse(config);
|
|
56
|
+
await fs_extra_1.default.writeJson(configPath, validated, { spaces: 2 });
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
throw new errors_1.ConfigError(`Failed to save configuration: ${error}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
static async exists(projectRoot) {
|
|
63
|
+
return fs_extra_1.default.pathExists(path_1.default.join(projectRoot, CONFIG_FILENAME));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.ConfigManager = ConfigManager;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthError = exports.ModuleError = exports.ConfigError = exports.KavenError = void 0;
|
|
4
|
+
class KavenError extends Error {
|
|
5
|
+
constructor(message, code = 'KAVEN_ERROR') {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.name = 'KavenError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.KavenError = KavenError;
|
|
12
|
+
class ConfigError extends KavenError {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message, 'CONFIG_ERROR');
|
|
15
|
+
this.name = 'ConfigError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.ConfigError = ConfigError;
|
|
19
|
+
class ModuleError extends KavenError {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message, 'MODULE_ERROR');
|
|
22
|
+
this.name = 'ModuleError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.ModuleError = ModuleError;
|
|
26
|
+
class AuthError extends KavenError {
|
|
27
|
+
constructor(message) {
|
|
28
|
+
super(message, 'AUTH_ERROR');
|
|
29
|
+
this.name = 'AuthError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.AuthError = AuthError;
|
|
@@ -0,0 +1,70 @@
|
|
|
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.Logger = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
class Logger {
|
|
10
|
+
static info(message) {
|
|
11
|
+
console.log(chalk_1.default.blue('ℹ'), message);
|
|
12
|
+
}
|
|
13
|
+
static succeedSpinner(message) {
|
|
14
|
+
this.success(message);
|
|
15
|
+
}
|
|
16
|
+
static success(message) {
|
|
17
|
+
if (this.spinner) {
|
|
18
|
+
this.spinner.succeed(chalk_1.default.green(message));
|
|
19
|
+
this.spinner = null;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
console.log(chalk_1.default.green('✔'), message);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
static warn(message) {
|
|
26
|
+
console.log(chalk_1.default.yellow('⚠'), message);
|
|
27
|
+
}
|
|
28
|
+
static error(message, error) {
|
|
29
|
+
if (this.spinner) {
|
|
30
|
+
this.spinner.fail(chalk_1.default.red(message));
|
|
31
|
+
this.spinner = null;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.error(chalk_1.default.red('✖'), message);
|
|
35
|
+
}
|
|
36
|
+
if (error instanceof Error) {
|
|
37
|
+
console.error(chalk_1.default.dim(error.stack));
|
|
38
|
+
}
|
|
39
|
+
else if (error) {
|
|
40
|
+
console.error(chalk_1.default.dim(JSON.stringify(error)));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
static startSpinner(text) {
|
|
44
|
+
if (this.spinner) {
|
|
45
|
+
this.spinner.text = text;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
this.spinner = (0, ora_1.default)(text).start();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
static stopSpinner() {
|
|
52
|
+
if (this.spinner) {
|
|
53
|
+
this.spinner.stop();
|
|
54
|
+
this.spinner = null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
static box(title, lines) {
|
|
58
|
+
const width = Math.max(title.length + 4, ...lines.map(l => l.length + 4));
|
|
59
|
+
const border = '─'.repeat(width);
|
|
60
|
+
console.log(chalk_1.default.cyan(`┌${border}┐`));
|
|
61
|
+
console.log(chalk_1.default.cyan(`│ ${chalk_1.default.bold(title.padEnd(width - 2))} │`));
|
|
62
|
+
console.log(chalk_1.default.cyan(`│${border}│`));
|
|
63
|
+
lines.forEach(line => {
|
|
64
|
+
console.log(chalk_1.default.cyan(`│ ${line.padEnd(width - 2)} │`));
|
|
65
|
+
});
|
|
66
|
+
console.log(chalk_1.default.cyan(`└${border}┘`));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.Logger = Logger;
|
|
70
|
+
Logger.spinner = null;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ModuleManifestSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const DependencySchema = zod_1.z.object({
|
|
6
|
+
npm: zod_1.z.array(zod_1.z.string()).default([]),
|
|
7
|
+
peerModules: zod_1.z.array(zod_1.z.string()).default([]),
|
|
8
|
+
kavenVersion: zod_1.z.string().default(">=0.1.0"),
|
|
9
|
+
});
|
|
10
|
+
const FileSetSchema = zod_1.z.object({
|
|
11
|
+
source: zod_1.z.string(),
|
|
12
|
+
dest: zod_1.z.string(),
|
|
13
|
+
});
|
|
14
|
+
const FilesSchema = zod_1.z.object({
|
|
15
|
+
backend: zod_1.z.array(FileSetSchema).default([]),
|
|
16
|
+
frontend: zod_1.z.array(FileSetSchema).default([]),
|
|
17
|
+
database: zod_1.z.array(FileSetSchema).default([]),
|
|
18
|
+
});
|
|
19
|
+
const InjectionSchema = zod_1.z.object({
|
|
20
|
+
file: zod_1.z.string(),
|
|
21
|
+
anchor: zod_1.z.string(),
|
|
22
|
+
code: zod_1.z.string(),
|
|
23
|
+
moduleName: zod_1.z.string().optional(),
|
|
24
|
+
});
|
|
25
|
+
const ScriptsSchema = zod_1.z.object({
|
|
26
|
+
postInstall: zod_1.z.string().nullable().default(null),
|
|
27
|
+
preRemove: zod_1.z.string().nullable().default(null),
|
|
28
|
+
});
|
|
29
|
+
const EnvVarSchema = zod_1.z.object({
|
|
30
|
+
key: zod_1.z.string(),
|
|
31
|
+
required: zod_1.z.boolean().default(false),
|
|
32
|
+
example: zod_1.z.string().optional(),
|
|
33
|
+
});
|
|
34
|
+
exports.ModuleManifestSchema = zod_1.z.object({
|
|
35
|
+
name: zod_1.z.string().min(1),
|
|
36
|
+
version: zod_1.z.string().regex(/^\d+\.\d+\.\d+$/),
|
|
37
|
+
description: zod_1.z.string().optional(),
|
|
38
|
+
author: zod_1.z.string().default("Kaven"),
|
|
39
|
+
license: zod_1.z.string().default("Proprietary"),
|
|
40
|
+
dependencies: DependencySchema,
|
|
41
|
+
files: FilesSchema,
|
|
42
|
+
injections: zod_1.z.array(InjectionSchema),
|
|
43
|
+
scripts: ScriptsSchema,
|
|
44
|
+
env: zod_1.z.array(EnvVarSchema).default([]),
|
|
45
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMarker = createMarker;
|
|
4
|
+
function createMarker(moduleName) {
|
|
5
|
+
return {
|
|
6
|
+
moduleName,
|
|
7
|
+
beginMarker: `// [KAVEN_MODULE:${moduleName} BEGIN]`,
|
|
8
|
+
endMarker: `// [KAVEN_MODULE:${moduleName} END]`,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ModuleManifestSchema = exports.InjectionSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.InjectionSchema = zod_1.z.object({
|
|
6
|
+
targetFile: zod_1.z.string(), // relative to project root
|
|
7
|
+
anchor: zod_1.z.string(), // e.g. "KAVEN_MODULE_IMPORTS"
|
|
8
|
+
content: zod_1.z.string(), // content to inject
|
|
9
|
+
strategy: zod_1.z.enum(['append', 'prepend', 'replace']).default('append'),
|
|
10
|
+
});
|
|
11
|
+
exports.ModuleManifestSchema = zod_1.z.object({
|
|
12
|
+
id: zod_1.z.string().uuid().optional(), // optional for local dev
|
|
13
|
+
slug: zod_1.z.string().min(3).regex(/^[a-z0-9-]+$/),
|
|
14
|
+
version: zod_1.z.string().regex(/^\d+\.\d+\.\d+.*$/), // SemVer
|
|
15
|
+
displayName: zod_1.z.string(),
|
|
16
|
+
description: zod_1.z.string(),
|
|
17
|
+
category: zod_1.z.string().default('features'),
|
|
18
|
+
publisher: zod_1.z.string().default('kaven'),
|
|
19
|
+
// Compatibility
|
|
20
|
+
compat: zod_1.z.object({
|
|
21
|
+
kaven: zod_1.z.string(), // SemVer range e.g. "^2.0.0"
|
|
22
|
+
node: zod_1.z.string().optional(),
|
|
23
|
+
}),
|
|
24
|
+
// Dependencies
|
|
25
|
+
dependencies: zod_1.z.record(zod_1.z.string()).optional(), // npm deps
|
|
26
|
+
devDependencies: zod_1.z.record(zod_1.z.string()).optional(),
|
|
27
|
+
peerModules: zod_1.z.record(zod_1.z.string()).optional(), // other kaven modules
|
|
28
|
+
// Configuration Requirements (Env Vars)
|
|
29
|
+
env: zod_1.z.array(zod_1.z.object({
|
|
30
|
+
key: zod_1.z.string(),
|
|
31
|
+
description: zod_1.z.string(),
|
|
32
|
+
required: zod_1.z.boolean().default(true),
|
|
33
|
+
defaultValue: zod_1.z.string().optional(),
|
|
34
|
+
})).default([]),
|
|
35
|
+
// File Copying mappings (TO-BE: flexible mappings)
|
|
36
|
+
// For AS-IS compatibility, we assume standard structure (api/admin)
|
|
37
|
+
// Injections
|
|
38
|
+
injections: zod_1.z.array(exports.InjectionSchema).default([]),
|
|
39
|
+
// Database
|
|
40
|
+
database: zod_1.z.object({
|
|
41
|
+
schemaPath: zod_1.z.string().optional(), // path to schema.prisma fragment
|
|
42
|
+
migrations: zod_1.z.boolean().default(false),
|
|
43
|
+
}).optional(),
|
|
44
|
+
// Tasks (hooks)
|
|
45
|
+
hooks: zod_1.z.object({
|
|
46
|
+
postInstall: zod_1.z.array(zod_1.z.string()).default([]),
|
|
47
|
+
preRemove: zod_1.z.array(zod_1.z.string()).default([]),
|
|
48
|
+
}).optional(),
|
|
49
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kaven-cli",
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
|
+
"description": "Kaven CLI - The official command line tool for Kaven",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"kaven": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"prepublishOnly": "pnpm run build && pnpm run quality",
|
|
16
|
+
"lint": "eslint 'src/**/*.{ts,tsx}' --max-warnings 0",
|
|
17
|
+
"lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"test:watch": "vitest watch",
|
|
20
|
+
"test:coverage": "vitest run --coverage",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"quality": "pnpm run lint && pnpm run typecheck && pnpm run test",
|
|
23
|
+
"quality:gate": "./.agent/scripts/quality-gate.sh",
|
|
24
|
+
"bootstrap": "./.agent/scripts/bootstrap.sh",
|
|
25
|
+
"evidence": "./.agent/scripts/evidence-bundle.sh",
|
|
26
|
+
"validate:evidence": "./.agent/scripts/validate-evidence.sh",
|
|
27
|
+
"create:pr": "./.agent/scripts/create-pr.sh",
|
|
28
|
+
"telemetry:view": "tail -f ~/.kaven/telemetry.log",
|
|
29
|
+
"telemetry:clear": "rm -f ~/.kaven/telemetry.log && touch ~/.kaven/telemetry.log"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"kaven",
|
|
33
|
+
"cli",
|
|
34
|
+
"developer-tools",
|
|
35
|
+
"saas",
|
|
36
|
+
"boilerplate"
|
|
37
|
+
],
|
|
38
|
+
"author": "Kaven",
|
|
39
|
+
"license": "Apache-2.0",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/KavenCompany/kaven-cli"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/fs-extra": "^11.0.4",
|
|
46
|
+
"@types/node": "^20.0.0",
|
|
47
|
+
"@typescript-eslint/eslint-plugin": "^8.53.1",
|
|
48
|
+
"@typescript-eslint/parser": "^8.53.1",
|
|
49
|
+
"eslint": "^8.0.0",
|
|
50
|
+
"typescript": "^5.0.0",
|
|
51
|
+
"vitest": "^1.0.0"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=20"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"chalk": "^5.6.2",
|
|
58
|
+
"commander": "^14.0.2",
|
|
59
|
+
"fs-extra": "^11.3.3",
|
|
60
|
+
"glob": "^13.0.0",
|
|
61
|
+
"ora": "^9.1.0",
|
|
62
|
+
"zod": "^4.3.6"
|
|
63
|
+
}
|
|
64
|
+
}
|