kaven-cli 0.4.1-alpha.0 → 0.4.2-alpha.2
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 +181 -207
- package/dist/EnvManager-NMS3NMIE.js +15 -0
- package/dist/MarketplaceClient-YCFH2VU4.js +1 -0
- package/dist/chunk-JHLQ46NG.js +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +248 -304
- package/dist/tier-table-DQMPQSI2.js +6 -0
- package/package.json +26 -11
- package/dist/EnvManager-GQMEZ6NV.js +0 -158
- package/dist/MarketplaceClient-IJGRQRC4.js +0 -7
- package/dist/chunk-3RG5ZIWI.js +0 -10
- package/dist/chunk-GHZX5OAA.js +0 -455
- package/dist/commands/aiox/index.js +0 -20
- package/dist/commands/auth/login.js +0 -122
- package/dist/commands/auth/logout.js +0 -23
- package/dist/commands/auth/whoami.js +0 -36
- package/dist/commands/cache/index.js +0 -43
- package/dist/commands/config/features.js +0 -161
- package/dist/commands/config/index.js +0 -95
- package/dist/commands/index.js +0 -2
- package/dist/commands/init/aiox-bootstrap.js +0 -83
- package/dist/commands/init/index.js +0 -210
- package/dist/commands/init-ci/index.js +0 -153
- package/dist/commands/license/index.js +0 -10
- package/dist/commands/license/status.js +0 -44
- package/dist/commands/license/tier-table.js +0 -46
- package/dist/commands/marketplace/browse.js +0 -186
- package/dist/commands/marketplace/install.js +0 -263
- package/dist/commands/marketplace/list.js +0 -122
- package/dist/commands/module/activate.js +0 -245
- package/dist/commands/module/add.js +0 -69
- package/dist/commands/module/doctor.js +0 -175
- package/dist/commands/module/list.js +0 -51
- package/dist/commands/module/publish.js +0 -258
- package/dist/commands/module/remove.js +0 -58
- package/dist/commands/telemetry/view.js +0 -27
- package/dist/commands/upgrade/check.js +0 -162
- package/dist/commands/upgrade/index.js +0 -185
- package/dist/core/AuthService.js +0 -222
- package/dist/core/CacheManager.js +0 -154
- package/dist/core/ConfigManager.js +0 -166
- package/dist/core/EnvManager.js +0 -196
- package/dist/core/ErrorRecovery.js +0 -192
- package/dist/core/LicenseService.js +0 -83
- package/dist/core/ManifestParser.js +0 -52
- package/dist/core/MarkerService.js +0 -62
- package/dist/core/ModuleDoctor.js +0 -451
- package/dist/core/ModuleInstaller.js +0 -169
- package/dist/core/ProjectInitializer.js +0 -183
- package/dist/core/RegistryResolver.js +0 -95
- package/dist/core/SchemaActivator.js +0 -278
- package/dist/core/ScriptRunner.js +0 -73
- package/dist/core/SignatureVerifier.js +0 -75
- package/dist/core/index.js +0 -2
- package/dist/infrastructure/Container.js +0 -37
- package/dist/infrastructure/MarketplaceClient.js +0 -425
- package/dist/infrastructure/TelemetryBuffer.js +0 -73
- package/dist/infrastructure/TransactionalFileSystem.js +0 -77
- package/dist/infrastructure/errors.js +0 -63
- package/dist/infrastructure/index.js +0 -2
- package/dist/lib/capabilities-catalog.js +0 -73
- package/dist/lib/module-registry.js +0 -47
- package/dist/lib/schema-modifier.js +0 -40
- package/dist/tier-table-LAL6PAVW.js +0 -52
- package/dist/types/auth.js +0 -2
- package/dist/types/manifest.js +0 -45
- package/dist/types/markers.js +0 -10
- package/dist/types/marketplace.js +0 -2
|
@@ -1,154 +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.CacheManager = void 0;
|
|
7
|
-
exports.getCacheManager = getCacheManager;
|
|
8
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
|
-
const os_1 = __importDefault(require("os"));
|
|
11
|
-
class CacheManager {
|
|
12
|
-
cacheDir;
|
|
13
|
-
maxSizeBytes;
|
|
14
|
-
indexPath;
|
|
15
|
-
constructor(cacheDir, maxSizeBytes) {
|
|
16
|
-
this.cacheDir = cacheDir ?? path_1.default.join(os_1.default.homedir(), ".kaven", "cache");
|
|
17
|
-
this.maxSizeBytes = maxSizeBytes ?? 50 * 1024 * 1024; // 50MB
|
|
18
|
-
this.indexPath = path_1.default.join(this.cacheDir, "_index.json");
|
|
19
|
-
}
|
|
20
|
-
async ensureDir() {
|
|
21
|
-
await fs_extra_1.default.ensureDir(this.cacheDir);
|
|
22
|
-
}
|
|
23
|
-
keyToFileName(key) {
|
|
24
|
-
// Sanitize key to valid filename
|
|
25
|
-
return key.replace(/[^a-zA-Z0-9-_:.]/g, "_") + ".json";
|
|
26
|
-
}
|
|
27
|
-
async readIndex() {
|
|
28
|
-
try {
|
|
29
|
-
if (await fs_extra_1.default.pathExists(this.indexPath)) {
|
|
30
|
-
return (await fs_extra_1.default.readJson(this.indexPath));
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
// ignore
|
|
35
|
-
}
|
|
36
|
-
return {};
|
|
37
|
-
}
|
|
38
|
-
async writeIndex(index) {
|
|
39
|
-
await this.ensureDir();
|
|
40
|
-
await fs_extra_1.default.writeJson(this.indexPath, index, { spaces: 2 });
|
|
41
|
-
}
|
|
42
|
-
/** Get fresh data or null if expired. */
|
|
43
|
-
async get(key) {
|
|
44
|
-
const index = await this.readIndex();
|
|
45
|
-
const entry = index[key];
|
|
46
|
-
if (!entry)
|
|
47
|
-
return null;
|
|
48
|
-
if (Date.now() > entry.expiresAt)
|
|
49
|
-
return null;
|
|
50
|
-
try {
|
|
51
|
-
const filePath = path_1.default.join(this.cacheDir, entry.file);
|
|
52
|
-
const data = await fs_extra_1.default.readJson(filePath);
|
|
53
|
-
return data.data;
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
/** Get stale data (ignore TTL expiry) — for offline fallback. */
|
|
60
|
-
async getStale(key) {
|
|
61
|
-
const index = await this.readIndex();
|
|
62
|
-
const entry = index[key];
|
|
63
|
-
if (!entry)
|
|
64
|
-
return null;
|
|
65
|
-
try {
|
|
66
|
-
const filePath = path_1.default.join(this.cacheDir, entry.file);
|
|
67
|
-
const data = await fs_extra_1.default.readJson(filePath);
|
|
68
|
-
return data.data;
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
/** Set data with TTL. */
|
|
75
|
-
async set(key, data, ttlMs) {
|
|
76
|
-
await this.ensureDir();
|
|
77
|
-
const serialized = JSON.stringify(data);
|
|
78
|
-
const size = Buffer.byteLength(serialized, "utf8");
|
|
79
|
-
const now = Date.now();
|
|
80
|
-
const expiresAt = now + ttlMs;
|
|
81
|
-
const fileName = this.keyToFileName(key);
|
|
82
|
-
const filePath = path_1.default.join(this.cacheDir, fileName);
|
|
83
|
-
const entry = {
|
|
84
|
-
data,
|
|
85
|
-
expiresAt,
|
|
86
|
-
size,
|
|
87
|
-
createdAt: now,
|
|
88
|
-
};
|
|
89
|
-
await fs_extra_1.default.writeJson(filePath, entry, { spaces: 2 });
|
|
90
|
-
const index = await this.readIndex();
|
|
91
|
-
index[key] = {
|
|
92
|
-
file: fileName,
|
|
93
|
-
expiresAt,
|
|
94
|
-
size,
|
|
95
|
-
createdAt: now,
|
|
96
|
-
};
|
|
97
|
-
await this.writeIndex(index);
|
|
98
|
-
// Evict if over limit
|
|
99
|
-
await this.evict();
|
|
100
|
-
}
|
|
101
|
-
/** Evict oldest entries if total size exceeds the limit. */
|
|
102
|
-
async evict() {
|
|
103
|
-
const index = await this.readIndex();
|
|
104
|
-
const entries = Object.entries(index);
|
|
105
|
-
let totalSize = entries.reduce((sum, [, e]) => sum + e.size, 0);
|
|
106
|
-
if (totalSize <= this.maxSizeBytes)
|
|
107
|
-
return;
|
|
108
|
-
// Sort by oldest first
|
|
109
|
-
entries.sort(([, a], [, b]) => a.createdAt - b.createdAt);
|
|
110
|
-
const updatedIndex = { ...index };
|
|
111
|
-
for (const [key, entry] of entries) {
|
|
112
|
-
if (totalSize <= this.maxSizeBytes)
|
|
113
|
-
break;
|
|
114
|
-
try {
|
|
115
|
-
const filePath = path_1.default.join(this.cacheDir, entry.file);
|
|
116
|
-
await fs_extra_1.default.remove(filePath);
|
|
117
|
-
delete updatedIndex[key];
|
|
118
|
-
totalSize -= entry.size;
|
|
119
|
-
}
|
|
120
|
-
catch {
|
|
121
|
-
// ignore individual removal errors
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
await this.writeIndex(updatedIndex);
|
|
125
|
-
}
|
|
126
|
-
/** Get cache statistics. */
|
|
127
|
-
async stats() {
|
|
128
|
-
const index = await this.readIndex();
|
|
129
|
-
const entries = Object.values(index);
|
|
130
|
-
if (entries.length === 0) {
|
|
131
|
-
return { totalSize: 0, entries: 0 };
|
|
132
|
-
}
|
|
133
|
-
const totalSize = entries.reduce((sum, e) => sum + e.size, 0);
|
|
134
|
-
const timestamps = entries.map((e) => e.createdAt);
|
|
135
|
-
const oldest = new Date(Math.min(...timestamps));
|
|
136
|
-
const newest = new Date(Math.max(...timestamps));
|
|
137
|
-
return { totalSize, entries: entries.length, oldest, newest };
|
|
138
|
-
}
|
|
139
|
-
/** Clear all cache entries. */
|
|
140
|
-
async clear() {
|
|
141
|
-
if (await fs_extra_1.default.pathExists(this.cacheDir)) {
|
|
142
|
-
await fs_extra_1.default.remove(this.cacheDir);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
exports.CacheManager = CacheManager;
|
|
147
|
-
// Singleton instance
|
|
148
|
-
let _cacheManager = null;
|
|
149
|
-
function getCacheManager() {
|
|
150
|
-
if (!_cacheManager) {
|
|
151
|
-
_cacheManager = new CacheManager();
|
|
152
|
-
}
|
|
153
|
-
return _cacheManager;
|
|
154
|
-
}
|
|
@@ -1,166 +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.configManager = exports.ConfigManager = exports.configSchema = void 0;
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
-
const os_1 = __importDefault(require("os"));
|
|
10
|
-
const zod_1 = require("zod");
|
|
11
|
-
const CONFIG_DIR = path_1.default.join(os_1.default.homedir(), ".kaven");
|
|
12
|
-
const CONFIG_PATH = path_1.default.join(CONFIG_DIR, "config.json");
|
|
13
|
-
exports.configSchema = zod_1.z.object({
|
|
14
|
-
registry: zod_1.z.string().url().default("https://marketplace.kaven.site"),
|
|
15
|
-
telemetry: zod_1.z.boolean().default(true),
|
|
16
|
-
theme: zod_1.z.enum(["light", "dark"]).default("dark"),
|
|
17
|
-
locale: zod_1.z.string().default("en-US"),
|
|
18
|
-
// Custom registry support
|
|
19
|
-
customRegistry: zod_1.z.string().url().optional(),
|
|
20
|
-
// For storing user preferences
|
|
21
|
-
lastLogin: zod_1.z.string().datetime().optional(),
|
|
22
|
-
projectDefaults: zod_1.z
|
|
23
|
-
.object({
|
|
24
|
-
dbUrl: zod_1.z.string().optional(),
|
|
25
|
-
emailProvider: zod_1.z.enum(["postmark", "resend", "ses", "smtp"]).optional(),
|
|
26
|
-
locale: zod_1.z.string().optional(),
|
|
27
|
-
currency: zod_1.z.string().optional(),
|
|
28
|
-
})
|
|
29
|
-
.optional(),
|
|
30
|
-
});
|
|
31
|
-
class ConfigManager {
|
|
32
|
-
config;
|
|
33
|
-
constructor() {
|
|
34
|
-
this.config = {
|
|
35
|
-
registry: "https://marketplace.kaven.site",
|
|
36
|
-
telemetry: true,
|
|
37
|
-
theme: "dark",
|
|
38
|
-
locale: "en-US",
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
async initialize() {
|
|
42
|
-
await fs_extra_1.default.ensureDir(CONFIG_DIR);
|
|
43
|
-
if (await fs_extra_1.default.pathExists(CONFIG_PATH)) {
|
|
44
|
-
try {
|
|
45
|
-
const raw = await fs_extra_1.default.readJson(CONFIG_PATH);
|
|
46
|
-
const parsed = exports.configSchema.safeParse(raw);
|
|
47
|
-
if (parsed.success) {
|
|
48
|
-
this.config = parsed.data;
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
// If validation fails, use defaults
|
|
52
|
-
this.config = {
|
|
53
|
-
registry: "https://marketplace.kaven.site",
|
|
54
|
-
telemetry: true,
|
|
55
|
-
theme: "dark",
|
|
56
|
-
locale: "en-US",
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
// If file is corrupted, start fresh
|
|
62
|
-
this.config = {
|
|
63
|
-
registry: "https://marketplace.kaven.site",
|
|
64
|
-
telemetry: true,
|
|
65
|
-
theme: "dark",
|
|
66
|
-
locale: "en-US",
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
// Initialize with defaults
|
|
72
|
-
this.config = {
|
|
73
|
-
registry: "https://marketplace.kaven.site",
|
|
74
|
-
telemetry: true,
|
|
75
|
-
theme: "dark",
|
|
76
|
-
locale: "en-US",
|
|
77
|
-
};
|
|
78
|
-
await this.persist();
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Get config value with env var override support
|
|
83
|
-
* Priority: ENV VAR > config file > CLI arg > default
|
|
84
|
-
*/
|
|
85
|
-
get(key, envVarName) {
|
|
86
|
-
// Check environment variable override
|
|
87
|
-
if (envVarName) {
|
|
88
|
-
const envValue = process.env[envVarName];
|
|
89
|
-
if (envValue !== undefined) {
|
|
90
|
-
return envValue;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// Check config file
|
|
94
|
-
const value = this.config[key];
|
|
95
|
-
if (value !== undefined) {
|
|
96
|
-
return value;
|
|
97
|
-
}
|
|
98
|
-
// Return default from schema
|
|
99
|
-
const defaults = exports.configSchema.parse({});
|
|
100
|
-
return defaults[key];
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Set config value and persist to disk
|
|
104
|
-
*/
|
|
105
|
-
async set(key, value) {
|
|
106
|
-
const updateObj = { [key]: value };
|
|
107
|
-
const updated = exports.configSchema.safeParse({ ...this.config, ...updateObj });
|
|
108
|
-
if (!updated.success) {
|
|
109
|
-
const errors = updated.error.issues
|
|
110
|
-
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
|
111
|
-
.join(", ");
|
|
112
|
-
throw new Error(`Invalid config: ${errors}`);
|
|
113
|
-
}
|
|
114
|
-
this.config = updated.data;
|
|
115
|
-
await this.persist();
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Get all config
|
|
119
|
-
*/
|
|
120
|
-
getAll() {
|
|
121
|
-
return { ...this.config };
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Reset config to defaults
|
|
125
|
-
*/
|
|
126
|
-
async reset() {
|
|
127
|
-
this.config = {
|
|
128
|
-
registry: "https://marketplace.kaven.site",
|
|
129
|
-
telemetry: true,
|
|
130
|
-
theme: "dark",
|
|
131
|
-
locale: "en-US",
|
|
132
|
-
};
|
|
133
|
-
await this.persist();
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Persist config to disk
|
|
137
|
-
*/
|
|
138
|
-
async persist() {
|
|
139
|
-
await fs_extra_1.default.ensureDir(CONFIG_DIR);
|
|
140
|
-
await fs_extra_1.default.writeJson(CONFIG_PATH, this.config, { spaces: 2 });
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Get registry URL (custom or default)
|
|
144
|
-
*/
|
|
145
|
-
getRegistry() {
|
|
146
|
-
return (this.config.customRegistry || this.config.registry || "https://marketplace.kaven.site");
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Check if telemetry is enabled (can be overridden by env var)
|
|
150
|
-
*/
|
|
151
|
-
isTelemetryEnabled() {
|
|
152
|
-
if (process.env.KAVEN_TELEMETRY === "0") {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
return this.config.telemetry !== false;
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Get config directory path
|
|
159
|
-
*/
|
|
160
|
-
getConfigDir() {
|
|
161
|
-
return CONFIG_DIR;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
exports.ConfigManager = ConfigManager;
|
|
165
|
-
// Export singleton instance
|
|
166
|
-
exports.configManager = new ConfigManager();
|
package/dist/core/EnvManager.js
DELETED
|
@@ -1,196 +0,0 @@
|
|
|
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.EnvManager = void 0;
|
|
40
|
-
const fs = __importStar(require("fs"));
|
|
41
|
-
const path = __importStar(require("path"));
|
|
42
|
-
const readline = __importStar(require("readline"));
|
|
43
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
44
|
-
class EnvManager {
|
|
45
|
-
async injectEnvVars(moduleSlug, envVars, options) {
|
|
46
|
-
if (options.skipEnv || !envVars || envVars.length === 0) {
|
|
47
|
-
return { added: 0, skipped: 0 };
|
|
48
|
-
}
|
|
49
|
-
const envFilePath = path.join(options.projectDir, options.envFile ?? '.env');
|
|
50
|
-
const existingContent = this.readEnvFile(envFilePath);
|
|
51
|
-
const existingVars = this.parseEnvFile(existingContent);
|
|
52
|
-
const newVars = [];
|
|
53
|
-
let skipped = 0;
|
|
54
|
-
console.log(chalk_1.default.bold(`\n Environment variables for '${moduleSlug}':\n`));
|
|
55
|
-
for (const envDef of envVars) {
|
|
56
|
-
if (existingVars.has(envDef.name)) {
|
|
57
|
-
console.log(chalk_1.default.dim(` ${envDef.name} — already set, skipping`));
|
|
58
|
-
skipped++;
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
let value;
|
|
62
|
-
if (envDef.sensitive) {
|
|
63
|
-
value = await this.promptPassword(` ${envDef.name} (${envDef.description})${envDef.default ? ' [****]' : ''}: `);
|
|
64
|
-
if (!value && envDef.default)
|
|
65
|
-
value = envDef.default;
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
const defaultHint = envDef.default ? ` [${envDef.default}]` : '';
|
|
69
|
-
value = await this.promptInput(` ${envDef.name} (${envDef.description})${defaultHint}: `, envDef.default);
|
|
70
|
-
}
|
|
71
|
-
if (envDef.required && !value) {
|
|
72
|
-
console.log(chalk_1.default.yellow(` ${envDef.name} is required.`));
|
|
73
|
-
value = envDef.sensitive
|
|
74
|
-
? await this.promptPassword(` ${envDef.name}: `)
|
|
75
|
-
: await this.promptInput(` ${envDef.name}: `);
|
|
76
|
-
if (!value) {
|
|
77
|
-
console.log(chalk_1.default.yellow(` Skipping ${envDef.name} — set it manually in .env`));
|
|
78
|
-
skipped++;
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
newVars.push({ name: envDef.name, value });
|
|
83
|
-
}
|
|
84
|
-
if (newVars.length === 0) {
|
|
85
|
-
console.log(chalk_1.default.dim(' No new environment variables to add.'));
|
|
86
|
-
return { added: 0, skipped };
|
|
87
|
-
}
|
|
88
|
-
const markerBlock = this.buildMarkerBlock(moduleSlug, newVars);
|
|
89
|
-
this.appendToEnvFile(envFilePath, existingContent, markerBlock);
|
|
90
|
-
console.log(chalk_1.default.green(`\n Added ${newVars.length} environment variable(s) to ${options.envFile ?? '.env'}`));
|
|
91
|
-
return { added: newVars.length, skipped };
|
|
92
|
-
}
|
|
93
|
-
removeEnvVars(moduleSlug, options) {
|
|
94
|
-
const envFiles = ['.env', '.env.local', '.env.development', '.env.production'];
|
|
95
|
-
if (options.envFile)
|
|
96
|
-
envFiles.unshift(options.envFile);
|
|
97
|
-
let totalRemoved = 0;
|
|
98
|
-
for (const envFile of envFiles) {
|
|
99
|
-
const envFilePath = path.join(options.projectDir, envFile);
|
|
100
|
-
if (!fs.existsSync(envFilePath))
|
|
101
|
-
continue;
|
|
102
|
-
const content = fs.readFileSync(envFilePath, 'utf-8');
|
|
103
|
-
const beginMarker = `# [KAVEN_MODULE:${moduleSlug} BEGIN]`;
|
|
104
|
-
const endMarker = `# [KAVEN_MODULE:${moduleSlug} END]`;
|
|
105
|
-
const beginIdx = content.indexOf(beginMarker);
|
|
106
|
-
const endIdx = content.indexOf(endMarker);
|
|
107
|
-
if (beginIdx === -1 || endIdx === -1)
|
|
108
|
-
continue;
|
|
109
|
-
const block = content.substring(beginIdx, endIdx + endMarker.length);
|
|
110
|
-
const varCount = block.split('\n').filter(l => /^[A-Z_]+=/.test(l)).length;
|
|
111
|
-
const before = content.substring(0, beginIdx).replace(/\n+$/, '\n');
|
|
112
|
-
const after = content.substring(endIdx + endMarker.length + 1);
|
|
113
|
-
fs.writeFileSync(envFilePath, before + after);
|
|
114
|
-
totalRemoved += varCount;
|
|
115
|
-
if (varCount > 0) {
|
|
116
|
-
console.log(chalk_1.default.dim(` Removed ${varCount} env var(s) from ${envFile}`));
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return totalRemoved;
|
|
120
|
-
}
|
|
121
|
-
readEnvFile(filePath) {
|
|
122
|
-
try {
|
|
123
|
-
return fs.readFileSync(filePath, 'utf-8');
|
|
124
|
-
}
|
|
125
|
-
catch {
|
|
126
|
-
return '';
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
parseEnvFile(content) {
|
|
130
|
-
const vars = new Map();
|
|
131
|
-
for (const line of content.split('\n')) {
|
|
132
|
-
const match = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
|
|
133
|
-
if (match)
|
|
134
|
-
vars.set(match[1], match[2]);
|
|
135
|
-
}
|
|
136
|
-
return vars;
|
|
137
|
-
}
|
|
138
|
-
buildMarkerBlock(moduleSlug, vars) {
|
|
139
|
-
return [
|
|
140
|
-
`# [KAVEN_MODULE:${moduleSlug} BEGIN]`,
|
|
141
|
-
...vars.map(v => `${v.name}=${v.value}`),
|
|
142
|
-
`# [KAVEN_MODULE:${moduleSlug} END]`,
|
|
143
|
-
].join('\n');
|
|
144
|
-
}
|
|
145
|
-
appendToEnvFile(filePath, existingContent, block) {
|
|
146
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
147
|
-
const separator = existingContent.endsWith('\n') || existingContent === '' ? '\n' : '\n\n';
|
|
148
|
-
fs.writeFileSync(filePath, existingContent + separator + block + '\n');
|
|
149
|
-
}
|
|
150
|
-
promptInput(message, defaultValue) {
|
|
151
|
-
return new Promise(resolve => {
|
|
152
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
153
|
-
rl.question(message, answer => {
|
|
154
|
-
rl.close();
|
|
155
|
-
resolve(answer || defaultValue || '');
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
promptPassword(message) {
|
|
160
|
-
return new Promise(resolve => {
|
|
161
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
162
|
-
// Hide input by listening to keypress but readline doesn't natively support this
|
|
163
|
-
// For simplicity, use standard prompt (production would use a proper password lib)
|
|
164
|
-
process.stdout.write(message);
|
|
165
|
-
process.stdin.setRawMode?.(true);
|
|
166
|
-
process.stdin.resume();
|
|
167
|
-
let password = '';
|
|
168
|
-
const handler = (key) => {
|
|
169
|
-
const char = key.toString();
|
|
170
|
-
if (char === '\r' || char === '\n') {
|
|
171
|
-
process.stdin.setRawMode?.(false);
|
|
172
|
-
process.stdin.pause();
|
|
173
|
-
process.stdin.removeListener('data', handler);
|
|
174
|
-
process.stdout.write('\n');
|
|
175
|
-
rl.close();
|
|
176
|
-
resolve(password);
|
|
177
|
-
}
|
|
178
|
-
else if (char === '\u0003') {
|
|
179
|
-
process.exit();
|
|
180
|
-
}
|
|
181
|
-
else if (char === '\u007f') {
|
|
182
|
-
password = password.slice(0, -1);
|
|
183
|
-
process.stdout.clearLine(0);
|
|
184
|
-
process.stdout.cursorTo(0);
|
|
185
|
-
process.stdout.write(message + '*'.repeat(password.length));
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
password += char;
|
|
189
|
-
process.stdout.write('*');
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
process.stdin.on('data', handler);
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
exports.EnvManager = EnvManager;
|