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
@@ -1,73 +1,397 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.MarketplaceClient = 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
+ const errors_1 = require("./errors");
11
+ const DEFAULT_BASE_URL = "https://api.kaven.sh";
12
+ const REQUEST_TIMEOUT_MS = 30000;
13
+ const MAX_RETRIES = 3;
14
+ const INITIAL_RETRY_DELAY_MS = 1000;
15
+ function debug(message) {
16
+ if (process.env.KAVEN_DEBUG === "1") {
17
+ console.debug(`[kaven:debug] ${message}`);
18
+ }
19
+ }
20
+ /** Load the apiUrl from ~/.kaven/config.json if present. */
21
+ async function loadConfigApiUrl() {
22
+ try {
23
+ const configPath = path_1.default.join(os_1.default.homedir(), ".kaven", "config.json");
24
+ if (await fs_extra_1.default.pathExists(configPath)) {
25
+ const config = await fs_extra_1.default.readJson(configPath);
26
+ if (typeof config.apiUrl === "string" && config.apiUrl) {
27
+ return config.apiUrl;
28
+ }
29
+ }
30
+ }
31
+ catch {
32
+ // Ignore config read errors
33
+ }
34
+ return null;
35
+ }
36
+ /** Resolve base URL from env → config file → default. */
37
+ async function resolveBaseUrl() {
38
+ if (process.env.KAVEN_API_URL) {
39
+ return process.env.KAVEN_API_URL.replace(/\/$/, "");
40
+ }
41
+ const configUrl = await loadConfigApiUrl();
42
+ if (configUrl) {
43
+ return configUrl.replace(/\/$/, "");
44
+ }
45
+ return DEFAULT_BASE_URL;
46
+ }
47
+ /** Sleep helper for retry backoff. */
48
+ function sleep(ms) {
49
+ return new Promise((resolve) => setTimeout(resolve, ms));
50
+ }
51
+ /** Determine if the error code / HTTP status is retryable. */
52
+ function isRetryable(status) {
53
+ return status >= 500;
54
+ }
4
55
  class MarketplaceClient {
5
- constructor() {
6
- this.mockModules = [
7
- {
8
- id: "auth-google",
9
- name: "Google Auth",
10
- description: "Integração completa com Google OAuth2 e suporte a multiplataforma.",
11
- version: "1.2.0",
12
- author: "Kaven Official",
13
- },
14
- {
15
- id: "db-postgresql",
16
- name: "PostgreSQL Adapter",
17
- description: "Conexão otimizada para PostgreSQL com suporte a pooling e migrações.",
18
- version: "2.0.1",
19
- author: "Kaven Official",
20
- },
21
- {
22
- id: "stripe-payments",
23
- name: "Stripe Checkout",
24
- description: "Lógica de pagamentos resiliente com suporte a webhooks e assinaturas.",
25
- version: "1.0.5",
26
- author: "Kaven Official",
27
- },
28
- ];
29
- }
30
- async listModules() {
31
- // Simular latência de rede
32
- await new Promise((resolve) => setTimeout(resolve, 800));
33
- return this.mockModules;
56
+ constructor(authService) {
57
+ this.authService = authService ?? null;
58
+ this.baseURLPromise = resolveBaseUrl();
59
+ }
60
+ /** Resolve a relative API path to an absolute URL. */
61
+ async resolveUrl(path) {
62
+ const baseURL = await this.baseURLPromise;
63
+ return `${baseURL}${path}`;
64
+ }
65
+ // ──────────────────────────────────────────────────────────
66
+ // Core HTTP helpers
67
+ // ──────────────────────────────────────────────────────────
68
+ /**
69
+ * Make an HTTP request with retry logic and typed error mapping.
70
+ * `authenticated` controls whether Authorization header is attached.
71
+ */
72
+ async request(method, endpoint, options = {}) {
73
+ const baseURL = await this.baseURLPromise;
74
+ const url = `${baseURL}${endpoint}`;
75
+ const { body, authenticated = false } = options;
76
+ let lastError = null;
77
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
78
+ if (attempt > 0) {
79
+ const delay = INITIAL_RETRY_DELAY_MS * Math.pow(2, attempt - 1);
80
+ debug(`Retry attempt ${attempt} for ${method} ${endpoint} (delay ${delay}ms)`);
81
+ await sleep(delay);
82
+ }
83
+ try {
84
+ const headers = {
85
+ "Content-Type": "application/json",
86
+ Accept: "application/json",
87
+ };
88
+ if (authenticated && this.authService) {
89
+ const token = await this.authService.getValidToken();
90
+ headers["Authorization"] = `Bearer ${token}`;
91
+ }
92
+ debug(`${method} ${url}`);
93
+ const controller = new AbortController();
94
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
95
+ let response;
96
+ try {
97
+ response = await fetch(url, {
98
+ method,
99
+ headers,
100
+ body: body !== undefined ? JSON.stringify(body) : undefined,
101
+ signal: controller.signal,
102
+ });
103
+ }
104
+ finally {
105
+ clearTimeout(timeoutId);
106
+ }
107
+ debug(`Response: ${response.status} ${response.statusText}`);
108
+ // Map HTTP errors to typed exceptions
109
+ if (!response.ok) {
110
+ const errorText = await response.text().catch(() => "");
111
+ let errorMessage = errorText;
112
+ try {
113
+ const errorJson = JSON.parse(errorText);
114
+ errorMessage = errorJson.message || errorJson.error || errorText;
115
+ }
116
+ catch {
117
+ // keep raw text
118
+ }
119
+ switch (response.status) {
120
+ case 401:
121
+ throw new errors_1.AuthenticationError(errorMessage || "Authentication required");
122
+ case 403: {
123
+ let requiredTier = "pro";
124
+ try {
125
+ const parsed = JSON.parse(errorText);
126
+ requiredTier = parsed.requiredTier || requiredTier;
127
+ }
128
+ catch {
129
+ // ignore
130
+ }
131
+ throw new errors_1.LicenseRequiredError(requiredTier, errorMessage || "License required");
132
+ }
133
+ case 404:
134
+ throw new errors_1.NotFoundError(errorMessage || "Resource not found");
135
+ case 429: {
136
+ const retryAfter = parseInt(response.headers.get("retry-after") ?? "60", 10);
137
+ throw new errors_1.RateLimitError(isNaN(retryAfter) ? 60 : retryAfter);
138
+ }
139
+ default:
140
+ if (isRetryable(response.status)) {
141
+ lastError = new errors_1.ServerError(errorMessage || `Server error: ${response.status}`);
142
+ continue; // retry
143
+ }
144
+ throw new errors_1.ServerError(errorMessage || `Server error: ${response.status}`);
145
+ }
146
+ }
147
+ // Parse successful response
148
+ const contentType = response.headers.get("content-type") ?? "";
149
+ if (contentType.includes("application/json")) {
150
+ return (await response.json());
151
+ }
152
+ // Return empty object for no-body responses (204, etc.)
153
+ return {};
154
+ }
155
+ catch (error) {
156
+ // Re-throw our typed errors without retrying on 4xx
157
+ if (error instanceof errors_1.AuthenticationError ||
158
+ error instanceof errors_1.LicenseRequiredError ||
159
+ error instanceof errors_1.NotFoundError ||
160
+ error instanceof errors_1.RateLimitError) {
161
+ throw error;
162
+ }
163
+ // Network / timeout errors
164
+ if (error instanceof TypeError ||
165
+ (error instanceof Error && error.name === "AbortError")) {
166
+ const networkError = new errors_1.NetworkError(error.name === "AbortError"
167
+ ? "Request timed out after 30s"
168
+ : `Network error: ${error.message}`);
169
+ lastError = networkError;
170
+ // Retry on network errors too
171
+ if (attempt < MAX_RETRIES)
172
+ continue;
173
+ throw networkError;
174
+ }
175
+ // ServerError already stored in lastError, will retry
176
+ if (error instanceof errors_1.ServerError) {
177
+ lastError = error;
178
+ if (attempt < MAX_RETRIES)
179
+ continue;
180
+ throw error;
181
+ }
182
+ // Unknown error — don't retry
183
+ throw error;
184
+ }
185
+ }
186
+ // All retries exhausted
187
+ throw lastError ?? new errors_1.NetworkError("Request failed after retries");
188
+ }
189
+ // ──────────────────────────────────────────────────────────
190
+ // Auth endpoints (unauthenticated)
191
+ // ──────────────────────────────────────────────────────────
192
+ /**
193
+ * Step 1 of Device Code Flow: Request device code from marketplace.
194
+ */
195
+ async requestDeviceCode() {
196
+ return this.request("POST", "/auth/device-code", {
197
+ body: { client_id: "kaven-cli" },
198
+ authenticated: false,
199
+ });
200
+ }
201
+ /**
202
+ * Step 2 of Device Code Flow: Poll for access token.
203
+ */
204
+ async pollDeviceToken(deviceCode) {
205
+ try {
206
+ const baseURL = await this.baseURLPromise;
207
+ const url = `${baseURL}/auth/token`;
208
+ const controller = new AbortController();
209
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
210
+ let response;
211
+ try {
212
+ response = await fetch(url, {
213
+ method: "POST",
214
+ headers: { "Content-Type": "application/json" },
215
+ body: JSON.stringify({
216
+ device_code: deviceCode,
217
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
218
+ }),
219
+ signal: controller.signal,
220
+ });
221
+ }
222
+ finally {
223
+ clearTimeout(timeoutId);
224
+ }
225
+ if (response.ok) {
226
+ const tokens = await response.json();
227
+ return { status: "success", tokens };
228
+ }
229
+ const errorData = await response.json().catch(() => ({}));
230
+ const errorCode = errorData.error ?? "unknown_error";
231
+ switch (errorCode) {
232
+ case "authorization_pending":
233
+ return { status: "authorization_pending" };
234
+ case "slow_down":
235
+ return { status: "slow_down" };
236
+ case "access_denied":
237
+ return { status: "access_denied" };
238
+ case "expired_token":
239
+ return { status: "expired_token" };
240
+ default:
241
+ throw new Error(`Unexpected error: ${errorCode}`);
242
+ }
243
+ }
244
+ catch (error) {
245
+ const nodeError = error;
246
+ if (nodeError.code === "ECONNREFUSED" ||
247
+ nodeError.code === "ENOTFOUND") {
248
+ throw new errors_1.NetworkError("Network error. Check your connection and try again.");
249
+ }
250
+ throw error;
251
+ }
34
252
  }
253
+ /**
254
+ * Refresh access token using refresh token.
255
+ */
256
+ async refreshToken(refreshToken) {
257
+ return this.request("POST", "/auth/refresh", {
258
+ body: { refresh_token: refreshToken },
259
+ authenticated: false,
260
+ });
261
+ }
262
+ // ──────────────────────────────────────────────────────────
263
+ // Module endpoints (authenticated)
264
+ // ──────────────────────────────────────────────────────────
265
+ /**
266
+ * List available modules with optional filters.
267
+ */
268
+ async listModules(filters) {
269
+ const params = new URLSearchParams();
270
+ if (filters?.category)
271
+ params.set("category", filters.category);
272
+ if (filters?.tier)
273
+ params.set("tier", filters.tier);
274
+ if (filters?.q)
275
+ params.set("q", filters.q);
276
+ if (filters?.page)
277
+ params.set("page", String(filters.page));
278
+ if (filters?.pageSize)
279
+ params.set("pageSize", String(filters.pageSize));
280
+ const query = params.toString();
281
+ const endpoint = `/modules${query ? `?${query}` : ""}`;
282
+ return this.request("GET", endpoint);
283
+ }
284
+ /**
285
+ * Get a single module by slug.
286
+ */
287
+ async getModule(slug) {
288
+ return this.request("GET", `/modules/${slug}`);
289
+ }
290
+ /**
291
+ * Get a module's manifest for a specific version.
292
+ */
293
+ async getManifest(slug, version) {
294
+ return this.request("GET", `/modules/${slug}/versions/${version}/manifest`);
295
+ }
296
+ /**
297
+ * Create a download token for a module release.
298
+ */
299
+ async createDownloadToken(moduleSlug, version) {
300
+ return this.request("POST", "/download-tokens", {
301
+ body: { moduleSlug, version },
302
+ authenticated: true,
303
+ });
304
+ }
305
+ // ──────────────────────────────────────────────────────────
306
+ // License endpoints
307
+ // ──────────────────────────────────────────────────────────
308
+ /**
309
+ * Validate a license key against the required tier.
310
+ */
311
+ async validateLicense(licenseKey, requiredTier) {
312
+ const response = await this.request('POST', '/licenses/validate', {
313
+ body: { licenseKey, requiredTier },
314
+ });
315
+ return response;
316
+ }
317
+ /**
318
+ * Get full license status including expiry information.
319
+ */
320
+ async getLicenseStatus(licenseKey) {
321
+ return this.request('GET', `/licenses/status?key=${encodeURIComponent(licenseKey)}`);
322
+ }
323
+ // ──────────────────────────────────────────────────────────
324
+ // Legacy / backward-compat methods
325
+ // ──────────────────────────────────────────────────────────
326
+ /**
327
+ * @deprecated Use getManifest(slug, version) instead.
328
+ */
35
329
  async getModuleManifest(moduleId) {
36
- await new Promise((resolve) => setTimeout(resolve, 1000));
37
- const module = this.mockModules.find((m) => m.id === moduleId);
38
- if (!module)
39
- return null;
40
- // Gerar manifest mockado baseado no ID
41
- return {
42
- name: module.id,
43
- version: module.version,
44
- description: module.description,
45
- author: module.author,
46
- license: "Proprietary",
47
- dependencies: {
48
- npm: [],
49
- peerModules: [],
50
- kavenVersion: ">=0.1.0",
51
- },
52
- files: {
53
- backend: [],
54
- frontend: [],
55
- database: [],
56
- },
57
- injections: [
58
- {
59
- file: "kaven-setup.ts",
60
- anchor: "// KAVEN_INIT",
61
- code: `console.log("Module ${module.name} initialized!");`,
62
- moduleName: module.id,
63
- },
64
- ],
65
- scripts: {
66
- postInstall: null,
67
- preRemove: null,
68
- },
69
- env: [],
70
- };
330
+ try {
331
+ // Try to get latest manifest for backward-compat we use "latest"
332
+ return await this.getManifest(moduleId, "latest");
333
+ }
334
+ catch (error) {
335
+ if (error instanceof errors_1.NotFoundError)
336
+ return null;
337
+ throw error;
338
+ }
339
+ }
340
+ /**
341
+ * Get release details for a specific module version.
342
+ * Returns checksum, signature, and publicKey for verification.
343
+ */
344
+ async getReleaseInfo(slug, version) {
345
+ return this.request("GET", `/modules/${slug}/versions/${version}`);
346
+ }
347
+ // ──────────────────────────────────────────────────────────
348
+ // Publish endpoints (authenticated)
349
+ // ──────────────────────────────────────────────────────────
350
+ /**
351
+ * Get a presigned S3 upload URL for a new module release.
352
+ */
353
+ async getUploadUrl(moduleSlug, version, size) {
354
+ return this.request("POST", "/releases/upload-url", {
355
+ body: { moduleSlug, version, size },
356
+ authenticated: true,
357
+ });
358
+ }
359
+ /**
360
+ * Create a release record after uploading the artifact.
361
+ */
362
+ async createRelease(data) {
363
+ return this.request("POST", "/releases", {
364
+ body: data,
365
+ authenticated: true,
366
+ });
367
+ }
368
+ // ──────────────────────────────────────────────────────────
369
+ // Checkout / upgrade endpoints (authenticated)
370
+ // ──────────────────────────────────────────────────────────
371
+ /**
372
+ * Create a Paddle checkout session for tier upgrade.
373
+ */
374
+ async createCheckoutSession(tier, licenseKey) {
375
+ return this.request("POST", "/checkout/session", {
376
+ body: { tier, licenseKey },
377
+ authenticated: true,
378
+ });
379
+ }
380
+ /**
381
+ * Poll the status of an ongoing Paddle checkout session.
382
+ */
383
+ async getCheckoutStatus(sessionId) {
384
+ return this.request("GET", `/checkout/session/${sessionId}/status`, { authenticated: true });
385
+ }
386
+ // ──────────────────────────────────────────────────────────
387
+ // Categories endpoint (authenticated)
388
+ // ──────────────────────────────────────────────────────────
389
+ /**
390
+ * Get all available module categories.
391
+ */
392
+ async getCategories() {
393
+ const result = await this.request("GET", "/modules/categories", { authenticated: true });
394
+ return result.categories;
71
395
  }
72
396
  }
