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.
Files changed (50) hide show
  1. package/README.md +284 -45
  2. package/README.pt-BR.md +334 -0
  3. package/dist/commands/auth/login.js +97 -19
  4. package/dist/commands/auth/logout.js +4 -6
  5. package/dist/commands/auth/whoami.js +12 -11
  6. package/dist/commands/cache/index.js +43 -0
  7. package/dist/commands/config/index.js +128 -0
  8. package/dist/commands/init/index.js +209 -0
  9. package/dist/commands/init-ci/index.js +153 -0
  10. package/dist/commands/license/index.js +10 -0
  11. package/dist/commands/license/status.js +44 -0
  12. package/dist/commands/license/tier-table.js +46 -0
  13. package/dist/commands/marketplace/browse.js +219 -0
  14. package/dist/commands/marketplace/install.js +233 -29
  15. package/dist/commands/marketplace/list.js +94 -16
  16. package/dist/commands/module/doctor.js +143 -38
  17. package/dist/commands/module/publish.js +291 -0
  18. package/dist/commands/upgrade/check.js +162 -0
  19. package/dist/commands/upgrade/index.js +218 -0
  20. package/dist/core/AuthService.js +207 -14
  21. package/dist/core/CacheManager.js +151 -0
  22. package/dist/core/ConfigManager.js +165 -0
  23. package/dist/core/EnvManager.js +196 -0
  24. package/dist/core/ErrorRecovery.js +191 -0
  25. package/dist/core/LicenseService.js +118 -0
  26. package/dist/core/ModuleDoctor.js +290 -4
  27. package/dist/core/ModuleInstaller.js +136 -2
  28. package/dist/core/ProjectInitializer.js +154 -0
  29. package/dist/core/RegistryResolver.js +94 -0
  30. package/dist/core/ScriptRunner.js +72 -0
  31. package/dist/core/SignatureVerifier.js +75 -0
  32. package/dist/index.js +265 -20
  33. package/dist/infrastructure/MarketplaceClient.js +388 -64
  34. package/dist/infrastructure/errors.js +61 -0
  35. package/dist/types/auth.js +2 -0
  36. package/dist/types/marketplace.js +2 -0
  37. package/package.json +23 -4
  38. package/dist/commands/modules/add.js +0 -53
  39. package/dist/commands/modules/list.js +0 -40
  40. package/dist/commands/modules/remove.js +0 -54
  41. package/dist/core/api/KavenApiClient.js +0 -61
  42. package/dist/core/auth/AuthManager.js +0 -91
  43. package/dist/core/modules/Injector.js +0 -86
  44. package/dist/core/modules/ModuleInstaller.js +0 -63
  45. package/dist/core/modules/ModuleManager.js +0 -59
  46. package/dist/core/modules/ModuleRemover.js +0 -60
  47. package/dist/lib/config.js +0 -66
  48. package/dist/lib/errors.js +0 -32
  49. package/dist/lib/logger.js +0 -70
  50. package/dist/types/module.js +0 -49
