kaven-cli 0.1.0-alpha.1 → 0.3.5
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 +284 -45
- package/README.pt-BR.md +334 -0
- package/dist/commands/auth/login.js +97 -19
- package/dist/commands/auth/logout.js +4 -6
- package/dist/commands/auth/whoami.js +12 -11
- package/dist/commands/cache/index.js +43 -0
- package/dist/commands/config/index.js +128 -0
- package/dist/commands/init/index.js +209 -0
- package/dist/commands/init-ci/index.js +153 -0
- package/dist/commands/license/index.js +10 -0
- package/dist/commands/license/status.js +44 -0
- package/dist/commands/license/tier-table.js +46 -0
- package/dist/commands/marketplace/browse.js +219 -0
- package/dist/commands/marketplace/install.js +233 -29
- package/dist/commands/marketplace/list.js +94 -16
- package/dist/commands/module/doctor.js +143 -38
- package/dist/commands/module/publish.js +291 -0
- package/dist/commands/upgrade/check.js +162 -0
- package/dist/commands/upgrade/index.js +218 -0
- package/dist/core/AuthService.js +207 -14
- package/dist/core/CacheManager.js +151 -0
- package/dist/core/ConfigManager.js +165 -0
- package/dist/core/EnvManager.js +196 -0
- package/dist/core/ErrorRecovery.js +191 -0
- package/dist/core/LicenseService.js +118 -0
- package/dist/core/ModuleDoctor.js +290 -4
- package/dist/core/ModuleInstaller.js +136 -2
- package/dist/core/ProjectInitializer.js +154 -0
- package/dist/core/RegistryResolver.js +94 -0
- package/dist/core/ScriptRunner.js +72 -0
- package/dist/core/SignatureVerifier.js +75 -0
- package/dist/index.js +265 -20
- package/dist/infrastructure/MarketplaceClient.js +388 -64
- package/dist/infrastructure/errors.js +61 -0
- package/dist/types/auth.js +2 -0
- package/dist/types/marketplace.js +2 -0
- package/package.json +23 -4
- package/dist/commands/modules/add.js +0 -53
- package/dist/commands/modules/list.js +0 -40
- package/dist/commands/modules/remove.js +0 -54
- package/dist/core/api/KavenApiClient.js +0 -61
- package/dist/core/auth/AuthManager.js +0 -91
- package/dist/core/modules/Injector.js +0 -86
- package/dist/core/modules/ModuleInstaller.js +0 -63
- package/dist/core/modules/ModuleManager.js +0 -59
- package/dist/core/modules/ModuleRemover.js +0 -60
- package/dist/lib/config.js +0 -66
- package/dist/lib/errors.js +0 -32
- package/dist/lib/logger.js +0 -70
- package/dist/types/module.js +0 -49
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RegistryResolver = void 0;
|
|
4
|
+
const ConfigManager_1 = require("./ConfigManager");
|
|
5
|
+
const MarketplaceClient_1 = require("../infrastructure/MarketplaceClient");
|
|
6
|
+
const AuthService_1 = require("./AuthService");
|
|
7
|
+
/**
|
|
8
|
+
* C2.5: Registry resolver — handles both official and custom registries
|
|
9
|
+
*/
|
|
10
|
+
class RegistryResolver {
|
|
11
|
+
constructor(authService) {
|
|
12
|
+
this.authService = authService || new AuthService_1.AuthService();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get the active registry URL (custom or default)
|
|
16
|
+
*/
|
|
17
|
+
async getActiveRegistry() {
|
|
18
|
+
await ConfigManager_1.configManager.initialize();
|
|
19
|
+
return ConfigManager_1.configManager.getRegistry();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get marketplace client for active registry
|
|
23
|
+
*/
|
|
24
|
+
async getMarketplaceClient() {
|
|
25
|
+
const registry = await this.getActiveRegistry();
|
|
26
|
+
const client = new MarketplaceClient_1.MarketplaceClient(this.authService);
|
|
27
|
+
// Set custom registry if configured
|
|
28
|
+
if (registry !== "https://marketplace.kaven.sh") {
|
|
29
|
+
client.baseUrl = registry;
|
|
30
|
+
}
|
|
31
|
+
return client;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validate registry URL is accessible
|
|
35
|
+
*/
|
|
36
|
+
async validateRegistry(url) {
|
|
37
|
+
try {
|
|
38
|
+
const response = await fetch(`${url}/health`);
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
return {
|
|
41
|
+
valid: false,
|
|
42
|
+
error: `Registry returned ${response.status} ${response.statusText}`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return { valid: true };
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
return {
|
|
49
|
+
valid: false,
|
|
50
|
+
error: `Failed to connect: ${error instanceof Error ? error.message : String(error)}`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Set custom registry
|
|
56
|
+
*/
|
|
57
|
+
async setCustomRegistry(url) {
|
|
58
|
+
// Validate URL format
|
|
59
|
+
try {
|
|
60
|
+
new URL(url);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
throw new Error(`Invalid URL format: ${url}`);
|
|
64
|
+
}
|
|
65
|
+
// Validate registry is accessible
|
|
66
|
+
const validation = await this.validateRegistry(url);
|
|
67
|
+
if (!validation.valid) {
|
|
68
|
+
throw new Error(`Registry validation failed: ${validation.error}`);
|
|
69
|
+
}
|
|
70
|
+
// Save to config
|
|
71
|
+
await ConfigManager_1.configManager.initialize();
|
|
72
|
+
await ConfigManager_1.configManager.set("customRegistry", url);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Reset to default registry
|
|
76
|
+
*/
|
|
77
|
+
async resetToDefaultRegistry() {
|
|
78
|
+
await ConfigManager_1.configManager.initialize();
|
|
79
|
+
await ConfigManager_1.configManager.set("customRegistry", undefined);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* List all available registries (default + custom)
|
|
83
|
+
*/
|
|
84
|
+
async listRegistries() {
|
|
85
|
+
await ConfigManager_1.configManager.initialize();
|
|
86
|
+
const config = ConfigManager_1.configManager.getAll();
|
|
87
|
+
return {
|
|
88
|
+
default: config.registry || "https://marketplace.kaven.sh",
|
|
89
|
+
custom: config.customRegistry,
|
|
90
|
+
active: await this.getActiveRegistry(),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.RegistryResolver = RegistryResolver;
|
|
@@ -0,0 +1,72 @@
|
|
|
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.ScriptRunner = void 0;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const readline_1 = __importDefault(require("readline"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
class ScriptRunner {
|
|
11
|
+
constructor(timeoutMs = 60000) {
|
|
12
|
+
this.timeoutMs = timeoutMs;
|
|
13
|
+
}
|
|
14
|
+
async runScript(script, label, skipConfirmation = false) {
|
|
15
|
+
if (!skipConfirmation) {
|
|
16
|
+
const confirmed = await this.confirm(`Run ${label} script: ${script.command} ${(script.args ?? []).join(' ')}?`);
|
|
17
|
+
if (!confirmed) {
|
|
18
|
+
console.log(chalk_1.default.dim(` Skipping ${label} script.`));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
const child = (0, child_process_1.spawn)(script.command, script.args ?? [], {
|
|
24
|
+
cwd: script.cwd,
|
|
25
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
26
|
+
shell: true,
|
|
27
|
+
});
|
|
28
|
+
const prefix = chalk_1.default.dim(`[${label}] `);
|
|
29
|
+
child.stdout?.on('data', (data) => {
|
|
30
|
+
process.stdout.write(prefix + data.toString());
|
|
31
|
+
});
|
|
32
|
+
child.stderr?.on('data', (data) => {
|
|
33
|
+
process.stderr.write(prefix + chalk_1.default.yellow(data.toString()));
|
|
34
|
+
});
|
|
35
|
+
const timer = setTimeout(() => {
|
|
36
|
+
console.warn(chalk_1.default.yellow(`\n ⚠ ${label} script timed out after ${this.timeoutMs / 1000}s, sending SIGTERM...`));
|
|
37
|
+
child.kill('SIGTERM');
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
child.kill('SIGKILL');
|
|
40
|
+
}, 5000);
|
|
41
|
+
}, this.timeoutMs);
|
|
42
|
+
child.on('close', (code) => {
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
if (code === 0 || code === null) {
|
|
45
|
+
resolve();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
reject(new Error(`${label} script exited with code ${code}`));
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
child.on('error', (err) => {
|
|
52
|
+
clearTimeout(timer);
|
|
53
|
+
reject(err);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async runScripts(scripts, label, skipConfirmation = false) {
|
|
58
|
+
for (const script of scripts) {
|
|
59
|
+
await this.runScript(script, label, skipConfirmation);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
confirm(message) {
|
|
63
|
+
return new Promise((resolve) => {
|
|
64
|
+
const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
65
|
+
rl.question(`\n ${message} [y/N] `, (answer) => {
|
|
66
|
+
rl.close();
|
|
67
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.ScriptRunner = ScriptRunner;
|
|
@@ -0,0 +1,75 @@
|
|
|
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.computeFileChecksum = computeFileChecksum;
|
|
7
|
+
exports.verifyEd25519Signature = verifyEd25519Signature;
|
|
8
|
+
exports.verifyDownload = verifyDownload;
|
|
9
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
11
|
+
const errors_1 = require("../infrastructure/errors");
|
|
12
|
+
/**
|
|
13
|
+
* Compute SHA-256 hex checksum of a file.
|
|
14
|
+
*/
|
|
15
|
+
async function computeFileChecksum(filePath) {
|
|
16
|
+
const data = await fs_extra_1.default.readFile(filePath);
|
|
17
|
+
return crypto_1.default.createHash("sha256").update(data).digest("hex");
|
|
18
|
+
}
|
|
19
|
+
const HEX_PATTERN = /^[0-9a-fA-F]+$/;
|
|
20
|
+
/**
|
|
21
|
+
* Decode a signature string that may be hex or base64 encoded.
|
|
22
|
+
* Ed25519 signatures are always 64 bytes:
|
|
23
|
+
* - hex: 128 chars, only [0-9a-fA-F]
|
|
24
|
+
* - base64: 88 chars, may contain +/=
|
|
25
|
+
*/
|
|
26
|
+
function decodeSignature(encoded) {
|
|
27
|
+
if (HEX_PATTERN.test(encoded) && encoded.length === 128) {
|
|
28
|
+
return Buffer.from(encoded, "hex");
|
|
29
|
+
}
|
|
30
|
+
return Buffer.from(encoded, "base64");
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Verify Ed25519 signature against a SHA-256 checksum.
|
|
34
|
+
*
|
|
35
|
+
* Accepts signature in either hex or base64 encoding.
|
|
36
|
+
* Tolerates signatures made over checksum with trailing newline
|
|
37
|
+
* (common when signing via `echo checksum > file && openssl sign`).
|
|
38
|
+
*/
|
|
39
|
+
function verifyEd25519Signature(checksum, signature, publicKeyBase64) {
|
|
40
|
+
try {
|
|
41
|
+
const publicKey = crypto_1.default.createPublicKey({
|
|
42
|
+
key: Buffer.from(publicKeyBase64, "base64"),
|
|
43
|
+
type: "spki",
|
|
44
|
+
format: "der",
|
|
45
|
+
});
|
|
46
|
+
const sigBuffer = decodeSignature(signature);
|
|
47
|
+
if (crypto_1.default.verify(null, Buffer.from(checksum), publicKey, sigBuffer)) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
// Tolerate trailing newline from shell-based signing
|
|
51
|
+
return crypto_1.default.verify(null, Buffer.from(checksum + "\n"), publicKey, sigBuffer);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Verify a downloaded module tarball:
|
|
59
|
+
* 1. Compute SHA-256 checksum and compare to expected
|
|
60
|
+
* 2. Verify Ed25519 signature of checksum with publisher key
|
|
61
|
+
*
|
|
62
|
+
* Throws SignatureVerificationError on failure.
|
|
63
|
+
*/
|
|
64
|
+
async function verifyDownload(opts) {
|
|
65
|
+
const actualChecksum = await computeFileChecksum(opts.filePath);
|
|
66
|
+
if (actualChecksum !== opts.expectedChecksum) {
|
|
67
|
+
throw new errors_1.SignatureVerificationError(`Checksum mismatch: expected ${opts.expectedChecksum.substring(0, 16)}..., ` +
|
|
68
|
+
`got ${actualChecksum.substring(0, 16)}...`);
|
|
69
|
+
}
|
|
70
|
+
const valid = verifyEd25519Signature(opts.expectedChecksum, opts.signature, opts.publicKeyBase64);
|
|
71
|
+
if (!valid) {
|
|
72
|
+
throw new errors_1.SignatureVerificationError("Ed25519 signature verification failed. " +
|
|
73
|
+
"The package may have been tampered with.");
|
|
74
|
+
}
|
|
75
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -6,55 +6,152 @@ const commander_1 = require("commander");
|
|
|
6
6
|
const doctor_1 = require("./commands/module/doctor");
|
|
7
7
|
const add_1 = require("./commands/module/add");
|
|
8
8
|
const remove_1 = require("./commands/module/remove");
|
|
9
|
+
const publish_1 = require("./commands/module/publish");
|
|
9
10
|
const login_1 = require("./commands/auth/login");
|
|
10
11
|
const logout_1 = require("./commands/auth/logout");
|
|
11
12
|
const whoami_1 = require("./commands/auth/whoami");
|
|
12
13
|
const list_1 = require("./commands/marketplace/list");
|
|
13
14
|
const install_1 = require("./commands/marketplace/install");
|
|
15
|
+
const browse_1 = require("./commands/marketplace/browse");
|
|
14
16
|
const view_1 = require("./commands/telemetry/view");
|
|
17
|
+
const index_js_1 = require("./commands/license/index.js");
|
|
18
|
+
const index_1 = require("./commands/init/index");
|
|
19
|
+
const index_2 = require("./commands/upgrade/index");
|
|
20
|
+
const index_3 = require("./commands/cache/index");
|
|
21
|
+
const index_4 = require("./commands/config/index");
|
|
22
|
+
const index_5 = require("./commands/init-ci/index");
|
|
15
23
|
const main = () => {
|
|
16
24
|
const program = new commander_1.Command();
|
|
17
25
|
program
|
|
18
26
|
.name("kaven")
|
|
19
|
-
.description("CLI
|
|
20
|
-
.version("0.
|
|
27
|
+
.description("The official CLI for the Kaven SaaS boilerplate ecosystem")
|
|
28
|
+
.version("0.2.0-alpha.1")
|
|
29
|
+
.addHelpText("after", `
|
|
30
|
+
Examples:
|
|
31
|
+
$ kaven init my-saas-app Bootstrap a new Kaven project
|
|
32
|
+
$ kaven auth login Authenticate with Kaven Marketplace
|
|
33
|
+
$ kaven marketplace list Browse available modules
|
|
34
|
+
$ kaven marketplace install auth Install the auth module
|
|
35
|
+
$ kaven upgrade Upgrade your license tier
|
|
36
|
+
$ kaven module doctor Check project health
|
|
37
|
+
|
|
38
|
+
Documentation: https://docs.kaven.sh/cli
|
|
39
|
+
Support: https://github.com/kaven-co/kaven-cli/issues
|
|
40
|
+
`);
|
|
41
|
+
/**
|
|
42
|
+
* Init command — Bootstrap a new Kaven project
|
|
43
|
+
*/
|
|
44
|
+
program
|
|
45
|
+
.command("init [project-name]")
|
|
46
|
+
.description("Bootstrap a new Kaven project from the official template")
|
|
47
|
+
.option("--defaults", "Skip interactive prompts and use default values")
|
|
48
|
+
.option("--skip-install", "Skip running pnpm install after setup")
|
|
49
|
+
.option("--skip-git", "Skip git init and initial commit")
|
|
50
|
+
.option("--force", "Overwrite existing directory if it exists")
|
|
51
|
+
.addHelpText("after", `
|
|
52
|
+
Examples:
|
|
53
|
+
$ kaven init my-app Interactive setup
|
|
54
|
+
$ kaven init my-app --defaults Use defaults (no prompts)
|
|
55
|
+
$ kaven init my-app --skip-git Skip git initialization
|
|
56
|
+
`)
|
|
57
|
+
.action((name, opts) => (0, index_1.initProject)(name, {
|
|
58
|
+
defaults: opts.defaults,
|
|
59
|
+
skipInstall: opts.skipInstall,
|
|
60
|
+
skipGit: opts.skipGit,
|
|
61
|
+
force: opts.force,
|
|
62
|
+
}));
|
|
21
63
|
/**
|
|
22
64
|
* Modules Group
|
|
23
65
|
*/
|
|
24
66
|
const moduleCommand = program
|
|
25
67
|
.command("module")
|
|
26
68
|
.alias("m")
|
|
27
|
-
.description("
|
|
69
|
+
.description("Manage Kaven modules: install, remove, publish, and diagnose")
|
|
70
|
+
.addHelpText("after", `
|
|
71
|
+
Examples:
|
|
72
|
+
$ kaven module doctor Check module integrity
|
|
73
|
+
$ kaven module doctor --fix Auto-fix detected issues
|
|
74
|
+
$ kaven module add ./my-module Install a local module
|
|
75
|
+
$ kaven module remove payments Remove a module
|
|
76
|
+
$ kaven module publish Publish module to marketplace
|
|
77
|
+
`);
|
|
28
78
|
moduleCommand
|
|
29
79
|
.command("doctor")
|
|
30
|
-
.description("
|
|
31
|
-
.option("--fix", "Attempt to fix issues")
|
|
32
|
-
.
|
|
80
|
+
.description("Run comprehensive project and module health checks")
|
|
81
|
+
.option("--fix", "Attempt to auto-fix detected issues (pnpm install, prisma generate, env vars)")
|
|
82
|
+
.option("--json", "Output results as machine-readable JSON")
|
|
83
|
+
.addHelpText("after", `
|
|
84
|
+
Exit codes:
|
|
85
|
+
0 All checks passed
|
|
86
|
+
1 One or more errors found
|
|
87
|
+
2 Warnings only (no errors)
|
|
88
|
+
|
|
89
|
+
Examples:
|
|
90
|
+
$ kaven module doctor
|
|
91
|
+
$ kaven module doctor --fix
|
|
92
|
+
$ kaven module doctor --json
|
|
93
|
+
`)
|
|
94
|
+
.action((options) => (0, doctor_1.moduleDoctor)({ fix: options.fix, json: options.json }));
|
|
33
95
|
moduleCommand
|
|
34
96
|
.command("add <path>")
|
|
35
|
-
.description("
|
|
97
|
+
.description("Install a module from a local manifest file")
|
|
98
|
+
.addHelpText("after", `
|
|
99
|
+
Examples:
|
|
100
|
+
$ kaven module add ./modules/payments/module.json
|
|
101
|
+
$ kaven module add /absolute/path/to/module.json
|
|
102
|
+
`)
|
|
36
103
|
.action((path) => (0, add_1.moduleAdd)(path));
|
|
37
104
|
moduleCommand
|
|
38
105
|
.command("remove <name>")
|
|
39
|
-
.description("Remove
|
|
106
|
+
.description("Remove an installed module and clean up injected code")
|
|
107
|
+
.addHelpText("after", `
|
|
108
|
+
Examples:
|
|
109
|
+
$ kaven module remove payments
|
|
110
|
+
$ kaven module remove notifications
|
|
111
|
+
`)
|
|
40
112
|
.action((name) => (0, remove_1.moduleRemove)(name));
|
|
113
|
+
moduleCommand
|
|
114
|
+
.command("publish")
|
|
115
|
+
.description("Publish the current directory as a module to Kaven Marketplace")
|
|
116
|
+
.option("--dry-run", "Validate and package the module without uploading")
|
|
117
|
+
.option("--changelog <text>", "Release notes for this version")
|
|
118
|
+
.addHelpText("after", `
|
|
119
|
+
Requirements:
|
|
120
|
+
- module.json must exist in the current directory
|
|
121
|
+
- Must be authenticated: run 'kaven auth login' first
|
|
122
|
+
|
|
123
|
+
Examples:
|
|
124
|
+
$ kaven module publish
|
|
125
|
+
$ kaven module publish --dry-run
|
|
126
|
+
$ kaven module publish --changelog "Added dark mode support"
|
|
127
|
+
`)
|
|
128
|
+
.action((opts) => (0, publish_1.modulePublish)({
|
|
129
|
+
dryRun: opts.dryRun,
|
|
130
|
+
changelog: opts.changelog,
|
|
131
|
+
}));
|
|
41
132
|
/**
|
|
42
133
|
* Auth Group
|
|
43
134
|
*/
|
|
44
135
|
const authCommand = program
|
|
45
136
|
.command("auth")
|
|
46
|
-
.description("
|
|
137
|
+
.description("Manage authentication and session tokens")
|
|
138
|
+
.addHelpText("after", `
|
|
139
|
+
Examples:
|
|
140
|
+
$ kaven auth login Start device code authentication flow
|
|
141
|
+
$ kaven auth whoami Show current user info
|
|
142
|
+
$ kaven auth logout End the local session
|
|
143
|
+
`);
|
|
47
144
|
authCommand
|
|
48
145
|
.command("login")
|
|
49
|
-
.description("
|
|
146
|
+
.description("Start the interactive device code authentication flow (RFC 8628)")
|
|
50
147
|
.action(() => (0, login_1.authLogin)());
|
|
51
148
|
authCommand
|
|
52
149
|
.command("logout")
|
|
53
|
-
.description("
|
|
150
|
+
.description("Clear the local authentication session")
|
|
54
151
|
.action(() => (0, logout_1.authLogout)());
|
|
55
152
|
authCommand
|
|
56
153
|
.command("whoami")
|
|
57
|
-
.description("
|
|
154
|
+
.description("Display information about the currently authenticated user")
|
|
58
155
|
.action(() => (0, whoami_1.authWhoami)());
|
|
59
156
|
/**
|
|
60
157
|
* Marketplace Group
|
|
@@ -63,26 +160,174 @@ const main = () => {
|
|
|
63
160
|
.command("marketplace")
|
|
64
161
|
.alias("mkt")
|
|
65
162
|
.alias("market")
|
|
66
|
-
.description("
|
|
163
|
+
.description("Explore, browse, and install modules from the Kaven Marketplace")
|
|
164
|
+
.addHelpText("after", `
|
|
165
|
+
Examples:
|
|
166
|
+
$ kaven marketplace list
|
|
167
|
+
$ kaven marketplace list --category auth --sort popular
|
|
168
|
+
$ kaven marketplace install payments
|
|
169
|
+
$ kaven marketplace browse
|
|
170
|
+
`);
|
|
67
171
|
marketplaceCommand
|
|
68
172
|
.command("list")
|
|
69
|
-
.description("
|
|
70
|
-
.
|
|
173
|
+
.description("List all modules available in the marketplace")
|
|
174
|
+
.option("--category <category>", "Filter modules by category")
|
|
175
|
+
.option("--sort <field>", "Sort order: newest (default), popular, name", "newest")
|
|
176
|
+
.option("--page <n>", "Page number (default: 1)", "1")
|
|
177
|
+
.option("--limit <n>", "Results per page (default: 20, max: 100)", "20")
|
|
178
|
+
.option("--json", "Output raw JSON instead of formatted table")
|
|
179
|
+
.action((options) => (0, list_1.marketplaceList)({
|
|
180
|
+
category: options.category,
|
|
181
|
+
sort: options.sort,
|
|
182
|
+
page: parseInt(options.page, 10),
|
|
183
|
+
limit: parseInt(options.limit, 10),
|
|
184
|
+
json: options.json ?? false,
|
|
185
|
+
}));
|
|
71
186
|
marketplaceCommand
|
|
72
187
|
.command("install <moduleId>")
|
|
73
|
-
.description("
|
|
74
|
-
.
|
|
188
|
+
.description("Download and install a module from the Kaven Marketplace")
|
|
189
|
+
.option("--version <ver>", "Install a specific version (default: latest)")
|
|
190
|
+
.option("--force", "Skip overwrite confirmation")
|
|
191
|
+
.option("--skip-env", "Skip environment variable injection")
|
|
192
|
+
.option("--skip-verify", "Skip Ed25519 signature verification (dev only)")
|
|
193
|
+
.option("--env-file <path>", "Target .env file (default: .env)")
|
|
194
|
+
.addHelpText("after", `
|
|
195
|
+
Examples:
|
|
196
|
+
$ kaven marketplace install payments
|
|
197
|
+
$ kaven marketplace install payments --version 1.2.0
|
|
198
|
+
$ kaven marketplace install auth --skip-env
|
|
199
|
+
$ kaven marketplace install my-module --skip-verify
|
|
200
|
+
`)
|
|
201
|
+
.action((moduleId, options) => (0, install_1.marketplaceInstall)(moduleId, {
|
|
202
|
+
version: options.version,
|
|
203
|
+
force: options.force ?? false,
|
|
204
|
+
skipEnv: options.skipEnv ?? false,
|
|
205
|
+
skipVerify: options.skipVerify ?? false,
|
|
206
|
+
envFile: options.envFile,
|
|
207
|
+
}));
|
|
208
|
+
marketplaceCommand
|
|
209
|
+
.command("browse")
|
|
210
|
+
.description("Interactive TUI module browser — explore modules by category")
|
|
211
|
+
.addHelpText("after", `
|
|
212
|
+
Navigate with arrow keys, press Enter to select.
|
|
213
|
+
Supports category filtering and pagination.
|
|
214
|
+
`)
|
|
215
|
+
.action(() => (0, browse_1.marketplaceBrowse)());
|
|
216
|
+
/**
|
|
217
|
+
* Upgrade Group — License tier upgrades and CLI updates
|
|
218
|
+
*/
|
|
219
|
+
const upgradeCommandGroup = program
|
|
220
|
+
.command("upgrade")
|
|
221
|
+
.description("Upgrade your license tier or CLI version")
|
|
222
|
+
.addHelpText("after", `
|
|
223
|
+
Examples:
|
|
224
|
+
$ kaven upgrade Upgrade license tier
|
|
225
|
+
$ kaven upgrade check Check for CLI updates
|
|
226
|
+
$ kaven upgrade install Install latest CLI version
|
|
227
|
+
`);
|
|
228
|
+
upgradeCommandGroup
|
|
229
|
+
.command("tier")
|
|
230
|
+
.description("Upgrade your Kaven license to a higher tier (default)")
|
|
231
|
+
.option("--no-browser", "Print the checkout URL instead of opening the browser")
|
|
232
|
+
.action((opts) => (0, index_2.upgradeCommand)({
|
|
233
|
+
browser: opts.browser !== false,
|
|
234
|
+
}));
|
|
235
|
+
upgradeCommandGroup
|
|
236
|
+
.command("check")
|
|
237
|
+
.description("Check for Kaven CLI updates")
|
|
238
|
+
.action(() => (0, index_2.upgradeCheck)());
|
|
239
|
+
upgradeCommandGroup
|
|
240
|
+
.command("install")
|
|
241
|
+
.description("Install the latest Kaven CLI version")
|
|
242
|
+
.action(() => (0, index_2.upgradeInstall)());
|
|
75
243
|
/**
|
|
76
244
|
* Telemetry Group
|
|
77
245
|
*/
|
|
78
246
|
const telemetryCommand = program
|
|
79
247
|
.command("telemetry")
|
|
80
|
-
.description("
|
|
248
|
+
.description("View observability and command audit logs");
|
|
81
249
|
telemetryCommand
|
|
82
250
|
.command("view")
|
|
83
|
-
.description("
|
|
84
|
-
.option("-l, --limit <number>", "
|
|
251
|
+
.description("Display the most recent local telemetry events")
|
|
252
|
+
.option("-l, --limit <number>", "Number of events to display", "10")
|
|
85
253
|
.action((options) => (0, view_1.telemetryView)(parseInt(options.limit)));
|
|
254
|
+
/**
|
|
255
|
+
* License Group
|
|
256
|
+
*/
|
|
257
|
+
program.addCommand((0, index_js_1.buildLicenseCommand)());
|
|
258
|
+
/**
|
|
259
|
+
* Cache Group
|
|
260
|
+
*/
|
|
261
|
+
const cacheCommand = program
|
|
262
|
+
.command("cache")
|
|
263
|
+
.description("Manage the local API response cache")
|
|
264
|
+
.addHelpText("after", `
|
|
265
|
+
Cache directory: ~/.kaven/cache (max 50 MB)
|
|
266
|
+
Cached data: module listings (24h TTL), manifests (7d), license status (1h)
|
|
267
|
+
|
|
268
|
+
Examples:
|
|
269
|
+
$ kaven cache status
|
|
270
|
+
$ kaven cache clear
|
|
271
|
+
`);
|
|
272
|
+
cacheCommand
|
|
273
|
+
.command("status")
|
|
274
|
+
.description("Show cache statistics (size, entry count, age)")
|
|
275
|
+
.action(() => (0, index_3.cacheStatus)());
|
|
276
|
+
cacheCommand
|
|
277
|
+
.command("clear")
|
|
278
|
+
.description("Delete all locally cached API responses")
|
|
279
|
+
.action(() => (0, index_3.cacheClear)());
|
|
280
|
+
/**
|
|
281
|
+
* Config Group — Manage Kaven CLI configuration
|
|
282
|
+
*/
|
|
283
|
+
const configCommand = program
|
|
284
|
+
.command("config")
|
|
285
|
+
.description("Manage Kaven CLI configuration")
|
|
286
|
+
.addHelpText("after", `
|
|
287
|
+
Config file: ~/.kaven/config.json
|
|
288
|
+
|
|
289
|
+
Examples:
|
|
290
|
+
$ kaven config set registry https://custom.registry.sh
|
|
291
|
+
$ kaven config get registry
|
|
292
|
+
$ kaven config view
|
|
293
|
+
$ kaven config reset
|
|
294
|
+
`);
|
|
295
|
+
configCommand
|
|
296
|
+
.command("set <key> <value>")
|
|
297
|
+
.description("Set a configuration value")
|
|
298
|
+
.action((key, value) => (0, index_4.configSet)(key, value));
|
|
299
|
+
configCommand
|
|
300
|
+
.command("get <key>")
|
|
301
|
+
.description("Get a configuration value")
|
|
302
|
+
.option("--json", "Output as JSON")
|
|
303
|
+
.action((key, opts) => (0, index_4.configGet)(key, { json: opts.json }));
|
|
304
|
+
configCommand
|
|
305
|
+
.command("view")
|
|
306
|
+
.description("Display all configuration")
|
|
307
|
+
.option("--json", "Output as JSON")
|
|
308
|
+
.action((opts) => (0, index_4.configView)({ json: opts.json }));
|
|
309
|
+
configCommand
|
|
310
|
+
.command("reset")
|
|
311
|
+
.description("Reset configuration to defaults")
|
|
312
|
+
.action(() => (0, index_4.configReset)());
|
|
313
|
+
/**
|
|
314
|
+
* Init CI — Initialize CI/CD workflows
|
|
315
|
+
*/
|
|
316
|
+
program
|
|
317
|
+
.command("init-ci")
|
|
318
|
+
.description("Initialize GitHub Actions CI/CD workflows")
|
|
319
|
+
.option("--dry-run", "Show what would be created without writing files")
|
|
320
|
+
.addHelpText("after", `
|
|
321
|
+
Creates:
|
|
322
|
+
- .github/workflows/test.yml Run tests on push/PR
|
|
323
|
+
- .github/workflows/publish.yml Publish modules on git tags
|
|
324
|
+
- .husky/pre-commit Local pre-commit validation
|
|
325
|
+
|
|
326
|
+
Examples:
|
|
327
|
+
$ kaven init-ci Interactive setup
|
|
328
|
+
$ kaven init-ci --dry-run Show what would be created
|
|
329
|
+
`)
|
|
330
|
+
.action((opts) => (0, index_5.initCi)({ dryRun: opts.dryRun }));
|
|
86
331
|
program.parse();
|
|
87
332
|
};
|
|
88
333
|
exports.main = main;
|