73
397
  exports.MarketplaceClient = MarketplaceClient;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SignatureVerificationError = exports.NetworkError = exports.ServerError = exports.RateLimitError = exports.NotFoundError = exports.LicenseRequiredError = exports.AuthenticationError = exports.MarketplaceError = void 0;
4
+ class MarketplaceError extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "MarketplaceError";
8
+ }
9
+ }
10
+ exports.MarketplaceError = MarketplaceError;
11
+ class AuthenticationError extends MarketplaceError {
12
+ constructor(message) {
13
+ super(message);
14
+ this.name = "AuthenticationError";
15
+ }
16
+ }
17
+ exports.AuthenticationError = AuthenticationError;
18
+ class LicenseRequiredError extends MarketplaceError {
19
+ constructor(requiredTier, message) {
20
+ super(message);
21
+ this.requiredTier = requiredTier;
22
+ this.name = "LicenseRequiredError";
23
+ }
24
+ }
25
+ exports.LicenseRequiredError = LicenseRequiredError;
26
+ class NotFoundError extends MarketplaceError {
27
+ constructor(message) {
28
+ super(message);
29
+ this.name = "NotFoundError";
30
+ }
31
+ }
32
+ exports.NotFoundError = NotFoundError;
33
+ class RateLimitError extends MarketplaceError {
34
+ constructor(retryAfter) {
35
+ super(`Rate limited. Try again in ${retryAfter}s`);
36
+ this.retryAfter = retryAfter;
37
+ this.name = "RateLimitError";
38
+ }
39
+ }
40
+ exports.RateLimitError = RateLimitError;
41
+ class ServerError extends MarketplaceError {
42
+ constructor(message) {
43
+ super(message);
44
+ this.name = "ServerError";
45
+ }
46
+ }
47
+ exports.ServerError = ServerError;
48
+ class NetworkError extends MarketplaceError {
49
+ constructor(message) {
50
+ super(message);
51
+ this.name = "NetworkError";
52
+ }
53
+ }
54
+ exports.NetworkError = NetworkError;
55
+ class SignatureVerificationError extends MarketplaceError {
56
+ constructor(message) {
57
+ super(message);
58
+ this.name = "SignatureVerificationError";
59
+ }
60
+ }
61
+ exports.SignatureVerificationError = SignatureVerificationError;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kaven-cli",
3
- "version": "0.1.0-alpha.1",
3
+ "version": "0.3.5",
4
4
  "description": "Kaven CLI - The official command line tool for Kaven",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -12,7 +12,7 @@