@@ -0,0 +1,153 @@
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.initCi = initCi;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const ora_1 = __importDefault(require("ora"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const fs_extra_1 = __importDefault(require("fs-extra"));
11
+ const GITHUB_WORKFLOW_TEST = `name: Tests
12
+ on:
13
+ push:
14
+ branches: [main, develop]
15
+ pull_request:
16
+ branches: [main, develop]
17
+
18
+ jobs:
19
+ test:
20
+ runs-on: ubuntu-latest
21
+ services:
22
+ postgres:
23
+ image: postgres:15
24
+ env:
25
+ POSTGRES_PASSWORD: postgres
26
+ options: >-
27
+ --health-cmd pg_isready
28
+ --health-interval 10s
29
+ --health-timeout 5s
30
+ --health-retries 5
31
+ ports:
32
+ - 5432:5432
33
+ steps:
34
+ - uses: actions/checkout@v3
35
+ - uses: pnpm/action-setup@v2
36
+ with:
37
+ version: 8
38
+ - uses: actions/setup-node@v3
39
+ with:
40
+ node-version: 20
41
+ cache: 'pnpm'
42
+ - run: pnpm install
43
+ - run: pnpm typecheck
44
+ - run: pnpm lint
45
+ - run: pnpm test
46
+ - run: pnpm build
47
+ `;
48
+ const GITHUB_WORKFLOW_PUBLISH = `name: Publish Module
49
+ on:
50
+ push:
51
+ tags:
52
+ - 'v*'
53
+
54
+ jobs:
55
+ publish:
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ - uses: actions/checkout@v3
59
+ - uses: pnpm/action-setup@v2
60
+ with:
61
+ version: 8
62
+ - uses: actions/setup-node@v3
63
+ with:
64
+ node-version: 20
65
+ cache: 'pnpm'
66
+ - run: pnpm install
67
+ - run: pnpm build
68
+ - name: Publish to Kaven Marketplace
69
+ env:
70
+ KAVEN_LICENSE_KEY: \${{ secrets.KAVEN_LICENSE_KEY }}
71
+ run: kaven module publish
72
+ `;
73
+ const PRE_COMMIT_HOOK = `#!/bin/bash
74
+ # Pre-commit hook for Kaven projects
75
+ set -e
76
+
77
+ echo "🔍 Running pre-commit checks..."
78
+
79
+ # Lint
80
+ echo " Linting..."
81
+ pnpm lint || exit 1
82
+
83
+ # Type check
84
+ echo " Type checking..."
85
+ pnpm typecheck || exit 1
86
+
87
+ # Format check
88
+ if command -v pnpm format &> /dev/null; then
89
+ echo " Format checking..."
90
+ pnpm format || exit 1
91
+ fi
92
+
93
+ echo "✅ All pre-commit checks passed"
94
+ `;
95
+ /**
96
+ * C2.6: Initialize CI/CD templates
97
+ */
98
+ async function initCi(options) {
99
+ const cwd = process.cwd();
100
+ // Check if it's a Kaven project
101
+ const packageJsonPath = path_1.default.join(cwd, "package.json");
102
+ if (!(await fs_extra_1.default.pathExists(packageJsonPath))) {
103
+ console.error(chalk_1.default.red("Error: package.json not found. Run this in a Kaven project root."));
104
+ process.exit(1);
105
+ }
106
+ const spinner = (0, ora_1.default)("Setting up CI/CD configuration...").start();
107
+ try {
108
+ // Create .github/workflows directory
109
+ const workflowDir = path_1.default.join(cwd, ".github", "workflows");
110
+ await fs_extra_1.default.ensureDir(workflowDir);
111
+ // Create test workflow
112
+ const testWorkflowPath = path_1.default.join(workflowDir, "test.yml");
113
+ if (!options.dryRun) {
114
+ await fs_extra_1.default.writeFile(testWorkflowPath, GITHUB_WORKFLOW_TEST);
115
+ }
116
+ spinner.text = `Creating ${chalk_1.default.cyan(".github/workflows/test.yml")}...`;
117
+ // Create publish workflow
118
+ const publishWorkflowPath = path_1.default.join(workflowDir, "publish.yml");
119
+ if (!options.dryRun) {
120
+ await fs_extra_1.default.writeFile(publishWorkflowPath, GITHUB_WORKFLOW_PUBLISH);
121
+ }
122
+ spinner.text = `Creating ${chalk_1.default.cyan(".github/workflows/publish.yml")}...`;
123
+ // Create pre-commit hook
124
+ const hookDir = path_1.default.join(cwd, ".husky");
125
+ await fs_extra_1.default.ensureDir(hookDir);
126
+ const preCommitHookPath = path_1.default.join(hookDir, "pre-commit");
127
+ if (!options.dryRun) {
128
+ await fs_extra_1.default.writeFile(preCommitHookPath, PRE_COMMIT_HOOK);
129
+ await fs_extra_1.default.chmod(preCommitHookPath, 0o755);
130
+ }
131
+ spinner.text = `Creating ${chalk_1.default.cyan(".husky/pre-commit")}...`;
132
+ spinner.succeed("CI/CD configuration created");
133
+ console.log();
134
+ console.log(chalk_1.default.bold("Files created:"));
135
+ console.log(` ${chalk_1.default.cyan(".github/workflows/test.yml")} - Run tests on push/PR`);
136
+ console.log(` ${chalk_1.default.cyan(".github/workflows/publish.yml")} - Publish on git tags`);
137
+ console.log(` ${chalk_1.default.cyan(".husky/pre-commit")} - Local pre-commit validation`);
138
+ console.log();
139
+ console.log(chalk_1.default.bold("Next steps:"));
140
+ console.log(chalk_1.default.gray(" 1. Install husky: pnpm husky install"));
141
+ console.log(chalk_1.default.gray(" 2. Add GitHub secrets: KAVEN_LICENSE_KEY"));
142
+ console.log(chalk_1.default.gray(" 3. Push to GitHub and watch workflows run"));
143
+ if (options.dryRun) {
144
+ console.log();
145
+ console.log(chalk_1.default.yellow("(Dry-run: No files were actually created)"));
146
+ }
147
+ }
148
+ catch (error) {
149
+ spinner.fail("Failed to create CI/CD configuration");
150
+ console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
151
+ process.exit(1);
152
+ }
153
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildLicenseCommand = buildLicenseCommand;
4
+ const commander_1 = require("commander");
5
+ const status_js_1 = require("./status.js");
6
+ function buildLicenseCommand() {
7
+ const cmd = new commander_1.Command('license').description('Manage Kaven licenses');
8
+ cmd.addCommand((0, status_js_1.buildLicenseStatusCommand)());
9
+ return cmd;
10
+ }
@@ -0,0 +1,44 @@
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.buildLicenseStatusCommand = buildLicenseStatusCommand;
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const LicenseService_js_1 = require("../../core/LicenseService.js");
10
+ function buildLicenseStatusCommand() {
11
+ return new commander_1.Command('status')
12
+ .description('Show license status and tier information')
13
+ .argument('[license-key]', 'License key to check (uses stored license if omitted)')
14
+ .action(async (licenseKey) => {
15
+ const service = new LicenseService_js_1.LicenseService();
16
+ // Resolve key from arg or environment
17
+ const key = licenseKey ?? process.env.KAVEN_LICENSE_KEY;
18
+ if (!key) {
19
+ console.error(chalk_1.default.red('✗ No license key provided. Pass as argument or set KAVEN_LICENSE_KEY.'));
20
+ process.exit(1);
21
+ }
22
+ try {
23
+ console.log(chalk_1.default.dim('Checking license status...'));
24
+ const status = await service.getLicenseStatus(key);
25
+ console.log('\n' + chalk_1.default.bold('License Status') + '\n');
26
+ console.log(` Key: ${chalk_1.default.dim(status.key.substring(0, 16) + '...')}`);
27
+ console.log(` Tier: ${chalk_1.default.magenta(status.tier)}`);
28
+ if (status.expiresAt) {
29
+ const days = status.daysUntilExpiry;
30
+ const expiryColor = days !== null && days < 30 ? chalk_1.default.red : chalk_1.default.green;
31
+ console.log(` Expires: ${expiryColor(status.expiresAt)}${days !== null ? chalk_1.default.dim(` (${days} days)`) : ''}`);
32
+ }
33
+ else {
34
+ console.log(` Expires: ${chalk_1.default.green('Never')}`);
35
+ }
36
+ console.log();
37
+ }
38
+ catch (err) {
39
+ const message = err instanceof Error ? err.message : 'Failed to check license status';
40
+ console.error(chalk_1.default.red('✗ ' + message));
41
+ process.exit(1);
42
+ }
43
+ });
44
+ }
@@ -0,0 +1,46 @@
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.printTierComparisonTable = printTierComparisonTable;
7
+ const cli_table3_1 = __importDefault(require("cli-table3"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const TIERS = [
10
+ { name: 'STARTER', price: '$149', projects: '1', tenants: '10', marketplace: false },
11
+ { name: 'COMPLETE', price: '$399', projects: '1', tenants: 'Unlimited', marketplace: false },
12
+ { name: 'PRO', price: '$799', projects: '5', tenants: 'Unlimited', marketplace: true },
13
+ { name: 'ENTERPRISE', price: 'Custom', projects: 'Unlimited', tenants: 'Unlimited', marketplace: true },
14
+ ];
15
+ function colorTier(tier) {
16
+ switch (tier.toUpperCase()) {
17
+ case 'STARTER': return chalk_1.default.green(tier);
18
+ case 'COMPLETE': return chalk_1.default.yellow(tier);
19
+ case 'PRO': return chalk_1.default.magenta(tier);
20
+ case 'ENTERPRISE': return chalk_1.default.cyan(tier);
21
+ default: return tier;
22
+ }
23
+ }
24
+ function printTierComparisonTable(userTier, requiredTier) {
25
+ console.log(chalk_1.default.red('\n✗ License tier insufficient\n'));
26
+ console.log(` Your tier: ${colorTier(userTier)}`);
27
+ console.log(` Required tier: ${colorTier(requiredTier)}\n`);
28
+ const table = new cli_table3_1.default({
29
+ head: ['Tier', 'Price', 'Projects', 'Tenants', 'Marketplace'],
30
+ style: { head: ['cyan'] },
31
+ });
32
+ for (const t of TIERS) {
33
+ const isUser = t.name === userTier.toUpperCase();
34
+ const isRequired = t.name === requiredTier.toUpperCase();
35
+ const marker = isRequired ? chalk_1.default.yellow(' ← required') : isUser ? chalk_1.default.dim(' ← you') : '';
36
+ table.push([
37
+ colorTier(t.name) + marker,
38
+ t.price,
39
+ t.projects,
40
+ t.tenants,
41
+ t.marketplace ? chalk_1.default.green('✓') : chalk_1.default.dim('✗'),
42
+ ]);
43
+ }
44
+ console.log(table.toString());
45
+ console.log(chalk_1.default.dim('\n Upgrade at: https://kaven.dev/pricing\n'));
46
+ }
@@ -0,0 +1,219 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.marketplaceBrowse = marketplaceBrowse;
40
+ const chalk_1 = __importDefault(require("chalk"));
41
+ const ora_1 = __importDefault(require("ora"));
42
+ const AuthService_1 = require("../../core/AuthService");
43
+ const MarketplaceClient_1 = require("../../infrastructure/MarketplaceClient");
44
+ const install_1 = require("./install");
45
+ const PAGE_SIZE = 10;
46
+ function tierBadge(tier) {
47
+ switch (tier.toUpperCase()) {
48
+ case "FREE":
49
+ return chalk_1.default.gray("[FREE]");
50
+ case "STARTER":
51
+ return chalk_1.default.green("[STARTER]");
52
+ case "COMPLETE":
53
+ return chalk_1.default.yellow("[COMPLETE]");
54
+ case "PRO":
55
+ return chalk_1.default.magenta("[PRO]");
56
+ case "ENTERPRISE":
57
+ return chalk_1.default.cyan("[ENTERPRISE]");
58
+ default:
59
+ return chalk_1.default.gray(`[${tier}]`);
60
+ }
61
+ }
62
+ async function marketplaceBrowse() {
63
+ const authService = new AuthService_1.AuthService();
64
+ const client = new MarketplaceClient_1.MarketplaceClient(authService);
65
+ const state = {
66
+ category: null,
67
+ page: 1,
68
+ selectedModule: null,
69
+ screen: "categories",
70
+ };
71
+ const { select } = await Promise.resolve().then(() => __importStar(require("@inquirer/prompts")));
72
+ while (state.screen !== "exit") {
73
+ if (state.screen === "categories") {
74
+ // Step 1: Category selection
75
+ const spinner = (0, ora_1.default)("Loading categories...").start();
76
+ let categories = [];
77
+ try {
78
+ categories = await client.getCategories();
79
+ spinner.stop();
80
+ }
81
+ catch {
82
+ spinner.stop();
83
+ console.log(chalk_1.default.yellow("Could not load categories — showing all modules."));
84
+ }
85
+ const categoryChoices = [
86
+ { name: "All modules", value: "__all__" },
87
+ ...categories.map((c) => ({ name: c, value: c })),
88
+ { name: chalk_1.default.red("Exit"), value: "__exit__" },
89
+ ];
90
+ const selected = await select({
91
+ message: "Browse by category:",
92
+ choices: categoryChoices,
93
+ });
94
+ if (selected === "__exit__") {
95
+ state.screen = "exit";
96
+ break;
97
+ }
98
+ state.category = selected === "__all__" ? null : selected;
99
+ state.page = 1;
100
+ state.screen = "list";
101
+ continue;
102
+ }
103
+ if (state.screen === "list") {
104
+ // Step 2: Module listing with pagination
105
+ const spinner = (0, ora_1.default)("Loading modules...").start();
106
+ let modules = [];
107
+ let totalPages = 1;
108
+ try {
109
+ const result = await client.listModules({
110
+ category: state.category || undefined,
111
+ page: state.page,
112
+ pageSize: PAGE_SIZE,
113
+ });
114
+ modules = result.data;
115
+ totalPages = Math.ceil(result.total / PAGE_SIZE) || 1;
116
+ spinner.stop();
117
+ }
118
+ catch (error) {
119
+ spinner.stop();
120
+ console.error(chalk_1.default.red(`Error loading modules: ${error instanceof Error ? error.message : String(error)}`));
121
+ state.screen = "categories";
122
+ continue;
123
+ }
124
+ if (modules.length === 0) {
125
+ console.log(chalk_1.default.yellow(`No modules found${state.category ? ` in category: ${state.category}` : ""}.`));
126
+ state.screen = "categories";
127
+ continue;
128
+ }
129
+ const categoryLabel = state.category ? ` [${state.category}]` : "";
130
+ const pageLabel = totalPages > 1 ? ` (page ${state.page}/${totalPages})` : "";
131
+ const moduleChoices = [
132
+ ...modules.map((m) => ({
133
+ name: `${m.name} ${tierBadge(m.requiredTier ?? m.tier ?? "")} — ${m.description}`,
134
+ value: m.slug,
135
+ })),
136
+ ];
137
+ // Navigation options at bottom
138
+ if (state.page < totalPages) {
139
+ moduleChoices.push({ name: chalk_1.default.cyan("→ Next page"), value: "__next__" });
140
+ }
141
+ if (state.page > 1) {
142
+ moduleChoices.push({ name: chalk_1.default.cyan("← Previous page"), value: "__prev__" });
143
+ }
144
+ moduleChoices.push({ name: chalk_1.default.dim("↑ Back to categories"), value: "__back__" });
145
+ moduleChoices.push({ name: chalk_1.default.red("Exit"), value: "__exit__" });
146
+ const selected = await select({
147
+ message: `Modules${categoryLabel}${pageLabel}:`,
148
+ choices: moduleChoices,
149
+ });
150
+ if (selected === "__exit__") {
151
+ state.screen = "exit";
152
+ break;
153
+ }
154
+ if (selected === "__back__") {
155
+ state.screen = "categories";
156
+ continue;
157
+ }
158
+ if (selected === "__next__") {
159
+ state.page++;
160
+ continue;
161
+ }
162
+ if (selected === "__prev__") {
163
+ state.page = Math.max(1, state.page - 1);
164
+ continue;
165
+ }
166
+ // Find selected module
167
+ const module = modules.find((m) => m.slug === selected);
168
+ if (module) {
169
+ state.selectedModule = module;
170
+ state.screen = "detail";
171
+ }
172
+ continue;
173
+ }
174
+ if (state.screen === "detail" && state.selectedModule) {
175
+ const m = state.selectedModule;
176
+ // Step 3: Module detail view
177
+ console.log();
178
+ console.log(chalk_1.default.bold(`${m.name}`), tierBadge(m.requiredTier ?? m.tier ?? ""));
179
+ console.log(chalk_1.default.gray(`Version: ${m.latestVersion || "latest"}`));
180
+ if (m.installCount !== undefined) {
181
+ console.log(chalk_1.default.gray(`Installs: ${m.installCount.toLocaleString()}`));
182
+ }
183
+ if (m.description) {
184
+ console.log();
185
+ console.log(m.description);
186
+ }
187
+ console.log();
188
+ const action = await select({
189
+ message: "What would you like to do?",
190
+ choices: [
191
+ { name: `Install ${m.name}`, value: "install" },
192
+ { name: "Back to module list", value: "back" },
193
+ { name: chalk_1.default.red("Exit"), value: "exit" },
194
+ ],
195
+ });
196
+ if (action === "exit") {
197
+ state.screen = "exit";
198
+ break;
199
+ }
200
+ if (action === "back") {
201
+ state.selectedModule = null;
202
+ state.screen = "list";
203
+ continue;
204
+ }
205
+ if (action === "install") {
206
+ console.log();
207
+ await (0, install_1.marketplaceInstall)(m.slug, {
208
+ force: false,
209
+ skipEnv: false,
210
+ });
211
+ state.screen = "exit";
212
+ break;
213
+ }
214
+ }
215
+ }
216
+ if (state.screen === "exit") {
217
+ console.log(chalk_1.default.gray("Browse session ended."));
218
+ }
219
+ }