kaven-cli 0.4.0-alpha.1 → 0.4.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +147 -84
- package/README.pt-BR.md +334 -0
- package/dist/EnvManager-GQMEZ6NV.js +158 -0
- package/dist/MarketplaceClient-IJGRQRC4.js +7 -0
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/chunk-GHZX5OAA.js +455 -0
- package/dist/commands/aiox/index.js +20 -0
- package/dist/commands/config/features.js +110 -1008
- package/dist/commands/config/index.js +1 -34
- package/dist/commands/index.js +1 -0
- package/dist/commands/init/aiox-bootstrap.js +83 -0
- package/dist/commands/init/index.js +20 -40
- package/dist/commands/marketplace/browse.js +1 -34
- package/dist/commands/module/activate.js +89 -48
- package/dist/commands/module/list.js +51 -0
- package/dist/commands/module/publish.js +2 -35
- package/dist/commands/upgrade/index.js +6 -39
- package/dist/core/AuthService.js +2 -34
- package/dist/core/CacheManager.js +3 -0
- package/dist/core/ConfigManager.js +8 -7
- package/dist/core/ErrorRecovery.js +1 -0
- package/dist/core/LicenseService.js +3 -38
- package/dist/core/ModuleDoctor.js +3 -0
- package/dist/core/ModuleInstaller.js +5 -36
- package/dist/core/ProjectInitializer.js +43 -5
- package/dist/core/RegistryResolver.js +3 -2
- package/dist/core/SchemaActivator.js +29 -8
- package/dist/core/ScriptRunner.js +3 -2
- package/dist/core/index.js +1 -0
- package/dist/index.js +30 -9
- package/dist/infrastructure/Container.js +2 -4
- package/dist/infrastructure/MarketplaceClient.js +31 -3
- package/dist/infrastructure/TelemetryBuffer.js +3 -1
- package/dist/infrastructure/TransactionalFileSystem.js +4 -1
- package/dist/infrastructure/errors.js +2 -0
- package/dist/infrastructure/index.js +1 -0
- package/dist/lib/capabilities-catalog.js +73 -0
- package/dist/lib/module-registry.js +47 -0
- package/dist/lib/schema-modifier.js +40 -0
- package/dist/tier-table-LAL6PAVW.js +52 -0
- package/package.json +11 -3
- 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
package/dist/index.js
CHANGED
|
@@ -22,12 +22,13 @@ const index_3 = require("./commands/cache/index");
|
|
|
22
22
|
const index_4 = require("./commands/config/index");
|
|
23
23
|
const features_1 = require("./commands/config/features");
|
|
24
24
|
const index_5 = require("./commands/init-ci/index");
|
|
25
|
+
const aiox_1 = require("./commands/aiox");
|
|
25
26
|
const main = () => {
|
|
26
27
|
const program = new commander_1.Command();
|
|
27
28
|
program
|
|
28
29
|
.name("kaven")
|
|
29
30
|
.description("The official CLI for the Kaven SaaS boilerplate ecosystem")
|
|
30
|
-
.version("0.
|
|
31
|
+
.version("0.4.1-alpha.0")
|
|
31
32
|
.addHelpText("after", `
|
|
32
33
|
Examples:
|
|
33
34
|
$ kaven init my-saas-app Bootstrap a new Kaven project
|
|
@@ -37,7 +38,7 @@ Examples:
|
|
|
37
38
|
$ kaven upgrade Upgrade your license tier
|
|
38
39
|
$ kaven module doctor Check project health
|
|
39
40
|
|
|
40
|
-
Documentation: https://docs.kaven.
|
|
41
|
+
Documentation: https://docs.kaven.site/cli
|
|
41
42
|
Support: https://github.com/kaven-co/kaven-cli/issues
|
|
42
43
|
`);
|
|
43
44
|
/**
|
|
@@ -50,7 +51,9 @@ Support: https://github.com/kaven-co/kaven-cli/issues
|
|
|
50
51
|
.option("--skip-install", "Skip running pnpm install after setup")
|
|
51
52
|
.option("--skip-git", "Skip git init and initial commit")
|
|
52
53
|
.option("--force", "Overwrite existing directory if it exists")
|
|
54
|
+
.option("--template <path>", "Path to a local template or custom git repository URL")
|
|
53
55
|
.option("--with-squad", "Install kaven-squad (AIOX) into squads/kaven-squad/ after scaffold")
|
|
56
|
+
.option("--skip-aiox", "Skip AIOX environment bootstrap")
|
|
54
57
|
.addHelpText("after", `
|
|
55
58
|
Examples:
|
|
56
59
|
$ kaven init my-app Interactive setup
|
|
@@ -63,7 +66,9 @@ Examples:
|
|
|
63
66
|
skipInstall: opts.skipInstall,
|
|
64
67
|
skipGit: opts.skipGit,
|
|
65
68
|
force: opts.force,
|
|
69
|
+
template: opts.template,
|
|
66
70
|
withSquad: opts.withSquad,
|
|
71
|
+
skipAiox: opts.skipAiox,
|
|
67
72
|
}));
|
|
68
73
|
/**
|
|
69
74
|
* Modules Group
|
|
@@ -138,35 +143,46 @@ Examples:
|
|
|
138
143
|
changelog: opts.changelog,
|
|
139
144
|
}));
|
|
140
145
|
moduleCommand
|
|
141
|
-
.command("activate <name>")
|
|
146
|
+
.command("activate <name> [root]")
|
|
142
147
|
.description("Activate a Kaven schema module by uncommenting its models in schema.extended.prisma")
|
|
148
|
+
.option("--with-deps", "Automatically activate required dependencies")
|
|
149
|
+
.option("--skip-migrate", "Skip db:generate and db:migrate after activation")
|
|
150
|
+
.option("--dry-run", "Show affected models without modifying schema")
|
|
151
|
+
.option("--yes", "Skip confirmation prompt")
|
|
143
152
|
.addHelpText("after", `
|
|
144
153
|
Modules: billing, projects, notifications
|
|
145
154
|
|
|
146
155
|
Examples:
|
|
147
156
|
$ kaven module activate billing
|
|
148
157
|
$ kaven module activate projects
|
|
158
|
+
$ kaven module activate projects ./my-app
|
|
159
|
+
$ kaven module activate billing --with-deps
|
|
149
160
|
`)
|
|
150
|
-
.action((name) => (0, activate_1.moduleActivate)(name));
|
|
161
|
+
.action((name, root, opts) => (0, activate_1.moduleActivate)(name, root, opts));
|
|
151
162
|
moduleCommand
|
|
152
|
-
.command("deactivate <name>")
|
|
163
|
+
.command("deactivate <name> [root]")
|
|
153
164
|
.description("Deactivate a Kaven schema module by commenting its models in schema.extended.prisma")
|
|
165
|
+
.option("--skip-migrate", "Skip db:generate and db:migrate")
|
|
166
|
+
.option("--dry-run", "Show affected models without modifying schema")
|
|
167
|
+
.option("--yes", "Skip confirmation prompt")
|
|
154
168
|
.addHelpText("after", `
|
|
155
169
|
Modules: billing, projects, notifications
|
|
156
170
|
|
|
157
171
|
Examples:
|
|
158
172
|
$ kaven module deactivate billing
|
|
159
173
|
$ kaven module deactivate projects
|
|
174
|
+
$ kaven module deactivate projects ./my-app
|
|
160
175
|
`)
|
|
161
|
-
.action((name) => (0, activate_1.moduleDeactivate)(name));
|
|
176
|
+
.action((name, root, opts) => (0, activate_1.moduleDeactivate)(name, root, opts));
|
|
162
177
|
moduleCommand
|
|
163
|
-
.command("list")
|
|
178
|
+
.command("list [root]")
|
|
164
179
|
.description("List available Kaven schema modules with their status, models, and dependencies")
|
|
165
180
|
.addHelpText("after", `
|
|
166
181
|
Examples:
|
|
167
182
|
$ kaven module list
|
|
183
|
+
$ kaven module list ./my-app
|
|
168
184
|
`)
|
|
169
|
-
.action(() => (0, activate_1.moduleListActivation)());
|
|
185
|
+
.action((root) => (0, activate_1.moduleListActivation)(root));
|
|
170
186
|
/**
|
|
171
187
|
* Auth Group
|
|
172
188
|
*/
|
|
@@ -390,9 +406,14 @@ Examples:
|
|
|
390
406
|
$ kaven init-ci --dry-run Show what would be created
|
|
391
407
|
`)
|
|
392
408
|
.action((opts) => (0, index_5.initCi)({ dryRun: opts.dryRun }));
|
|
393
|
-
|
|
409
|
+
/**
|
|
410
|
+
* AIOX Commands
|
|
411
|
+
*/
|
|
412
|
+
(0, aiox_1.registerAioxCommand)(program);
|
|
413
|
+
program.parse(process.argv);
|
|
394
414
|
};
|
|
395
415
|
exports.main = main;
|
|
416
|
+
// Execute main if this is the entry point
|
|
396
417
|
if (require.main === module) {
|
|
397
418
|
(0, exports.main)();
|
|
398
419
|
}
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.container = exports.Container = void 0;
|
|
4
4
|
class Container {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
this.factories = new Map();
|
|
8
|
-
}
|
|
5
|
+
services = new Map();
|
|
6
|
+
factories = new Map();
|
|
9
7
|
register(name, factory) {
|
|
10
8
|
this.factories.set(name, factory);
|
|
11
9
|
}
|
|
@@ -8,10 +8,10 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const os_1 = __importDefault(require("os"));
|
|
10
10
|
const errors_1 = require("./errors");
|
|
11
|
-
const DEFAULT_BASE_URL = "https://
|
|
12
|
-
const REQUEST_TIMEOUT_MS =
|
|
11
|
+
const DEFAULT_BASE_URL = "https://marketplace.kaven.site";
|
|
12
|
+
const REQUEST_TIMEOUT_MS = 30_000;
|
|
13
13
|
const MAX_RETRIES = 3;
|
|
14
|
-
const INITIAL_RETRY_DELAY_MS =
|
|
14
|
+
const INITIAL_RETRY_DELAY_MS = 1_000;
|
|
15
15
|
function debug(message) {
|
|
16
16
|
if (process.env.KAVEN_DEBUG === "1") {
|
|
17
17
|
console.debug(`[kaven:debug] ${message}`);
|
|
@@ -33,6 +33,28 @@ async function loadConfigApiUrl() {
|
|
|
33
33
|
}
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Load a service token for agent-to-service auth.
|
|
38
|
+
* Resolution order: KAVEN_SERVICE_TOKEN env → ~/.kaven/config.json#serviceToken
|
|
39
|
+
*/
|
|
40
|
+
async function loadServiceToken() {
|
|
41
|
+
if (process.env.KAVEN_SERVICE_TOKEN) {
|
|
42
|
+
return process.env.KAVEN_SERVICE_TOKEN;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const configPath = path_1.default.join(os_1.default.homedir(), ".kaven", "config.json");
|
|
46
|
+
if (await fs_extra_1.default.pathExists(configPath)) {
|
|
47
|
+
const config = await fs_extra_1.default.readJson(configPath);
|
|
48
|
+
if (typeof config.serviceToken === "string" && config.serviceToken) {
|
|
49
|
+
return config.serviceToken;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Ignore config read errors
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
36
58
|
/** Resolve base URL from env → config file → default. */
|
|
37
59
|
async function resolveBaseUrl() {
|
|
38
60
|
if (process.env.KAVEN_API_URL) {
|
|
@@ -53,6 +75,8 @@ function isRetryable(status) {
|
|
|
53
75
|
return status >= 500;
|
|
54
76
|
}
|
|
55
77
|
class MarketplaceClient {
|
|
78
|
+
baseURLPromise;
|
|
79
|
+
authService;
|
|
56
80
|
constructor(authService) {
|
|
57
81
|
this.authService = authService ?? null;
|
|
58
82
|
this.baseURLPromise = resolveBaseUrl();
|
|
@@ -89,6 +113,10 @@ class MarketplaceClient {
|
|
|
89
113
|
const token = await this.authService.getValidToken();
|
|
90
114
|
headers["Authorization"] = `Bearer ${token}`;
|
|
91
115
|
}
|
|
116
|
+
const serviceToken = await loadServiceToken();
|
|
117
|
+
if (serviceToken) {
|
|
118
|
+
headers["X-Service-Token"] = serviceToken;
|
|
119
|
+
}
|
|
92
120
|
debug(`${method} ${url}`);
|
|
93
121
|
const controller = new AbortController();
|
|
94
122
|
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
@@ -8,8 +8,10 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const os_1 = __importDefault(require("os"));
|
|
10
10
|
class TelemetryBuffer {
|
|
11
|
+
static instance;
|
|
12
|
+
logPath;
|
|
13
|
+
buffer = [];
|
|
11
14
|
constructor() {
|
|
12
|
-
this.buffer = [];
|
|
13
15
|
this.logPath = path_1.default.join(os_1.default.homedir(), ".kaven", "telemetry.log");
|
|
14
16
|
}
|
|
15
17
|
static getInstance() {
|
|
@@ -8,9 +8,12 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const glob_1 = require("glob");
|
|
10
10
|
class TransactionalFileSystem {
|
|
11
|
+
projectRoot;
|
|
12
|
+
backupDir;
|
|
13
|
+
backupId;
|
|
14
|
+
filesToBackup = [];
|
|
11
15
|
constructor(projectRoot, backupDir = ".agent/backups") {
|
|
12
16
|
this.projectRoot = projectRoot;
|
|
13
|
-
this.filesToBackup = [];
|
|
14
17
|
this.backupDir = path_1.default.join(projectRoot, backupDir);
|
|
15
18
|
this.backupId = `backup_${Date.now()}`;
|
|
16
19
|
}
|
|
@@ -16,6 +16,7 @@ class AuthenticationError extends MarketplaceError {
|
|
|
16
16
|
}
|
|
17
17
|
exports.AuthenticationError = AuthenticationError;
|
|
18
18
|
class LicenseRequiredError extends MarketplaceError {
|
|
19
|
+
requiredTier;
|
|
19
20
|
constructor(requiredTier, message) {
|
|
20
21
|
super(message);
|
|
21
22
|
this.requiredTier = requiredTier;
|
|
@@ -31,6 +32,7 @@ class NotFoundError extends MarketplaceError {
|
|
|
31
32
|
}
|
|
32
33
|
exports.NotFoundError = NotFoundError;
|
|
33
34
|
class RateLimitError extends MarketplaceError {
|
|
35
|
+
retryAfter;
|
|
34
36
|
constructor(retryAfter) {
|
|
35
37
|
super(`Rate limited. Try again in ${retryAfter}s`);
|
|
36
38
|
this.retryAfter = retryAfter;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TIER_DEFAULTS = exports.ALL_CAPABILITIES = void 0;
|
|
4
|
+
exports.ALL_CAPABILITIES = [
|
|
5
|
+
// --- AUTH ---
|
|
6
|
+
{ key: "FEATURE_EMAIL_VERIFICATION", type: "boolean", description: "Email verification on signup", category: "Auth", defaultValue: "true" },
|
|
7
|
+
{ key: "FEATURE_2FA_TOTP", type: "boolean", description: "Two-factor authentication via TOTP", category: "Auth", defaultValue: "false" },
|
|
8
|
+
{ key: "FEATURE_SSO_SAML", type: "boolean", description: "Single Sign-On via SAML/OIDC", category: "Auth", defaultValue: "false" },
|
|
9
|
+
{ key: "FEATURE_SOCIAL_LOGIN", type: "boolean", description: "Login via Google, GitHub, etc.", category: "Auth", defaultValue: "true" },
|
|
10
|
+
{ key: "FEATURE_MAGIC_LINK", type: "boolean", description: "Passwordless login via email", category: "Auth", defaultValue: "false" },
|
|
11
|
+
// --- TENANCY ---
|
|
12
|
+
{ key: "FEATURE_CUSTOM_DOMAIN", type: "boolean", description: "Custom domain per tenant", category: "Tenancy", defaultValue: "false" },
|
|
13
|
+
{ key: "FEATURE_WHITE_LABEL", type: "boolean", description: "Remove Kaven branding", category: "Tenancy", defaultValue: "false" },
|
|
14
|
+
{ key: "FEATURE_MULTI_BUSINESS", type: "boolean", description: "Multiple businesses per user", category: "Tenancy", defaultValue: "false" },
|
|
15
|
+
{ key: "FEATURE_AGENCY_HUB", type: "boolean", description: "Agency management dashboard", category: "Tenancy", defaultValue: "false" },
|
|
16
|
+
{ key: "FEATURE_TENANT_THEMES", type: "boolean", description: "Custom themes for tenants", category: "Tenancy", defaultValue: "true" },
|
|
17
|
+
// --- BILLING ---
|
|
18
|
+
{ key: "FEATURE_SUBSCRIPTIONS", type: "boolean", description: "Subscription management", category: "Billing", defaultValue: "true" },
|
|
19
|
+
{ key: "FEATURE_INVOICING", type: "boolean", description: "Automatic invoicing", category: "Billing", defaultValue: "true" },
|
|
20
|
+
{ key: "FEATURE_USAGE_BILLING", type: "boolean", description: "Metered usage billing", category: "Billing", defaultValue: "false" },
|
|
21
|
+
{ key: "FEATURE_PADDLE_CHECKOUT", type: "boolean", description: "Paddle payment integration", category: "Billing", defaultValue: "true" },
|
|
22
|
+
{ key: "FEATURE_PAGUBIT_PIX", type: "boolean", description: "Pix payment support", category: "Billing", defaultValue: "false" },
|
|
23
|
+
// --- API ---
|
|
24
|
+
{ key: "FEATURE_API_ACCESS", type: "boolean", description: "External API access", category: "API", defaultValue: "false" },
|
|
25
|
+
{ key: "FEATURE_WEBHOOKS", type: "boolean", description: "Outgoing webhooks", category: "API", defaultValue: "false" },
|
|
26
|
+
{ key: "FEATURE_MARKETPLACE_ACCESS", type: "boolean", description: "Kaven Marketplace access", category: "API", defaultValue: "true" },
|
|
27
|
+
{ key: "MAX_API_CALLS_MONTH", type: "numeric", description: "Maximum API calls per month", category: "API", defaultValue: "10000" },
|
|
28
|
+
{ key: "MAX_AGENT_API_CALLS_HOUR", type: "numeric", description: "Maximum agent calls per hour", category: "API", defaultValue: "100" },
|
|
29
|
+
// --- LIMITS ---
|
|
30
|
+
{ key: "MAX_TEAM_MEMBERS", type: "numeric", description: "Maximum team members per tenant", category: "Limits", defaultValue: "5" },
|
|
31
|
+
{ key: "MAX_PROJECTS", type: "numeric", description: "Maximum projects per tenant", category: "Limits", defaultValue: "3" },
|
|
32
|
+
{ key: "MAX_STORAGE_GB", type: "numeric", description: "Maximum storage in GB", category: "Limits", defaultValue: "1" },
|
|
33
|
+
{ key: "MAX_TENANTS", type: "numeric", description: "Maximum sub-tenants", category: "Limits", defaultValue: "1" },
|
|
34
|
+
// --- SUPPORT ---
|
|
35
|
+
{ key: "FEATURE_PRIORITY_SUPPORT", type: "boolean", description: "Priority support queue", category: "Support", defaultValue: "false" },
|
|
36
|
+
{ key: "FEATURE_AUDIT_COMPLIANCE", type: "boolean", description: "Audit logs and compliance", category: "Support", defaultValue: "false" },
|
|
37
|
+
{ key: "FEATURE_DATA_EXPORT", type: "boolean", description: "Customer data export", category: "Support", defaultValue: "true" },
|
|
38
|
+
];
|
|
39
|
+
exports.TIER_DEFAULTS = {
|
|
40
|
+
starter: {
|
|
41
|
+
FEATURE_EMAIL_VERIFICATION: true,
|
|
42
|
+
FEATURE_SOCIAL_LOGIN: true,
|
|
43
|
+
FEATURE_MARKETPLACE_ACCESS: true,
|
|
44
|
+
MAX_TEAM_MEMBERS: "5",
|
|
45
|
+
MAX_PROJECTS: "3",
|
|
46
|
+
MAX_API_CALLS_MONTH: "10000",
|
|
47
|
+
MAX_AGENT_API_CALLS_HOUR: "100",
|
|
48
|
+
},
|
|
49
|
+
complete: {
|
|
50
|
+
FEATURE_EMAIL_VERIFICATION: true,
|
|
51
|
+
FEATURE_SOCIAL_LOGIN: true,
|
|
52
|
+
FEATURE_CUSTOM_DOMAIN: true,
|
|
53
|
+
FEATURE_API_ACCESS: true,
|
|
54
|
+
FEATURE_MARKETPLACE_ACCESS: true,
|
|
55
|
+
MAX_TEAM_MEMBERS: "25",
|
|
56
|
+
MAX_PROJECTS: "20",
|
|
57
|
+
MAX_API_CALLS_MONTH: "100000",
|
|
58
|
+
MAX_AGENT_API_CALLS_HOUR: "500",
|
|
59
|
+
},
|
|
60
|
+
pro: {
|
|
61
|
+
FEATURE_EMAIL_VERIFICATION: true,
|
|
62
|
+
FEATURE_SOCIAL_LOGIN: true,
|
|
63
|
+
FEATURE_CUSTOM_DOMAIN: true,
|
|
64
|
+
FEATURE_WHITE_LABEL: true,
|
|
65
|
+
FEATURE_API_ACCESS: true,
|
|
66
|
+
FEATURE_MARKETPLACE_ACCESS: true,
|
|
67
|
+
MAX_TEAM_MEMBERS: "100",
|
|
68
|
+
MAX_PROJECTS: "100",
|
|
69
|
+
MAX_API_CALLS_MONTH: "1000000",
|
|
70
|
+
MAX_AGENT_API_CALLS_HOUR: "2000",
|
|
71
|
+
},
|
|
72
|
+
enterprise: {}
|
|
73
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MODULE_REGISTRY = void 0;
|
|
4
|
+
exports.MODULE_REGISTRY = [
|
|
5
|
+
{
|
|
6
|
+
id: "core",
|
|
7
|
+
name: "Core",
|
|
8
|
+
description: "Base models — always active, cannot be deactivated",
|
|
9
|
+
models: ["Tenant", "User", "Role", "Capability", "AuthSession", "AuditLog", "RefreshToken", "EmailVerification"],
|
|
10
|
+
dependsOn: [],
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: "billing",
|
|
14
|
+
name: "Billing",
|
|
15
|
+
description: "Subscriptions, invoices, orders, payments",
|
|
16
|
+
models: ["Invoice", "Order", "Subscription", "Plan", "Payment", "Product"],
|
|
17
|
+
dependsOn: ["core"],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "projects",
|
|
21
|
+
name: "Projects",
|
|
22
|
+
description: "Spaces, projects, tasks — project management features",
|
|
23
|
+
models: ["Space", "Project", "Task"],
|
|
24
|
+
dependsOn: ["core"],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "notifications",
|
|
28
|
+
name: "Notifications",
|
|
29
|
+
description: "In-app notifications and user preferences",
|
|
30
|
+
models: ["Notification", "UserPreference"],
|
|
31
|
+
dependsOn: ["core"],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "service-tokens",
|
|
35
|
+
name: "Service Tokens",
|
|
36
|
+
description: "Agent authentication tokens for AIOX integration",
|
|
37
|
+
models: ["ServiceToken"],
|
|
38
|
+
dependsOn: ["core"],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: "marketing-tracking",
|
|
42
|
+
name: "Marketing Tracking",
|
|
43
|
+
description: "Ad tracking, GTM, GA4 and Meta CAPI observability",
|
|
44
|
+
models: ["TrackingEvent"],
|
|
45
|
+
dependsOn: ["core"],
|
|
46
|
+
},
|
|
47
|
+
];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deactivateModels = deactivateModels;
|
|
4
|
+
exports.activateModels = activateModels;
|
|
5
|
+
exports.isModuleActive = isModuleActive;
|
|
6
|
+
/**
|
|
7
|
+
* Deactivates models by commenting them out in the Prisma schema
|
|
8
|
+
*/
|
|
9
|
+
function deactivateModels(schemaContent, models) {
|
|
10
|
+
let updatedSchema = schemaContent;
|
|
11
|
+
for (const modelName of models) {
|
|
12
|
+
const modelRegex = new RegExp(`^model ${modelName} \\{[^}]*\\}`, "gm");
|
|
13
|
+
updatedSchema = updatedSchema.replace(modelRegex, (match) => match.split("\n").map(line => `// ${line}`).join("\n"));
|
|
14
|
+
}
|
|
15
|
+
return updatedSchema;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Activates models by uncommenting them in the Prisma schema
|
|
19
|
+
*/
|
|
20
|
+
function activateModels(schemaContent, models) {
|
|
21
|
+
let updatedSchema = schemaContent;
|
|
22
|
+
for (const modelName of models) {
|
|
23
|
+
// Regex matches multiple lines starting with // until the closing brace of the model
|
|
24
|
+
const regex = new RegExp(`// model ${modelName} \\{[^}]*// \\}`, "gs");
|
|
25
|
+
updatedSchema = updatedSchema.replace(regex, (match) => {
|
|
26
|
+
return match.split("\n").map(line => line.replace(/^\/\/ /, "")).join("\n");
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return updatedSchema;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Checks if a module is currently active in the schema
|
|
33
|
+
*/
|
|
34
|
+
function isModuleActive(schemaContent, models) {
|
|
35
|
+
if (models.length === 0)
|
|
36
|
+
return true;
|
|
37
|
+
const firstModel = models[0];
|
|
38
|
+
const activeRegex = new RegExp(`^model ${firstModel} \\{`, "m");
|
|
39
|
+
return activeRegex.test(schemaContent);
|
|
40
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import "./chunk-3RG5ZIWI.js";
|
|
2
|
+
|
|
3
|
+
// src/commands/license/tier-table.ts
|
|
4
|
+
import Table from "cli-table3";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
var TIERS = [
|
|
7
|
+
{ name: "STARTER", price: "$149", projects: "1", tenants: "10", marketplace: false },
|
|
8
|
+
{ name: "COMPLETE", price: "$399", projects: "1", tenants: "Unlimited", marketplace: false },
|
|
9
|
+
{ name: "PRO", price: "$799", projects: "5", tenants: "Unlimited", marketplace: true },
|
|
10
|
+
{ name: "ENTERPRISE", price: "Custom", projects: "Unlimited", tenants: "Unlimited", marketplace: true }
|
|
11
|
+
];
|
|
12
|
+
function colorTier(tier) {
|
|
13
|
+
switch (tier.toUpperCase()) {
|
|
14
|
+
case "STARTER":
|
|
15
|
+
return chalk.green(tier);
|
|
16
|
+
case "COMPLETE":
|
|
17
|
+
return chalk.yellow(tier);
|
|
18
|
+
case "PRO":
|
|
19
|
+
return chalk.magenta(tier);
|
|
20
|
+
case "ENTERPRISE":
|
|
21
|
+
return chalk.cyan(tier);
|
|
22
|
+
default:
|
|
23
|
+
return tier;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function printTierComparisonTable(userTier, requiredTier) {
|
|
27
|
+
console.log(chalk.red("\n\u2717 License tier insufficient\n"));
|
|
28
|
+
console.log(` Your tier: ${colorTier(userTier)}`);
|
|
29
|
+
console.log(` Required tier: ${colorTier(requiredTier)}
|
|
30
|
+
`);
|
|
31
|
+
const table = new Table({
|
|
32
|
+
head: ["Tier", "Price", "Projects", "Tenants", "Marketplace"],
|
|
33
|
+
style: { head: ["cyan"] }
|
|
34
|
+
});
|
|
35
|
+
for (const t of TIERS) {
|
|
36
|
+
const isUser = t.name === userTier.toUpperCase();
|
|
37
|
+
const isRequired = t.name === requiredTier.toUpperCase();
|
|
38
|
+
const marker = isRequired ? chalk.yellow(" \u2190 required") : isUser ? chalk.dim(" \u2190 you") : "";
|
|
39
|
+
table.push([
|
|
40
|
+
colorTier(t.name) + marker,
|
|
41
|
+
t.price,
|
|
42
|
+
t.projects,
|
|
43
|
+
t.tenants,
|
|
44
|
+
t.marketplace ? chalk.green("\u2713") : chalk.dim("\u2717")
|
|
45
|
+
]);
|
|
46
|
+
}
|
|
47
|
+
console.log(table.toString());
|
|
48
|
+
console.log(chalk.dim("\n Upgrade at: https://kaven.dev/pricing\n"));
|
|
49
|
+
}
|
|
50
|
+
export {
|
|
51
|
+
printTierComparisonTable
|
|
52
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kaven-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1-alpha.0",
|
|
4
|
+
|
|
4
5
|
"description": "Kaven CLI - The official command line tool for Kaven",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"bin": {
|
|
@@ -12,7 +13,7 @@
|
|
|
12
13
|
],
|
|
13
14
|
"scripts": {
|
|
14
15
|
"build": "tsc",
|
|
15
|
-
"prepublishOnly": "pnpm run build
|
|
16
|
+
"prepublishOnly": "pnpm run build",
|
|
16
17
|
"lint": "eslint 'src/**/*.{ts,tsx}' --max-warnings 0",
|
|
17
18
|
"lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix",
|
|
18
19
|
"test": "vitest run",
|
|
@@ -39,9 +40,14 @@
|
|
|
39
40
|
"license": "Apache-2.0",
|
|
40
41
|
"repository": {
|
|
41
42
|
"type": "git",
|
|
42
|
-
"url": "https://github.com/
|
|
43
|
+
"url": "https://github.com/kaven-co/kaven-cli"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
46
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
47
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
48
|
+
"@semantic-release/github": "^12.0.6",
|
|
49
|
+
"@semantic-release/npm": "^13.1.5",
|
|
50
|
+
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
45
51
|
"@types/fs-extra": "^11.0.4",
|
|
46
52
|
"@types/node": "^20.0.0",
|
|
47
53
|
"@types/tar": "^6.1.13",
|
|
@@ -49,6 +55,8 @@
|
|
|
49
55
|
"@typescript-eslint/parser": "^8.53.1",
|
|
50
56
|
"eslint": "^8.0.0",
|
|
51
57
|
"msw": "^2.12.10",
|
|
58
|
+
"semantic-release": "^25.0.3",
|
|
59
|
+
"tsup": "^8.5.1",
|
|
52
60
|
"typescript": "^5.0.0",
|
|
53
61
|
"vitest": "^1.0.0"
|
|
54
62
|
},
|
|
@@ -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
|
-
});
|
|
@@ -1,40 +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.listCommand = void 0;
|
|
7
|
-
const commander_1 = require("commander");
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const ModuleManager_1 = require("../../core/modules/ModuleManager");
|
|
10
|
-
const logger_1 = require("../../lib/logger");
|
|
11
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
-
exports.listCommand = new commander_1.Command('list')
|
|
13
|
-
.description('List available modules')
|
|
14
|
-
.action(async () => {
|
|
15
|
-
try {
|
|
16
|
-
logger_1.Logger.startSpinner('Loading modules...');
|
|
17
|
-
// By default, Kaven CLI looks for modules in the current project's ./kaven-cli/modules
|
|
18
|
-
// OR internal modules directory. For dev/bootstrap, we use the local 'modules' dir relative to CWD or __dirname.
|
|
19
|
-
// Strategy:
|
|
20
|
-
// 1. Check local repo structure (dev mode): ./modules
|
|
21
|
-
// 2. Check installed structure (production): ../modules
|
|
22
|
-
const modulesPath = path_1.default.resolve('modules');
|
|
23
|
-
const modules = await ModuleManager_1.ModuleManager.listAvailableModules(modulesPath);
|
|
24
|
-
logger_1.Logger.stopSpinner();
|
|
25
|
-
if (modules.length === 0) {
|
|
26
|
-
logger_1.Logger.warn('No modules found in ' + modulesPath);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
logger_1.Logger.info(`Found ${modules.length} modules:`);
|
|
30
|
-
modules.forEach(mod => {
|
|
31
|
-
console.log('');
|
|
32
|
-
console.log(chalk_1.default.bold.cyan(mod.displayName) + ' ' + chalk_1.default.dim(`(${mod.slug})`));
|
|
33
|
-
console.log(chalk_1.default.white(mod.description));
|
|
34
|
-
console.log(chalk_1.default.dim(`Version: ${mod.version}`));
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
logger_1.Logger.error('Failed to list modules', error);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
@@ -1,54 +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.removeCommand = 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 ModuleRemover_1 = require("../../core/modules/ModuleRemover");
|
|
12
|
-
const logger_1 = require("../../lib/logger");
|
|
13
|
-
exports.removeCommand = new commander_1.Command('remove')
|
|
14
|
-
.description('Remove a module')
|
|
15
|
-
.argument('<slug>', 'Module slug to remove')
|
|
16
|
-
.action(async (slug) => {
|
|
17
|
-
try {
|
|
18
|
-
const projectRoot = process.cwd();
|
|
19
|
-
// For removal, we need the manifest to know what to eject.
|
|
20
|
-
// We look for the installed module first?
|
|
21
|
-
// Doc 3: "The engine behaves as if it’s 'playing back' the manifest in reverse."
|
|
22
|
-
// We need the manifest. Where do we get it?
|
|
23
|
-
// Option A: From the installed module directory (if we copied the manifest there).
|
|
24
|
-
// Option B: From the store (but what if version changed?).
|
|
25
|
-
// Best practice: We should have copied module.json to the installed location.
|
|
26
|
-
// Current Installer (Phase 2) does NOT copy module.json to installed location explicitly (it copies `api` folder content).
|
|
27
|
-
// Let's check `ModuleInstaller.ts`:
|
|
28
|
-
// if (manifest.slug) -> copy `api` to `modules/slug`.
|
|
29
|
-
// Does `api` contain `module.json`? No, `module.json` is at root of module source.
|
|
30
|
-
// FIX REQUIRED: We should probably look up the manifest from the *store* (catalog) matching the installed version,
|
|
31
|
-
// OR we should store the manifest upon installation.
|
|
32
|
-
// For MVP (Phase 3), let's assume we can find the manifest in the same Store logic as `add`.
|
|
33
|
-
let modulesSource = process.env.KAVEN_MODULES_PATH;
|
|
34
|
-
if (!modulesSource) {
|
|
35
|
-
if (await fs_extra_1.default.pathExists(path_1.default.resolve('modules'))) {
|
|
36
|
-
modulesSource = path_1.default.resolve('modules');
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
modulesSource = path_1.default.resolve(__dirname, '../../modules');
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const manifestPath = path_1.default.join(modulesSource, slug, 'module.json');
|
|
43
|
-
if (!await fs_extra_1.default.pathExists(manifestPath)) {
|
|
44
|
-
logger_1.Logger.error(`Module manifest not found in store for ${slug}. Cannot safely remove.`);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
const manifest = await ModuleManager_1.ModuleManager.loadManifest(manifestPath);
|
|
48
|
-
await ModuleRemover_1.ModuleRemover.remove(manifest, projectRoot);
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
logger_1.Logger.error('Failed to remove module', error);
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
});
|