@invect/cli 0.0.1

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/dist/index.js ADDED
@@ -0,0 +1,581 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ generateCommand
4
+ } from "./chunk-T4KEEHFJ.js";
5
+ import "./chunk-K4RRNATQ.js";
6
+ import {
7
+ migrateCommand
8
+ } from "./chunk-DGBTXQND.js";
9
+ import {
10
+ findConfigPath,
11
+ loadConfig
12
+ } from "./chunk-Q6JKV7VX.js";
13
+
14
+ // src/index.ts
15
+ import { Command as Command4 } from "commander";
16
+
17
+ // src/commands/init.ts
18
+ import { Command } from "commander";
19
+ import path from "path";
20
+ import fs from "fs";
21
+ import { execSync } from "child_process";
22
+ import pc from "picocolors";
23
+ import prompts from "prompts";
24
+ var FRAMEWORKS = [
25
+ {
26
+ name: "Express",
27
+ id: "express",
28
+ dependency: "express",
29
+ adapterPackage: "@invect/express",
30
+ configPaths: null
31
+ },
32
+ {
33
+ name: "NestJS",
34
+ id: "nestjs",
35
+ dependency: "@nestjs/core",
36
+ adapterPackage: "@invect/nestjs",
37
+ configPaths: ["nest-cli.json"]
38
+ },
39
+ {
40
+ name: "Next.js",
41
+ id: "nextjs",
42
+ dependency: "next",
43
+ adapterPackage: "@invect/nextjs",
44
+ configPaths: ["next.config.js", "next.config.ts", "next.config.mjs"]
45
+ },
46
+ {
47
+ name: "Other / Custom",
48
+ id: "other",
49
+ dependency: null,
50
+ adapterPackage: null,
51
+ configPaths: null
52
+ }
53
+ ];
54
+ var DATABASES = [
55
+ { name: "SQLite (better-sqlite3)", id: "sqlite", dependency: "better-sqlite3" },
56
+ { name: "PostgreSQL", id: "postgresql", dependency: "postgres" },
57
+ { name: "MySQL", id: "mysql", dependency: "mysql2" }
58
+ ];
59
+ var initCommand = new Command("init").description("Initialize Invect in your project").option("--framework <framework>", "Framework to use (express, nestjs, nextjs)").option("--database <database>", "Database to use (sqlite, postgresql, mysql)").option(
60
+ "--package-manager <pm>",
61
+ "Package manager (npm, pnpm, yarn, bun)"
62
+ ).action(async (options) => {
63
+ console.log(
64
+ "\n" + [
65
+ ` ${pc.bold("Invect CLI")} ${pc.dim("(v0.1.0)")}`,
66
+ ` ${pc.gray("Let's set up Invect in your project.")}`
67
+ ].join("\n") + "\n"
68
+ );
69
+ const pkgPath = path.join(process.cwd(), "package.json");
70
+ if (!fs.existsSync(pkgPath)) {
71
+ console.error(
72
+ pc.red("\u2717 No package.json found in the current directory.\n") + pc.dim(" Please initialize a project first (e.g., npm init).\n")
73
+ );
74
+ process.exit(1);
75
+ }
76
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
77
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
78
+ let stepNum = 0;
79
+ const step = (text) => {
80
+ stepNum++;
81
+ console.log(pc.white(`
82
+ ${stepNum}. ${text}`));
83
+ };
84
+ const pm = options.packageManager || detectPackageManager();
85
+ console.log(pc.dim(` Package manager: ${pm}`));
86
+ step("Select Framework");
87
+ let framework;
88
+ if (options.framework) {
89
+ framework = FRAMEWORKS.find((f) => f.id === options.framework) || FRAMEWORKS[FRAMEWORKS.length - 1];
90
+ } else {
91
+ const detected = FRAMEWORKS.find((f) => f.dependency && f.dependency in allDeps);
92
+ if (detected) {
93
+ console.log(pc.dim(` Detected: ${detected.name}`));
94
+ const { useDetected } = await prompts({
95
+ type: "confirm",
96
+ name: "useDetected",
97
+ message: `Use detected framework ${pc.cyan(detected.name)}?`,
98
+ initial: true
99
+ });
100
+ framework = useDetected ? detected : await askFramework();
101
+ } else {
102
+ framework = await askFramework();
103
+ }
104
+ }
105
+ console.log(pc.dim(` Framework: ${framework.name}`));
106
+ step("Select Database");
107
+ let database;
108
+ if (options.database) {
109
+ database = DATABASES.find((d) => d.id === options.database) || DATABASES[0];
110
+ } else {
111
+ const detected = DATABASES.find((d) => d.dependency in allDeps);
112
+ if (detected) {
113
+ console.log(pc.dim(` Detected: ${detected.name}`));
114
+ database = detected;
115
+ } else {
116
+ database = await askDatabase();
117
+ }
118
+ }
119
+ console.log(pc.dim(` Database: ${database.name}`));
120
+ step("Install Dependencies");
121
+ const depsToInstall = ["@invect/core", "drizzle-orm"];
122
+ const devDepsToInstall = ["drizzle-kit", "@invect/cli"];
123
+ if (!(database.dependency in allDeps)) {
124
+ depsToInstall.push(database.dependency);
125
+ }
126
+ if (framework.adapterPackage && !(framework.adapterPackage in allDeps)) {
127
+ depsToInstall.push(framework.adapterPackage);
128
+ }
129
+ if (framework.id !== "other") {
130
+ if (!("@invect/frontend" in allDeps)) {
131
+ depsToInstall.push("@invect/frontend");
132
+ }
133
+ }
134
+ console.log(pc.dim(` Dependencies: ${depsToInstall.join(", ")}`));
135
+ if (devDepsToInstall.length > 0) {
136
+ console.log(pc.dim(` Dev dependencies: ${devDepsToInstall.join(", ")}`));
137
+ }
138
+ const { shouldInstall } = await prompts({
139
+ type: "confirm",
140
+ name: "shouldInstall",
141
+ message: `Install packages using ${pc.bold(pm)}?`,
142
+ initial: true
143
+ });
144
+ if (shouldInstall) {
145
+ try {
146
+ const installCmd = getInstallCommand(pm, depsToInstall, false);
147
+ console.log(pc.dim(` $ ${installCmd}`));
148
+ execSync(installCmd, { stdio: "inherit", cwd: process.cwd() });
149
+ if (devDepsToInstall.length > 0) {
150
+ const devCmd = getInstallCommand(pm, devDepsToInstall, true);
151
+ console.log(pc.dim(` $ ${devCmd}`));
152
+ execSync(devCmd, { stdio: "inherit", cwd: process.cwd() });
153
+ }
154
+ } catch {
155
+ console.error(pc.yellow(" \u26A0 Package installation failed. You can install manually later."));
156
+ }
157
+ }
158
+ step("Create Configuration");
159
+ const configCode = generateConfigFile(framework, database);
160
+ const configDir = fs.existsSync(path.join(process.cwd(), "src")) ? "src" : ".";
161
+ const configPath = path.join(process.cwd(), configDir, "invect.config.ts");
162
+ if (fs.existsSync(configPath)) {
163
+ console.log(pc.yellow(` \u26A0 ${path.relative(process.cwd(), configPath)} already exists \u2014 skipping`));
164
+ } else {
165
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
166
+ fs.writeFileSync(configPath, configCode, "utf-8");
167
+ console.log(pc.green(` \u2713 Created ${path.relative(process.cwd(), configPath)}`));
168
+ }
169
+ step("Generate Encryption Key");
170
+ const crypto2 = await import("crypto");
171
+ const encryptionKey = crypto2.randomBytes(32).toString("base64");
172
+ const envPath = path.join(process.cwd(), ".env");
173
+ const envLine = `INVECT_ENCRYPTION_KEY="${encryptionKey}"`;
174
+ if (fs.existsSync(envPath)) {
175
+ const envContent = fs.readFileSync(envPath, "utf-8");
176
+ if (!envContent.includes("INVECT_ENCRYPTION_KEY")) {
177
+ fs.appendFileSync(envPath, `
178
+ ${envLine}
179
+ `);
180
+ console.log(pc.green(` \u2713 Added INVECT_ENCRYPTION_KEY to .env`));
181
+ } else {
182
+ console.log(pc.dim(" \u2139 INVECT_ENCRYPTION_KEY already set in .env"));
183
+ }
184
+ } else {
185
+ fs.writeFileSync(envPath, `${envLine}
186
+ `);
187
+ console.log(pc.green(` \u2713 Created .env with INVECT_ENCRYPTION_KEY`));
188
+ }
189
+ step("Generate Database Schema");
190
+ const { shouldGenerate } = await prompts({
191
+ type: "confirm",
192
+ name: "shouldGenerate",
193
+ message: "Generate database schema files now?",
194
+ initial: true
195
+ });
196
+ if (shouldGenerate) {
197
+ try {
198
+ const { generateAction } = await import("./generate-JDAYY3OL.js");
199
+ const schemaDir = fs.existsSync(path.join(process.cwd(), "src")) ? "./src/database" : "./database";
200
+ await generateAction({
201
+ config: configPath,
202
+ output: schemaDir,
203
+ yes: true
204
+ });
205
+ } catch (error) {
206
+ console.error(
207
+ pc.yellow(" \u26A0 Schema generation failed. You can run it manually later:") + "\n" + pc.dim(` npx invect generate
208
+ `)
209
+ );
210
+ }
211
+ } else {
212
+ console.log(
213
+ pc.dim(
214
+ " Skipped. Run " + pc.cyan("npx invect generate") + " when ready."
215
+ )
216
+ );
217
+ }
218
+ if (database.id === "sqlite" && shouldGenerate) {
219
+ const { shouldMigrate } = await prompts({
220
+ type: "confirm",
221
+ name: "shouldMigrate",
222
+ message: "Run database migration now? (creates the SQLite database)",
223
+ initial: true
224
+ });
225
+ if (shouldMigrate) {
226
+ try {
227
+ const { migrateAction } = await import("./migrate-JMKLRLSJ.js");
228
+ await migrateAction({
229
+ config: configPath,
230
+ yes: true,
231
+ push: true
232
+ // Use push for quick dev setup
233
+ });
234
+ } catch {
235
+ console.error(
236
+ pc.yellow(" \u26A0 Migration failed. You can run it manually:") + "\n" + pc.dim(" npx invect migrate\n")
237
+ );
238
+ }
239
+ }
240
+ }
241
+ console.log(pc.bold(pc.green("\n\u2713 Invect initialized successfully!\n")));
242
+ console.log(pc.dim(" Next steps:"));
243
+ const nextSteps = [];
244
+ let n = 1;
245
+ nextSteps.push(` ${n++}. Review ${pc.cyan(path.relative(process.cwd(), configPath))}`);
246
+ if (database.id !== "sqlite") {
247
+ nextSteps.push(
248
+ ` ${n++}. Set ${pc.cyan("DATABASE_URL")} in your .env file`
249
+ );
250
+ }
251
+ if (!shouldGenerate) {
252
+ nextSteps.push(` ${n++}. Run ${pc.cyan("npx invect generate")} to create schema files`);
253
+ }
254
+ nextSteps.push(` ${n++}. Run ${pc.cyan("npx invect migrate")} to apply the schema`);
255
+ if (framework.id === "express") {
256
+ nextSteps.push(` ${n++}. Mount the router: ${pc.cyan("app.use('/invect', createInvectRouter(config))")}`);
257
+ } else if (framework.id === "nextjs") {
258
+ nextSteps.push(` ${n++}. Create a catch-all route: ${pc.cyan("app/api/invect/[...invect]/route.ts")}`);
259
+ } else if (framework.id === "nestjs") {
260
+ nextSteps.push(` ${n++}. Import ${pc.cyan("InvectModule.forRoot(config)")} in your AppModule`);
261
+ }
262
+ for (const s of nextSteps) {
263
+ console.log(s);
264
+ }
265
+ console.log("");
266
+ });
267
+ async function askFramework() {
268
+ const { framework } = await prompts({
269
+ type: "select",
270
+ name: "framework",
271
+ message: "Which framework are you using?",
272
+ choices: FRAMEWORKS.map((f) => ({
273
+ title: f.name,
274
+ value: f.id
275
+ }))
276
+ });
277
+ if (!framework) {
278
+ console.log(pc.dim("\n Cancelled.\n"));
279
+ process.exit(0);
280
+ }
281
+ return FRAMEWORKS.find((f) => f.id === framework);
282
+ }
283
+ async function askDatabase() {
284
+ const { database } = await prompts({
285
+ type: "select",
286
+ name: "database",
287
+ message: "Which database will you use?",
288
+ choices: DATABASES.map((d) => ({
289
+ title: d.name,
290
+ value: d.id
291
+ }))
292
+ });
293
+ if (!database) {
294
+ console.log(pc.dim("\n Cancelled.\n"));
295
+ process.exit(0);
296
+ }
297
+ return DATABASES.find((d) => d.id === database);
298
+ }
299
+ function generateConfigFile(framework, database) {
300
+ const dbConfigMap = {
301
+ sqlite: ` baseDatabaseConfig: {
302
+ type: 'sqlite',
303
+ connectionString: 'file:./dev.db',
304
+ },`,
305
+ postgresql: ` baseDatabaseConfig: {
306
+ type: 'postgresql',
307
+ connectionString: process.env.DATABASE_URL || 'postgresql://localhost:5432/invect',
308
+ },`,
309
+ mysql: ` baseDatabaseConfig: {
310
+ type: 'mysql',
311
+ connectionString: process.env.DATABASE_URL || 'mysql://root@localhost:3306/invect',
312
+ },`
313
+ };
314
+ const adapterImport = framework.adapterPackage ? `// import { ... } from '${framework.adapterPackage}';
315
+ ` : "";
316
+ return `/**
317
+ * Invect Configuration
318
+ *
319
+ * This file is read by the Invect CLI for schema generation
320
+ * and by your application at runtime.
321
+ *
322
+ * Docs: https://invect.dev/docs
323
+ */
324
+
325
+ ${adapterImport}export default {
326
+ ${dbConfigMap[database.id]}
327
+
328
+ // Add plugins here
329
+ // plugins: [],
330
+
331
+ // AI provider configuration
332
+ // ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
333
+ // OPENAI_API_KEY: process.env.OPENAI_API_KEY,
334
+
335
+ // Encryption key for credential storage (auto-generated)
336
+ // INVECT_ENCRYPTION_KEY: process.env.INVECT_ENCRYPTION_KEY,
337
+ };
338
+ `;
339
+ }
340
+ function detectPackageManager() {
341
+ const cwd = process.cwd();
342
+ if (fs.existsSync(path.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
343
+ if (fs.existsSync(path.join(cwd, "bun.lockb")) || fs.existsSync(path.join(cwd, "bun.lock"))) return "bun";
344
+ if (fs.existsSync(path.join(cwd, "yarn.lock"))) return "yarn";
345
+ return "npm";
346
+ }
347
+ function getInstallCommand(pm, packages, isDev) {
348
+ const flags = {
349
+ npm: isDev ? "--save-dev" : "",
350
+ pnpm: isDev ? "--save-dev" : "",
351
+ yarn: isDev ? "--dev" : "",
352
+ bun: isDev ? "--dev" : ""
353
+ };
354
+ const flag = flags[pm] || "";
355
+ const cmd = pm === "npm" ? "npm install" : `${pm} add`;
356
+ return `${cmd} ${flag} ${packages.join(" ")}`.replace(/\s+/g, " ").trim();
357
+ }
358
+
359
+ // src/commands/info.ts
360
+ import { Command as Command2 } from "commander";
361
+ import path2 from "path";
362
+ import fs2 from "fs";
363
+ import os from "os";
364
+ import pc2 from "picocolors";
365
+ var infoCommand = new Command2("info").description("Display diagnostic information about your Invect setup").option("--config <path>", "Path to your Invect config file").option("--json", "Output as JSON").action(async (options) => {
366
+ const info = {};
367
+ info.system = {
368
+ os: `${os.platform()} ${os.release()} (${os.arch()})`,
369
+ cpu: os.cpus()[0]?.model || "unknown",
370
+ memory: `${Math.round(os.totalmem() / 1024 / 1024 / 1024)}GB`,
371
+ nodeVersion: process.version
372
+ };
373
+ info.packageManager = detectPackageManager2();
374
+ info.invect = {
375
+ cliVersion: "0.1.0",
376
+ coreVersion: await detectPackageVersion("@invect/core")
377
+ };
378
+ info.frameworks = detectFrameworks();
379
+ info.databases = detectDatabaseTools();
380
+ const configPath = findConfigPath(options.config);
381
+ if (configPath) {
382
+ info.configPath = path2.relative(process.cwd(), configPath);
383
+ try {
384
+ const config = await loadConfig(configPath);
385
+ info.plugins = config.plugins.map((p) => ({
386
+ id: p.id,
387
+ name: p.name || p.id,
388
+ hasSchema: !!p.schema,
389
+ schemaTablesCount: p.schema ? Object.keys(p.schema).length : 0
390
+ }));
391
+ const safeConfig = redactSensitive(config.raw);
392
+ info.config = safeConfig;
393
+ } catch (error) {
394
+ info.configError = error instanceof Error ? error.message : String(error);
395
+ }
396
+ } else {
397
+ info.configPath = null;
398
+ info.configError = "No config file found";
399
+ }
400
+ if (options.json) {
401
+ console.log(JSON.stringify(info, null, 2));
402
+ } else {
403
+ printInfo(info);
404
+ }
405
+ });
406
+ function printInfo(info) {
407
+ console.log(pc2.bold("\n\u{1F4CB} Invect Info\n"));
408
+ const sys = info.system;
409
+ console.log(pc2.bold(" System:"));
410
+ console.log(pc2.dim(` OS: ${sys.os}`));
411
+ console.log(pc2.dim(` CPU: ${sys.cpu}`));
412
+ console.log(pc2.dim(` Memory: ${sys.memory}`));
413
+ console.log(pc2.dim(` Node: ${sys.nodeVersion}`));
414
+ console.log("");
415
+ const pm = info.packageManager;
416
+ console.log(pc2.bold(" Package Manager:"));
417
+ console.log(pc2.dim(` ${pm}`));
418
+ console.log("");
419
+ const imp = info.invect;
420
+ console.log(pc2.bold(" Invect:"));
421
+ console.log(pc2.dim(` CLI: ${imp.cliVersion}`));
422
+ console.log(pc2.dim(` Core: ${imp.coreVersion}`));
423
+ console.log("");
424
+ const fw = info.frameworks;
425
+ console.log(pc2.bold(" Frameworks:"));
426
+ if (fw.length > 0) {
427
+ for (const f of fw) {
428
+ console.log(pc2.dim(` \u2713 ${f}`));
429
+ }
430
+ } else {
431
+ console.log(pc2.dim(" (none detected)"));
432
+ }
433
+ console.log("");
434
+ const db = info.databases;
435
+ console.log(pc2.bold(" Database Tools:"));
436
+ if (db.length > 0) {
437
+ for (const d of db) {
438
+ console.log(pc2.dim(` \u2713 ${d}`));
439
+ }
440
+ } else {
441
+ console.log(pc2.dim(" (none detected)"));
442
+ }
443
+ console.log("");
444
+ console.log(pc2.bold(" Config:"));
445
+ if (info.configPath) {
446
+ console.log(pc2.dim(` File: ${info.configPath}`));
447
+ } else {
448
+ console.log(pc2.yellow(` \u26A0 ${info.configError || "Not found"}`));
449
+ }
450
+ const plugins = info.plugins;
451
+ if (plugins && plugins.length > 0) {
452
+ console.log("");
453
+ console.log(pc2.bold(" Plugins:"));
454
+ for (const p of plugins) {
455
+ const schemaInfo = p.hasSchema ? ` (${p.schemaTablesCount} table(s))` : "";
456
+ console.log(pc2.dim(` \u2713 ${p.name}${schemaInfo}`));
457
+ }
458
+ }
459
+ console.log("");
460
+ }
461
+ function detectPackageManager2() {
462
+ const cwd = process.cwd();
463
+ if (fs2.existsSync(path2.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
464
+ if (fs2.existsSync(path2.join(cwd, "bun.lockb")) || fs2.existsSync(path2.join(cwd, "bun.lock"))) return "bun";
465
+ if (fs2.existsSync(path2.join(cwd, "yarn.lock"))) return "yarn";
466
+ if (fs2.existsSync(path2.join(cwd, "package-lock.json"))) return "npm";
467
+ return "unknown";
468
+ }
469
+ async function detectPackageVersion(pkg) {
470
+ try {
471
+ const pkgJsonPath = path2.join(process.cwd(), "node_modules", pkg, "package.json");
472
+ if (fs2.existsSync(pkgJsonPath)) {
473
+ const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
474
+ return pkgJson.version || "unknown";
475
+ }
476
+ } catch {
477
+ }
478
+ return "not installed";
479
+ }
480
+ function detectFrameworks() {
481
+ const frameworks = [];
482
+ const pkgPath = path2.join(process.cwd(), "package.json");
483
+ if (!fs2.existsSync(pkgPath)) return frameworks;
484
+ try {
485
+ const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
486
+ const allDeps = {
487
+ ...pkg.dependencies,
488
+ ...pkg.devDependencies
489
+ };
490
+ if (allDeps["next"]) frameworks.push(`Next.js (${allDeps["next"]})`);
491
+ if (allDeps["@nestjs/core"]) frameworks.push(`NestJS (${allDeps["@nestjs/core"]})`);
492
+ if (allDeps["express"]) frameworks.push(`Express (${allDeps["express"]})`);
493
+ if (allDeps["react"]) frameworks.push(`React (${allDeps["react"]})`);
494
+ if (allDeps["vue"]) frameworks.push(`Vue (${allDeps["vue"]})`);
495
+ if (allDeps["svelte"]) frameworks.push(`Svelte (${allDeps["svelte"]})`);
496
+ if (allDeps["hono"]) frameworks.push(`Hono (${allDeps["hono"]})`);
497
+ if (allDeps["fastify"]) frameworks.push(`Fastify (${allDeps["fastify"]})`);
498
+ } catch {
499
+ }
500
+ return frameworks;
501
+ }
502
+ function detectDatabaseTools() {
503
+ const tools = [];
504
+ const pkgPath = path2.join(process.cwd(), "package.json");
505
+ if (!fs2.existsSync(pkgPath)) return tools;
506
+ try {
507
+ const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
508
+ const allDeps = {
509
+ ...pkg.dependencies,
510
+ ...pkg.devDependencies
511
+ };
512
+ if (allDeps["drizzle-orm"]) tools.push(`Drizzle ORM (${allDeps["drizzle-orm"]})`);
513
+ if (allDeps["drizzle-kit"]) tools.push(`Drizzle Kit (${allDeps["drizzle-kit"]})`);
514
+ if (allDeps["prisma"] || allDeps["@prisma/client"]) tools.push("Prisma");
515
+ if (allDeps["better-sqlite3"] || allDeps["@libsql/client"]) tools.push("SQLite");
516
+ if (allDeps["pg"] || allDeps["postgres"]) tools.push("PostgreSQL");
517
+ if (allDeps["mysql2"]) tools.push("MySQL");
518
+ } catch {
519
+ }
520
+ return tools;
521
+ }
522
+ function redactSensitive(config) {
523
+ const sensitiveKeys = [
524
+ "apiKey",
525
+ "api_key",
526
+ "secret",
527
+ "password",
528
+ "token",
529
+ "connectionString",
530
+ "databaseUrl",
531
+ "ANTHROPIC_API_KEY",
532
+ "OPENAI_API_KEY",
533
+ "encryptionKey"
534
+ ];
535
+ const redacted = { ...config };
536
+ function redactDeep(obj) {
537
+ const result = {};
538
+ for (const [key, value] of Object.entries(obj)) {
539
+ if (sensitiveKeys.some((sk) => key.toLowerCase().includes(sk.toLowerCase()))) {
540
+ result[key] = "[REDACTED]";
541
+ } else if (value && typeof value === "object" && !Array.isArray(value)) {
542
+ result[key] = redactDeep(value);
543
+ } else {
544
+ result[key] = value;
545
+ }
546
+ }
547
+ return result;
548
+ }
549
+ return redactDeep(redacted);
550
+ }
551
+
552
+ // src/commands/secret.ts
553
+ import { Command as Command3 } from "commander";
554
+ import crypto from "crypto";
555
+ import pc3 from "picocolors";
556
+ var secretCommand = new Command3("secret").description("Generate a secure encryption key for INVECT_ENCRYPTION_KEY").action(() => {
557
+ const key = crypto.randomBytes(32).toString("base64");
558
+ console.log(pc3.bold("\n\u{1F511} Generated Encryption Key\n"));
559
+ console.log(` ${pc3.green(key)}`);
560
+ console.log("");
561
+ console.log(pc3.dim(" Add this to your environment:"));
562
+ console.log(pc3.dim(` INVECT_ENCRYPTION_KEY="${key}"`));
563
+ console.log("");
564
+ console.log(pc3.dim(" This key is used for AES-256-GCM encryption of credentials."));
565
+ console.log(pc3.dim(" Store it securely \u2014 losing it means losing access to encrypted data.\n"));
566
+ });
567
+
568
+ // src/index.ts
569
+ import "dotenv/config";
570
+ process.on("SIGINT", () => process.exit(0));
571
+ process.on("SIGTERM", () => process.exit(0));
572
+ async function main() {
573
+ const program = new Command4("invect");
574
+ program.description("CLI for managing Invect workflow engine projects").version("0.1.0");
575
+ program.addCommand(generateCommand).addCommand(migrateCommand).addCommand(initCommand).addCommand(infoCommand).addCommand(secretCommand).action(() => program.help());
576
+ await program.parseAsync(process.argv);
577
+ }
578
+ main().catch((error) => {
579
+ console.error("Error running Invect CLI:", error);
580
+ process.exit(1);
581
+ });
@@ -0,0 +1,9 @@
1
+ import {
2
+ migrateAction,
3
+ migrateCommand
4
+ } from "./chunk-DGBTXQND.js";
5
+ import "./chunk-Q6JKV7VX.js";
6
+ export {
7
+ migrateAction,
8
+ migrateCommand
9
+ };
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@invect/cli",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "description": "CLI for managing Invect database schemas, migrations, and project setup",
6
+ "bin": {
7
+ "invect": "./dist/index.js",
8
+ "@invect/cli": "./dist/index.js"
9
+ },
10
+ "main": "dist/index.js",
11
+ "types": "dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ },
17
+ "./api": {
18
+ "types": "./dist/api.d.ts",
19
+ "import": "./dist/api.js"
20
+ }
21
+ },
22
+ "dependencies": {
23
+ "@mrleebo/prisma-ast": "^0.14.0",
24
+ "commander": "^13.1.0",
25
+ "dotenv": "^16.4.7",
26
+ "jiti": "^2.4.2",
27
+ "picocolors": "^1.1.1",
28
+ "prompts": "^2.4.2",
29
+ "@invect/core": "0.0.1"
30
+ },
31
+ "devDependencies": {
32
+ "@types/prompts": "^2.4.9",
33
+ "tsup": "^8.3.5",
34
+ "typescript": "^5.7.3",
35
+ "vitest": "^3.2.4"
36
+ },
37
+ "files": [
38
+ "dist"
39
+ ],
40
+ "keywords": [
41
+ "invect",
42
+ "cli",
43
+ "workflow",
44
+ "migration",
45
+ "drizzle"
46
+ ],
47
+ "author": "robase",
48
+ "license": "MIT",
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "https://github.com/robase/invect.git",
52
+ "directory": "pkg/cli"
53
+ },
54
+ "bugs": {
55
+ "url": "https://github.com/robase/invect/issues"
56
+ },
57
+ "homepage": "https://invect.dev",
58
+ "publishConfig": {
59
+ "access": "public"
60
+ },
61
+ "scripts": {
62
+ "build": "tsup src/index.ts src/api.ts --format esm --clean",
63
+ "dev": "tsup src/index.ts src/api.ts --format esm --watch",
64
+ "test": "vitest run",
65
+ "test:watch": "vitest"
66
+ }
67
+ }