12
12
  ],
13
13
  "scripts": {
14
14
  "build": "tsc",
15
- "prepublishOnly": "pnpm run build && pnpm run quality",
15
+ "prepublishOnly": "pnpm run build",
16
16
  "lint": "eslint 'src/**/*.{ts,tsx}' --max-warnings 0",
17
17
  "lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix",
18
18
  "test": "vitest run",
@@ -39,14 +39,22 @@
39
39
  "license": "Apache-2.0",
40
40
  "repository": {
41
41
  "type": "git",
42
- "url": "https://github.com/KavenCompany/kaven-cli"
42
+ "url": "https://github.com/kaven-co/kaven-cli"
43
43
  },
44
44
  "devDependencies": {
45
+ "@semantic-release/changelog": "^6.0.3",
46
+ "@semantic-release/commit-analyzer": "^13.0.1",
47
+ "@semantic-release/github": "^12.0.6",
48
+ "@semantic-release/npm": "^13.1.5",
49
+ "@semantic-release/release-notes-generator": "^14.1.0",
45
50
  "@types/fs-extra": "^11.0.4",
46
51
  "@types/node": "^20.0.0",
52
+ "@types/tar": "^6.1.13",
47
53
  "@typescript-eslint/eslint-plugin": "^8.53.1",
48
54
  "@typescript-eslint/parser": "^8.53.1",
49
55
  "eslint": "^8.0.0",
56
+ "msw": "^2.12.10",
57
+ "semantic-release": "^25.0.3",
50
58
  "typescript": "^5.0.0",
51
59
  "vitest": "^1.0.0"
52
60
  },
@@ -54,11 +62,22 @@
54
62
  "node": ">=20"
55
63
  },
56
64
  "dependencies": {
65
+ "@inquirer/prompts": "^7.5.2",
57
66
  "chalk": "^5.6.2",
67
+ "cli-table3": "^0.6.5",
58
68
  "commander": "^14.0.2",
59
69
  "fs-extra": "^11.3.3",
60
70
  "glob": "^13.0.0",
71
+ "open": "^10.1.0",
61
72
  "ora": "^9.1.0",
73
+ "tar": "^7.5.9",
62
74
  "zod": "^4.3.6"
75
+ },
76
+ "pnpm": {
77
+ "overrides": {
78
+ "minimatch@<10.2.1": ">=10.2.1",
79
+ "@isaacs/brace-expansion@<=5.0.0": ">=5.0.1",
80
+ "esbuild@<=0.24.2": ">=0.25.0"
81
+ }
63
82
  }
64
- }
83
+ }
@@ -1,53 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.addCommand = void 0;
7
- const commander_1 = require("commander");
8
- const path_1 = __importDefault(require("path"));
9
- const fs_extra_1 = __importDefault(require("fs-extra"));
10
- const ModuleManager_1 = require("../../core/modules/ModuleManager");
11
- const ModuleInstaller_1 = require("../../core/modules/ModuleInstaller");
12
- const logger_1 = require("../../lib/logger");
13
- exports.addCommand = new commander_1.Command('add')
14
- .description('Install a module')
15
- .argument('<slug>', 'Module slug to install')
16
- .action(async (slug) => {
17
- try {
18
- const projectRoot = process.cwd();
19
- // Locate modules source:
20
- // In dev: ./modules
21
- // In prod (installed): ../modules relative to dist
22
- // For now, assume we run from CLI root or use logic to find 'modules' folder.
23
- // Ideally CLI should be installed in a way that 'modules' folder is known.
24
- // Fallback logic for finding modules source:
25
- // 1. Env var KAVEN_MODULES_PATH
26
- // 2. Local ./modules
27
- // 3. Resolve relative to __dirname (dist) -> ../modules
28
- let modulesSource = process.env.KAVEN_MODULES_PATH;
29
- if (!modulesSource) {
30
- if (await fs_extra_1.default.pathExists(path_1.default.resolve('modules'))) {
31
- modulesSource = path_1.default.resolve('modules');
32
- }
33
- else {
34
- modulesSource = path_1.default.resolve(__dirname, '../../modules');
35
- }
36
- }
37
- if (!await fs_extra_1.default.pathExists(modulesSource)) {
38
- logger_1.Logger.error(`Module source not found at ${modulesSource}`);
39
- return;
40
- }
41
- const manifestPath = path_1.default.join(modulesSource, slug, 'module.json');
42
- if (!await fs_extra_1.default.pathExists(manifestPath)) {
43
- logger_1.Logger.error(`Module ${slug} not found in catalog.`);
44
- return;
45
- }
46
- const manifest = await ModuleManager_1.ModuleManager.loadManifest(manifestPath);
47
- await ModuleInstaller_1.ModuleInstaller.install(manifest, projectRoot, modulesSource);
48
- }
49
- catch (error) {
50
- logger_1.Logger.error('Failed to add module', error);
51
- process.exit(1);
52
- }
53
- });