@kodus/cli 0.0.1 ā 0.0.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/index.js +2 -525
- package/license.md +21 -0
- package/package.json +5 -1
- package/readme.md +128 -0
- package/templates/docker-compose.yml +159 -0
package/index.js
CHANGED
|
@@ -1,70 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { program } from "commander";
|
|
4
|
-
import
|
|
5
|
-
import chalk from "chalk";
|
|
6
|
-
import ora from "ora";
|
|
7
|
-
import fs from "fs-extra";
|
|
8
|
-
import path from "path";
|
|
9
|
-
import { execSync } from "child_process";
|
|
10
|
-
import { fileURLToPath } from "url";
|
|
11
|
-
import { dirname } from "path";
|
|
12
|
-
import crypto from "crypto";
|
|
13
|
-
import fetch from "node-fetch";
|
|
14
|
-
|
|
15
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
-
const __dirname = dirname(__filename);
|
|
17
|
-
|
|
18
|
-
// Helper functions
|
|
19
|
-
const generateSecretKey = () => crypto.randomBytes(32).toString("base64");
|
|
20
|
-
const generateDbPassword = () =>
|
|
21
|
-
crypto
|
|
22
|
-
.randomBytes(16)
|
|
23
|
-
.toString("base64")
|
|
24
|
-
.replace(/[^a-zA-Z0-9]/g, "")
|
|
25
|
-
.slice(0, 16);
|
|
26
|
-
|
|
27
|
-
const backupEnv = () => {
|
|
28
|
-
if (fs.existsSync(".env")) {
|
|
29
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
30
|
-
fs.copySync(".env", `.env.backup.${timestamp}`);
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
return false;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const restoreEnv = (backupFile) => {
|
|
37
|
-
if (fs.existsSync(backupFile)) {
|
|
38
|
-
fs.copySync(backupFile, ".env");
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
return false;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const getLatestVersion = () => {
|
|
45
|
-
try {
|
|
46
|
-
const result = execSync("git describe --tags --abbrev=0", { stdio: "pipe" })
|
|
47
|
-
.toString()
|
|
48
|
-
.trim();
|
|
49
|
-
return result;
|
|
50
|
-
} catch (error) {
|
|
51
|
-
Y;
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const getCurrentVersion = () => {
|
|
57
|
-
try {
|
|
58
|
-
const result = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
59
|
-
stdio: "pipe",
|
|
60
|
-
})
|
|
61
|
-
.toString()
|
|
62
|
-
.trim();
|
|
63
|
-
return result;
|
|
64
|
-
} catch (error) {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
};
|
|
4
|
+
import setupEnvironment from "./src/commands/install.js";
|
|
68
5
|
|
|
69
6
|
// CLI version
|
|
70
7
|
program.version("1.0.0");
|
|
@@ -73,466 +10,6 @@ program.version("1.0.0");
|
|
|
73
10
|
program
|
|
74
11
|
.command("install")
|
|
75
12
|
.description("Install and configure Kodus")
|
|
76
|
-
.action(
|
|
77
|
-
try {
|
|
78
|
-
// Check prerequisites
|
|
79
|
-
console.log(chalk.blue("\nš Checking prerequisites..."));
|
|
80
|
-
const spinner = ora("Checking Docker installation").start();
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
execSync("docker --version", { stdio: "ignore" });
|
|
84
|
-
spinner.succeed("Docker is installed");
|
|
85
|
-
} catch (error) {
|
|
86
|
-
spinner.fail("Docker is not installed");
|
|
87
|
-
console.error(
|
|
88
|
-
chalk.red(
|
|
89
|
-
"\nPlease install Docker first: https://docs.docker.com/get-docker/"
|
|
90
|
-
)
|
|
91
|
-
);
|
|
92
|
-
process.exit(1);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Environment type selection
|
|
96
|
-
const { envType } = await inquirer.prompt([
|
|
97
|
-
{
|
|
98
|
-
type: "list",
|
|
99
|
-
name: "envType",
|
|
100
|
-
message: "What type of environment are you setting up?",
|
|
101
|
-
choices: [
|
|
102
|
-
{ name: "Local (localhost)", value: "local" },
|
|
103
|
-
{ name: "External (with public URL)", value: "external" },
|
|
104
|
-
],
|
|
105
|
-
default: "local",
|
|
106
|
-
},
|
|
107
|
-
]);
|
|
108
|
-
|
|
109
|
-
let baseUrl = "http://localhost:3000";
|
|
110
|
-
if (envType === "external") {
|
|
111
|
-
const { url } = await inquirer.prompt([
|
|
112
|
-
{
|
|
113
|
-
type: "input",
|
|
114
|
-
name: "url",
|
|
115
|
-
message: "Enter your public URL (e.g., https://kodus.yourdomain.com):",
|
|
116
|
-
validate: (input) => {
|
|
117
|
-
try {
|
|
118
|
-
const url = new URL(input);
|
|
119
|
-
if (!url.protocol.startsWith('http')) {
|
|
120
|
-
return "URL must start with http:// or https://";
|
|
121
|
-
}
|
|
122
|
-
if (!url.hostname.includes('.')) {
|
|
123
|
-
return "URL must include a valid domain name";
|
|
124
|
-
}
|
|
125
|
-
return true;
|
|
126
|
-
} catch (e) {
|
|
127
|
-
return "Please enter a valid URL (e.g., https://kodus.yourdomain.com)";
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
]);
|
|
132
|
-
baseUrl = url;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Git service selection
|
|
136
|
-
const { gitService } = await inquirer.prompt([
|
|
137
|
-
{
|
|
138
|
-
type: "list",
|
|
139
|
-
name: "gitService",
|
|
140
|
-
message: "Which Git service will you use?",
|
|
141
|
-
choices: [
|
|
142
|
-
{ name: "GitHub", value: "github" },
|
|
143
|
-
{ name: "GitLab", value: "gitlab" },
|
|
144
|
-
{ name: "Bitbucket", value: "bitbucket" },
|
|
145
|
-
],
|
|
146
|
-
},
|
|
147
|
-
]);
|
|
148
|
-
|
|
149
|
-
// Git service configuration
|
|
150
|
-
let gitConfig = {};
|
|
151
|
-
|
|
152
|
-
if (envType === "local") {
|
|
153
|
-
console.log(chalk.yellow("\nā ļø IMPORTANT: If you're using a cloud Git service (GitHub, GitLab, Bitbucket), you'll need to configure the webhook manually."));
|
|
154
|
-
console.log(chalk.yellow("For local or self-hosted Git instances, no additional configuration is needed."));
|
|
155
|
-
console.log(chalk.yellow("The webhook URL will be:"));
|
|
156
|
-
console.log(chalk.white(`${baseUrl}/api/webhook/${gitService}`));
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Configure webhook URL based on the selected Git service
|
|
160
|
-
if (gitService === "github") {
|
|
161
|
-
gitConfig = {
|
|
162
|
-
API_GITHUB_CODE_MANAGEMENT_WEBHOOK: `${baseUrl}/api/webhook/${gitService}`,
|
|
163
|
-
};
|
|
164
|
-
} else if (gitService === "gitlab") {
|
|
165
|
-
gitConfig = {
|
|
166
|
-
API_GITLAB_CODE_MANAGEMENT_WEBHOOK: `${baseUrl}/api/webhook/${gitService}`,
|
|
167
|
-
};
|
|
168
|
-
} else if (gitService === "bitbucket") {
|
|
169
|
-
gitConfig = {
|
|
170
|
-
GLOBAL_BITBUCKET_CODE_MANAGEMENT_WEBHOOK: `${baseUrl}/api/webhook/${gitService}`,
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Database configuration
|
|
175
|
-
const { useDefaultDb } = await inquirer.prompt([
|
|
176
|
-
{
|
|
177
|
-
type: "confirm",
|
|
178
|
-
name: "useDefaultDb",
|
|
179
|
-
message: "Would you like to use default database configurations?",
|
|
180
|
-
default: true,
|
|
181
|
-
},
|
|
182
|
-
]);
|
|
183
|
-
|
|
184
|
-
// LLM API Keys configuration
|
|
185
|
-
console.log(chalk.blue("\nš Configuring LLM API Keys..."));
|
|
186
|
-
const llmKeys = await inquirer.prompt([
|
|
187
|
-
{
|
|
188
|
-
type: "input",
|
|
189
|
-
name: "openAiKey",
|
|
190
|
-
message: "Enter your OpenAI API key (optional):",
|
|
191
|
-
default: "",
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
type: "input",
|
|
195
|
-
name: "googleAiKey",
|
|
196
|
-
message: "Enter your Google AI API key (optional):",
|
|
197
|
-
default: "",
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
type: "input",
|
|
201
|
-
name: "anthropicKey",
|
|
202
|
-
message: "Enter your Anthropic API key (optional):",
|
|
203
|
-
default: "",
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
type: "input",
|
|
207
|
-
name: "fireworksKey",
|
|
208
|
-
message: "Enter your Fireworks API key (optional):",
|
|
209
|
-
default: "",
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
type: "input",
|
|
213
|
-
name: "novitaKey",
|
|
214
|
-
message: "Enter your Novita AI API key (optional):",
|
|
215
|
-
default: "",
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
type: "input",
|
|
219
|
-
name: "vertexKey",
|
|
220
|
-
message: "Enter your Vertex AI API key (optional):",
|
|
221
|
-
default: "",
|
|
222
|
-
},
|
|
223
|
-
]);
|
|
224
|
-
|
|
225
|
-
// Start installation
|
|
226
|
-
console.log(chalk.blue("\nš Starting installation..."));
|
|
227
|
-
|
|
228
|
-
// Generate .env content
|
|
229
|
-
const envContent = {
|
|
230
|
-
// Base configuration
|
|
231
|
-
WEB_NODE_ENV: "development",
|
|
232
|
-
WEB_HOSTNAME_API: "localhost",
|
|
233
|
-
WEB_PORT_API: "3001",
|
|
234
|
-
WEB_PORT: "3000",
|
|
235
|
-
WEB_NEXTAUTH_URL: "http://localhost:3000",
|
|
236
|
-
WEB_NEXTAUTH_SECRET: generateSecretKey(),
|
|
237
|
-
WEB_JWT_SECRET_KEY: generateSecretKey(),
|
|
238
|
-
|
|
239
|
-
API_NODE_ENV: "development",
|
|
240
|
-
API_LOG_LEVEL: "error",
|
|
241
|
-
API_LOG_PRETTY: "true",
|
|
242
|
-
API_HOST: "0.0.0.0",
|
|
243
|
-
API_PORT: "3001",
|
|
244
|
-
API_RATE_MAX_REQUEST: "100",
|
|
245
|
-
API_RATE_INTERVAL: "1000",
|
|
246
|
-
API_JWT_EXPIRES_IN: "365d",
|
|
247
|
-
API_JWT_SECRET: generateSecretKey(),
|
|
248
|
-
API_JWT_REFRESHSECRET: generateSecretKey(),
|
|
249
|
-
API_JWT_REFRESH_EXPIRES_IN: "7d",
|
|
250
|
-
|
|
251
|
-
GLOBAL_API_CONTAINER_NAME: "kodus-orchestrator-prod",
|
|
252
|
-
|
|
253
|
-
// Database
|
|
254
|
-
API_DATABASE_ENV: "development",
|
|
255
|
-
API_PG_DB_USERNAME: "kodusdev",
|
|
256
|
-
API_PG_DB_PASSWORD: generateDbPassword(),
|
|
257
|
-
API_PG_DB_DATABASE: "kodus_db",
|
|
258
|
-
API_PG_DB_HOST: "db_kodus_postgres",
|
|
259
|
-
API_PG_DB_PORT: "5432",
|
|
260
|
-
|
|
261
|
-
API_MG_DB_USERNAME: "kodusdev",
|
|
262
|
-
API_MG_DB_PASSWORD: generateDbPassword(),
|
|
263
|
-
API_MG_DB_DATABASE: "kodus_db",
|
|
264
|
-
API_MG_DB_HOST: "db_kodus_mongodb",
|
|
265
|
-
API_MG_DB_PORT: "27017",
|
|
266
|
-
API_MG_DB_PRODUCTION_CONFIG: "",
|
|
267
|
-
|
|
268
|
-
// LLM API Keys
|
|
269
|
-
API_OPEN_AI_APIKEY: llmKeys.openAiKey,
|
|
270
|
-
API_GOOGLE_AI_API_KEY: llmKeys.googleAiKey,
|
|
271
|
-
API_ANTHROPIC_API_KEY: llmKeys.anthropicKey,
|
|
272
|
-
API_FIREWORKS_API_KEY: llmKeys.fireworksKey,
|
|
273
|
-
API_NOVITA_AI_API_KEY: llmKeys.novitaKey,
|
|
274
|
-
API_VERTEX_AI_API_KEY: llmKeys.vertexKey,
|
|
275
|
-
|
|
276
|
-
// LLM Models
|
|
277
|
-
API_LLM_MODEL_CHATGPT_3_5_TURBO: "gpt-4o-mini",
|
|
278
|
-
API_LLM_MODEL_CHATGPT_3_5_TURBO_16K: "gpt-4o-mini",
|
|
279
|
-
API_LLM_MODEL_CHATGPT_4: "gpt-4o-mini",
|
|
280
|
-
API_LLM_MODEL_CHATGPT_4_TURBO: "gpt-4o-mini",
|
|
281
|
-
API_LLM_MODEL_CHATGPT_4_ALL: "gpt-4o",
|
|
282
|
-
API_LLM_MODEL_CHATGPT_4_ALL_MINI: "gpt-4o-mini",
|
|
283
|
-
API_LLM_MODEL_CLAUDE_3_5_SONNET: "claude-3-5-sonnet-20241022",
|
|
284
|
-
API_LLM_MODEL_CLAUDE_3_5_SONNET_20241022: "claude-3-5-sonnet-20241022",
|
|
285
|
-
API_LLM_MODEL_GEMINI_1_5_PRO: "gpt-4o-mini",
|
|
286
|
-
API_LLM_MODEL_GEMINI_1_5_PRO_EXP: "gpt-4o-mini",
|
|
287
|
-
|
|
288
|
-
// Git service configuration
|
|
289
|
-
...gitConfig,
|
|
290
|
-
|
|
291
|
-
// Ports
|
|
292
|
-
WEB_PORT: "3000",
|
|
293
|
-
API_PORT: "3001",
|
|
294
|
-
|
|
295
|
-
// RabbitMQ
|
|
296
|
-
RABBITMQ_DEFAULT_USER: "kodus",
|
|
297
|
-
RABBITMQ_DEFAULT_PASS: generateDbPassword(),
|
|
298
|
-
|
|
299
|
-
// Monitoring
|
|
300
|
-
GRAFANA_ADMIN_PASSWORD: generateDbPassword(),
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
// Create .env file
|
|
304
|
-
const envSpinner = ora("Creating .env file").start();
|
|
305
|
-
const envContentString = Object.entries(envContent)
|
|
306
|
-
.map(([key, value]) => `${key}=${value}`)
|
|
307
|
-
.join("\n");
|
|
308
|
-
fs.writeFileSync(".env", envContentString);
|
|
309
|
-
envSpinner.succeed("Created .env file");
|
|
310
|
-
|
|
311
|
-
// Start containers
|
|
312
|
-
const dockerSpinner = ora("Starting containers").start();
|
|
313
|
-
try {
|
|
314
|
-
execSync("docker-compose up -d", { stdio: "pipe" });
|
|
315
|
-
dockerSpinner.succeed("Containers started");
|
|
316
|
-
} catch (error) {
|
|
317
|
-
dockerSpinner.fail("Failed to start containers");
|
|
318
|
-
console.error(chalk.red("\nError details:"));
|
|
319
|
-
console.error(chalk.white(error.stdout?.toString() || error.message));
|
|
320
|
-
process.exit(1);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const maxAttempts = 30; // 5 minutes with 10 second intervals
|
|
324
|
-
|
|
325
|
-
// Wait for PostgreSQL to be ready
|
|
326
|
-
const pgSpinner = ora("Waiting for PostgreSQL to be ready").start();
|
|
327
|
-
let isPgReady = false;
|
|
328
|
-
let pgAttempts = 0;
|
|
329
|
-
|
|
330
|
-
while (!isPgReady && pgAttempts < maxAttempts) {
|
|
331
|
-
try {
|
|
332
|
-
const logs = execSync("docker-compose logs db_kodus_postgres", { stdio: "pipe" }).toString();
|
|
333
|
-
if (logs.includes("database system is ready to accept connections")) {
|
|
334
|
-
isPgReady = true;
|
|
335
|
-
pgSpinner.succeed("PostgreSQL is ready");
|
|
336
|
-
} else {
|
|
337
|
-
pgAttempts++;
|
|
338
|
-
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
339
|
-
}
|
|
340
|
-
} catch (error) {
|
|
341
|
-
pgAttempts++;
|
|
342
|
-
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
if (!isPgReady) {
|
|
347
|
-
pgSpinner.fail("PostgreSQL failed to start");
|
|
348
|
-
console.error(chalk.red("\nError: PostgreSQL failed to start properly"));
|
|
349
|
-
console.error(chalk.yellow("\nTroubleshooting steps:"));
|
|
350
|
-
console.error(chalk.white("1. Check PostgreSQL logs: docker-compose logs db_kodus_postgres"));
|
|
351
|
-
console.error(chalk.white("2. Verify PostgreSQL container is running: docker-compose ps db_kodus_postgres"));
|
|
352
|
-
process.exit(1);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// Wait for MongoDB to be ready
|
|
356
|
-
const mongoSpinner = ora("Waiting for MongoDB to be ready").start();
|
|
357
|
-
let isMongoReady = false;
|
|
358
|
-
let mongoAttempts = 0;
|
|
359
|
-
|
|
360
|
-
while (!isMongoReady && mongoAttempts < maxAttempts) {
|
|
361
|
-
try {
|
|
362
|
-
const logs = execSync("docker-compose logs db_kodus_mongodb", { stdio: "pipe" }).toString();
|
|
363
|
-
if (logs.includes("Waiting for connections") || logs.includes("Connection accepted")) {
|
|
364
|
-
isMongoReady = true;
|
|
365
|
-
mongoSpinner.succeed("MongoDB is ready");
|
|
366
|
-
} else {
|
|
367
|
-
mongoAttempts++;
|
|
368
|
-
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
369
|
-
}
|
|
370
|
-
} catch (error) {
|
|
371
|
-
mongoAttempts++;
|
|
372
|
-
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
if (!isMongoReady) {
|
|
377
|
-
mongoSpinner.fail("MongoDB failed to start");
|
|
378
|
-
console.error(chalk.red("\nError: MongoDB failed to start properly"));
|
|
379
|
-
console.error(chalk.yellow("\nTroubleshooting steps:"));
|
|
380
|
-
console.error(chalk.white("1. Check MongoDB logs: docker-compose logs db_kodus_mongodb"));
|
|
381
|
-
console.error(chalk.white("2. Verify MongoDB container is running: docker-compose ps db_kodus_mongodb"));
|
|
382
|
-
process.exit(1);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
// Now wait for orchestrator to be ready
|
|
386
|
-
const healthSpinner = ora("Waiting for orchestrator to be ready").start();
|
|
387
|
-
let isOrchestratorReady = false;
|
|
388
|
-
let attempts = 0;
|
|
389
|
-
|
|
390
|
-
const criticalErrors = [
|
|
391
|
-
"password authentication failed",
|
|
392
|
-
"Unable to connect to the database",
|
|
393
|
-
"FATAL:",
|
|
394
|
-
"MongoServerError:",
|
|
395
|
-
"connection refused"
|
|
396
|
-
];
|
|
397
|
-
|
|
398
|
-
while (!isOrchestratorReady && attempts < maxAttempts) {
|
|
399
|
-
try {
|
|
400
|
-
// Check if container is running
|
|
401
|
-
const containerStatus = execSync("docker-compose ps orchestrator --format json", { stdio: "pipe" }).toString();
|
|
402
|
-
const status = JSON.parse(containerStatus)[0];
|
|
403
|
-
|
|
404
|
-
if (status.State === "running") {
|
|
405
|
-
// Check logs for any errors
|
|
406
|
-
const logs = execSync("docker-compose logs --tail=50 orchestrator", { stdio: "pipe" }).toString();
|
|
407
|
-
|
|
408
|
-
// Check for critical errors that should stop the process
|
|
409
|
-
const foundCriticalError = criticalErrors.find(error => logs.includes(error));
|
|
410
|
-
if (foundCriticalError) {
|
|
411
|
-
healthSpinner.fail("Critical error detected");
|
|
412
|
-
console.error(chalk.red("\nError: Database connection failed"));
|
|
413
|
-
console.error(chalk.yellow("\nTroubleshooting steps:"));
|
|
414
|
-
console.error(chalk.white("1. Check if the database passwords in .env match the ones in your database"));
|
|
415
|
-
console.error(chalk.white("2. Verify if the database containers are running: docker-compose ps"));
|
|
416
|
-
console.error(chalk.white("3. Check database logs: docker-compose logs db_kodus_postgres db_kodus_mongodb"));
|
|
417
|
-
console.error(chalk.white("\nFull error log:"));
|
|
418
|
-
console.error(chalk.white(logs));
|
|
419
|
-
process.exit(1);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// If no critical errors and we see successful connection messages, proceed
|
|
423
|
-
if (logs.includes("Database connection established") || logs.includes("Connected to MongoDB")) {
|
|
424
|
-
isOrchestratorReady = true;
|
|
425
|
-
healthSpinner.succeed("Orchestrator is ready");
|
|
426
|
-
} else {
|
|
427
|
-
attempts++;
|
|
428
|
-
await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds
|
|
429
|
-
}
|
|
430
|
-
} else {
|
|
431
|
-
attempts++;
|
|
432
|
-
await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds
|
|
433
|
-
}
|
|
434
|
-
} catch (error) {
|
|
435
|
-
attempts++;
|
|
436
|
-
await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
if (!isOrchestratorReady) {
|
|
441
|
-
healthSpinner.fail("Orchestrator failed to start");
|
|
442
|
-
console.error(chalk.red("\nError: The orchestrator service failed to start properly."));
|
|
443
|
-
console.error(chalk.yellow("\nTroubleshooting steps:"));
|
|
444
|
-
console.error(chalk.white("1. Check the orchestrator logs: docker-compose logs orchestrator"));
|
|
445
|
-
console.error(chalk.white("2. Verify all required services are running: docker-compose ps"));
|
|
446
|
-
console.error(chalk.white("3. Try restarting the services: docker-compose restart"));
|
|
447
|
-
process.exit(1);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// Setup database
|
|
451
|
-
const dbSpinner = ora("Setting up database").start();
|
|
452
|
-
try {
|
|
453
|
-
execSync("./scripts/setup-db.sh", { stdio: "pipe" });
|
|
454
|
-
dbSpinner.succeed("Database setup completed");
|
|
455
|
-
} catch (error) {
|
|
456
|
-
dbSpinner.fail("Failed to setup database");
|
|
457
|
-
console.error(chalk.red("\nError details:"));
|
|
458
|
-
console.error(chalk.white(error.stdout?.toString() || error.message));
|
|
459
|
-
process.exit(1);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// Verify database connection by checking orchestrator logs
|
|
463
|
-
const dbCheckSpinner = ora("Verifying database connection").start();
|
|
464
|
-
try {
|
|
465
|
-
const logs = execSync("docker-compose logs --tail=50 orchestrator", { stdio: "pipe" }).toString();
|
|
466
|
-
|
|
467
|
-
// Look for database connection errors in logs
|
|
468
|
-
if (logs.includes("database connection error") || logs.includes("Database connection failed")) {
|
|
469
|
-
throw new Error("Database connection errors found in logs");
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
dbCheckSpinner.succeed("Database connection verified");
|
|
473
|
-
} catch (error) {
|
|
474
|
-
dbCheckSpinner.fail("Failed to verify database connection");
|
|
475
|
-
console.error(chalk.red("\nError: Could not verify database connection."));
|
|
476
|
-
console.error(chalk.yellow("Please check the logs with: docker-compose logs orchestrator"));
|
|
477
|
-
process.exit(1);
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
// Installation complete
|
|
481
|
-
console.log(chalk.green("\n⨠Installation completed successfully!"));
|
|
482
|
-
|
|
483
|
-
console.log(chalk.blue("\nš Installation Summary:"));
|
|
484
|
-
console.log(
|
|
485
|
-
chalk.white(
|
|
486
|
-
` - Environment: ${envType === "local" ? "Local" : "External"}`
|
|
487
|
-
)
|
|
488
|
-
);
|
|
489
|
-
if (envType === "external") {
|
|
490
|
-
console.log(chalk.white(` - Base URL: ${baseUrl}`));
|
|
491
|
-
}
|
|
492
|
-
console.log(
|
|
493
|
-
chalk.white(
|
|
494
|
-
` - Git Service: ${
|
|
495
|
-
gitService.charAt(0).toUpperCase() + gitService.slice(1)
|
|
496
|
-
}`
|
|
497
|
-
)
|
|
498
|
-
);
|
|
499
|
-
console.log(
|
|
500
|
-
chalk.white(
|
|
501
|
-
` - Database: ${
|
|
502
|
-
useDefaultDb ? "Default configuration" : "Custom configuration"
|
|
503
|
-
}`
|
|
504
|
-
)
|
|
505
|
-
);
|
|
506
|
-
|
|
507
|
-
console.log(chalk.blue("\nš Access URLs:"));
|
|
508
|
-
console.log(chalk.white(` - Web Interface: ${baseUrl}`));
|
|
509
|
-
console.log(chalk.white(" - Grafana Dashboard: http://localhost:3001"));
|
|
510
|
-
console.log(
|
|
511
|
-
chalk.white(" - RabbitMQ Management: http://localhost:15672")
|
|
512
|
-
);
|
|
513
|
-
|
|
514
|
-
console.log(chalk.blue("\nš Next Steps:"));
|
|
515
|
-
console.log(chalk.white(" 1. Access the web interface"));
|
|
516
|
-
console.log(chalk.white(" 2. Set up your first user"));
|
|
517
|
-
console.log(chalk.white(" 3. Start using Kodus!"));
|
|
518
|
-
|
|
519
|
-
const { startServices } = await inquirer.prompt([
|
|
520
|
-
{
|
|
521
|
-
type: "confirm",
|
|
522
|
-
name: "startServices",
|
|
523
|
-
message: "Would you like to start the services now?",
|
|
524
|
-
default: true,
|
|
525
|
-
},
|
|
526
|
-
]);
|
|
527
|
-
|
|
528
|
-
if (startServices) {
|
|
529
|
-
execSync("docker-compose up -d", { stdio: "ignore" });
|
|
530
|
-
console.log(chalk.green("\nServices started successfully!"));
|
|
531
|
-
}
|
|
532
|
-
} catch (error) {
|
|
533
|
-
console.error(chalk.red("\nā Installation failed:"), error.message);
|
|
534
|
-
process.exit(1);
|
|
535
|
-
}
|
|
536
|
-
});
|
|
13
|
+
.action(setupEnvironment);
|
|
537
14
|
|
|
538
15
|
program.parse(process.argv);
|
package/license.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Kodus CLI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kodus/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "CLI tool for Kodus installation and management",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
"bin": {
|
|
9
9
|
"kodus": "./index.js"
|
|
10
10
|
},
|
|
11
|
+
"files": [
|
|
12
|
+
"index.js",
|
|
13
|
+
"templates/**/*"
|
|
14
|
+
],
|
|
11
15
|
"scripts": {
|
|
12
16
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
13
17
|
},
|
package/readme.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://kodus.io/wp-content/uploads/2025/04/koduscli.png" alt="Kodus CLI Banner" />
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
**Deploy and manage Kodus AI Code Review Agents in your infrastructure**
|
|
8
|
+
|
|
9
|
+
[](https://github.com/yourusername/kodus-cli/blob/main/LICENSE)
|
|
10
|
+
[](https://www.npmjs.com/package/@kodus/cli)
|
|
11
|
+
[](https://www.npmjs.com/package/@kodus/cli)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
## š Overview
|
|
16
|
+
|
|
17
|
+
Kodus CLI is your gateway to running Kodus AI Code Review Agents in your own infrastructure. With a single command, deploy and manage your code review automation system, keeping your code quality high while maintaining full control over your data and infrastructure.
|
|
18
|
+
|
|
19
|
+
## ⨠Features
|
|
20
|
+
|
|
21
|
+
- š„ **One-Command Deployment**: Deploy your entire Kodus infrastructure in minutes
|
|
22
|
+
- š **Self-Hosted**: Keep your code and data within your infrastructure
|
|
23
|
+
- š¤ **AI-Powered Reviews**: Leverage advanced AI models for code review automation
|
|
24
|
+
- š **Git Integration**: Seamless integration with GitHub, GitLab, and Bitbucket
|
|
25
|
+
- š **Monitoring & Analytics**: Built-in Grafana dashboards for insights
|
|
26
|
+
- š³ **Docker-Powered**: Containerized for consistency and easy management
|
|
27
|
+
- š **Secure by Default**: Enterprise-grade security with auto-generated credentials
|
|
28
|
+
|
|
29
|
+
## š Quick Start
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Install globally
|
|
33
|
+
npm install -g kodus-cli
|
|
34
|
+
|
|
35
|
+
# Deploy Kodus in your infrastructure
|
|
36
|
+
kodus install
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## š Documentation
|
|
40
|
+
|
|
41
|
+
### Basic Usage
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Deploy Kodus
|
|
45
|
+
kodus install
|
|
46
|
+
|
|
47
|
+
# Follow the interactive prompts to configure:
|
|
48
|
+
# - Environment type (local/external)
|
|
49
|
+
# - Git service integration
|
|
50
|
+
# - AI provider settings
|
|
51
|
+
# - Infrastructure preferences
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Environment Types
|
|
55
|
+
|
|
56
|
+
- **Local Development**
|
|
57
|
+
|
|
58
|
+
- Perfect for testing and development
|
|
59
|
+
- Runs everything on localhost
|
|
60
|
+
- Ideal for small teams and individual developers
|
|
61
|
+
|
|
62
|
+
- **External Deployment**
|
|
63
|
+
- Production-ready setup
|
|
64
|
+
- Configurable for any domain
|
|
65
|
+
- Suitable for enterprise environments
|
|
66
|
+
|
|
67
|
+
### Supported Git Services
|
|
68
|
+
|
|
69
|
+
| Service | Features |
|
|
70
|
+
| --------- | ------------------------------------------- |
|
|
71
|
+
| GitHub | Pull Request Reviews, Issue Analysis |
|
|
72
|
+
| GitLab | Merge Request Reviews, Pipeline Integration |
|
|
73
|
+
| Bitbucket | Pull Request Reviews, Repository Analysis |
|
|
74
|
+
|
|
75
|
+
### AI Integration
|
|
76
|
+
|
|
77
|
+
Kodus supports multiple AI providers for code review:
|
|
78
|
+
|
|
79
|
+
- OpenAI (GPT-4)
|
|
80
|
+
- Google AI
|
|
81
|
+
- Anthropic (Claude)
|
|
82
|
+
- Novita AI
|
|
83
|
+
- Vertex AI
|
|
84
|
+
|
|
85
|
+
## š Security
|
|
86
|
+
|
|
87
|
+
- All data stays within your infrastructure
|
|
88
|
+
- No code or sensitive information is sent to external servers
|
|
89
|
+
- Enterprise-grade encryption for all communications
|
|
90
|
+
- Role-based access control
|
|
91
|
+
- Audit logging for all operations
|
|
92
|
+
|
|
93
|
+
## š¤ Contributing
|
|
94
|
+
|
|
95
|
+
We welcome contributions!
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Clone the repository
|
|
99
|
+
git clone https://github.com/yourusername/kodus-cli.git
|
|
100
|
+
|
|
101
|
+
# Install dependencies
|
|
102
|
+
npm install
|
|
103
|
+
|
|
104
|
+
# Run tests
|
|
105
|
+
npm test
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## š License
|
|
109
|
+
|
|
110
|
+
MIT Ā© Kodus
|
|
111
|
+
|
|
112
|
+
## š Star History
|
|
113
|
+
|
|
114
|
+
[](https://star-history.com/#yourusername/kodus-cli&Date)
|
|
115
|
+
|
|
116
|
+
## š Acknowledgments
|
|
117
|
+
|
|
118
|
+
Special thanks to all our contributors and the amazing open-source community.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
<div align="center">
|
|
123
|
+
|
|
124
|
+
**[Website](https://kodus.ios)** ⢠**[Documentation](https://docs.kodus.io)** ⢠**[Twitter](https://twitter.com/kodustech)** ⢠**[Discord](https://discord.gg/VkbfjbZr)**
|
|
125
|
+
|
|
126
|
+
Made with ā¤ļø by the Kodus Team
|
|
127
|
+
|
|
128
|
+
</div>
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
services:
|
|
2
|
+
kodus-web:
|
|
3
|
+
image: ghcr.io/kodustech/kodus-web:latest
|
|
4
|
+
container_name: kodus-web-prod
|
|
5
|
+
ports:
|
|
6
|
+
- "${WEB_PORT}:${WEB_PORT}"
|
|
7
|
+
networks:
|
|
8
|
+
- shared-network
|
|
9
|
+
- kodus-backend-services
|
|
10
|
+
restart: unless-stopped
|
|
11
|
+
env_file:
|
|
12
|
+
- .env
|
|
13
|
+
|
|
14
|
+
kodus-orchestrator:
|
|
15
|
+
image: ghcr.io/kodustech/kodus-ai:latest
|
|
16
|
+
platform: linux/amd64
|
|
17
|
+
container_name: ${GLOBAL_API_CONTAINER_NAME}
|
|
18
|
+
volumes:
|
|
19
|
+
- log_volume:/app/logs
|
|
20
|
+
logging:
|
|
21
|
+
options:
|
|
22
|
+
max-size: "200m"
|
|
23
|
+
max-file: "10"
|
|
24
|
+
ports:
|
|
25
|
+
- "3001:3001"
|
|
26
|
+
- "9229:9229"
|
|
27
|
+
environment:
|
|
28
|
+
- ENV=production
|
|
29
|
+
- NODE_ENV=production
|
|
30
|
+
networks:
|
|
31
|
+
- shared-network
|
|
32
|
+
- kodus-backend-services
|
|
33
|
+
restart: unless-stopped
|
|
34
|
+
env_file:
|
|
35
|
+
- .env
|
|
36
|
+
|
|
37
|
+
rabbitmq:
|
|
38
|
+
image: localhost:5000/rabbitmq:prod
|
|
39
|
+
container_name: rabbitmq-prod
|
|
40
|
+
hostname: rabbitmq
|
|
41
|
+
ports:
|
|
42
|
+
- "5672:5672"
|
|
43
|
+
- "15672:15672"
|
|
44
|
+
networks:
|
|
45
|
+
- monitoring-network
|
|
46
|
+
- shared-network
|
|
47
|
+
environment:
|
|
48
|
+
- RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS=-rabbit heartbeat 60
|
|
49
|
+
restart: unless-stopped
|
|
50
|
+
env_file:
|
|
51
|
+
- .env
|
|
52
|
+
|
|
53
|
+
db_kodus_postgres:
|
|
54
|
+
image: postgres:latest
|
|
55
|
+
container_name: db_kodus_postgres
|
|
56
|
+
ports:
|
|
57
|
+
- "5432:5432"
|
|
58
|
+
environment:
|
|
59
|
+
# These variables must be defined in the .env file
|
|
60
|
+
POSTGRES_USER: ${API_PG_DB_USERNAME}
|
|
61
|
+
POSTGRES_PASSWORD: ${API_PG_DB_PASSWORD}
|
|
62
|
+
POSTGRES_DB: ${API_PG_DB_DATABASE}
|
|
63
|
+
volumes:
|
|
64
|
+
- pgdata:/var/lib/postgresql/data
|
|
65
|
+
networks:
|
|
66
|
+
- kodus-backend-services
|
|
67
|
+
|
|
68
|
+
db_kodus_mongodb:
|
|
69
|
+
image: mongo:7
|
|
70
|
+
container_name: db_kodus_mongodb
|
|
71
|
+
ports:
|
|
72
|
+
- "27017:27017"
|
|
73
|
+
volumes:
|
|
74
|
+
- mongodbdata:/data/db
|
|
75
|
+
environment:
|
|
76
|
+
# These variables must be defined in the .env file
|
|
77
|
+
MONGO_INITDB_ROOT_USERNAME: ${API_MG_DB_USERNAME}
|
|
78
|
+
MONGO_INITDB_ROOT_PASSWORD: ${API_MG_DB_PASSWORD}
|
|
79
|
+
MONGO_INITDB_DATABASE: ${API_MG_DB_DATABASE}
|
|
80
|
+
networks:
|
|
81
|
+
- kodus-backend-services
|
|
82
|
+
|
|
83
|
+
prometheus:
|
|
84
|
+
container_name: prometheus-prod
|
|
85
|
+
image: prom/prometheus:latest
|
|
86
|
+
environment:
|
|
87
|
+
- ENV=production
|
|
88
|
+
command:
|
|
89
|
+
- "--config.file=/etc/prometheus/prometheus.yml"
|
|
90
|
+
- "--storage.tsdb.retention.time=30d"
|
|
91
|
+
- "--storage.tsdb.retention.size=50GB"
|
|
92
|
+
- "--web.enable-lifecycle"
|
|
93
|
+
- "--web.enable-admin-api"
|
|
94
|
+
deploy:
|
|
95
|
+
resources:
|
|
96
|
+
limits:
|
|
97
|
+
cpus: "1"
|
|
98
|
+
memory: 4G
|
|
99
|
+
reservations:
|
|
100
|
+
cpus: "0.75"
|
|
101
|
+
memory: 2G
|
|
102
|
+
|
|
103
|
+
migration:
|
|
104
|
+
image: ghcr.io/kodustech/kodus-ai:latest
|
|
105
|
+
platform: linux/amd64
|
|
106
|
+
container_name: migration
|
|
107
|
+
depends_on:
|
|
108
|
+
- db_kodus_postgres
|
|
109
|
+
environment:
|
|
110
|
+
- ENV=${API_DATABASE_ENV}
|
|
111
|
+
- NODE_ENV=${API_NODE_ENV}
|
|
112
|
+
- API_PG_DB_HOST=${API_PG_DB_HOST}
|
|
113
|
+
- API_PG_DB_PORT=${API_PG_DB_PORT}
|
|
114
|
+
- API_PG_DB_USERNAME=${API_PG_DB_USERNAME}
|
|
115
|
+
- API_PG_DB_PASSWORD=${API_PG_DB_PASSWORD}
|
|
116
|
+
- API_PG_DB_DATABASE=${API_PG_DB_DATABASE}
|
|
117
|
+
- PGSSLMODE=disable
|
|
118
|
+
command: >
|
|
119
|
+
sh -c '
|
|
120
|
+
echo "Debug: Printing environment variables..." &&
|
|
121
|
+
echo "API_PG_DB_HOST=" $$API_PG_DB_HOST &&
|
|
122
|
+
echo "Creating temporary datasource file..." &&
|
|
123
|
+
echo "const { DataSource } = require(\"typeorm\");
|
|
124
|
+
module.exports = new DataSource({
|
|
125
|
+
type: \"postgres\",
|
|
126
|
+
host: \"db_kodus_postgres\",
|
|
127
|
+
port: 5432,
|
|
128
|
+
username: \"$$API_PG_DB_USERNAME\",
|
|
129
|
+
password: \"$$API_PG_DB_PASSWORD\",
|
|
130
|
+
database: \"$$API_PG_DB_DATABASE\",
|
|
131
|
+
ssl: false,
|
|
132
|
+
entities: [\"./dist/modules/**/infra/typeorm/entities/*.js\"],
|
|
133
|
+
migrations: [\"./dist/config/database/typeorm/migrations/*.js\"]
|
|
134
|
+
});" > datasource.js &&
|
|
135
|
+
yarn typeorm migration:run -d datasource.js
|
|
136
|
+
'
|
|
137
|
+
networks:
|
|
138
|
+
- kodus-backend-services
|
|
139
|
+
env_file:
|
|
140
|
+
- .env
|
|
141
|
+
|
|
142
|
+
volumes:
|
|
143
|
+
log_volume:
|
|
144
|
+
rabbitmq-data-prod:
|
|
145
|
+
name: rabbitmq-data-prod
|
|
146
|
+
pgdata:
|
|
147
|
+
mongodbdata:
|
|
148
|
+
|
|
149
|
+
networks:
|
|
150
|
+
shared-network:
|
|
151
|
+
external: true
|
|
152
|
+
monitoring-network:
|
|
153
|
+
driver: bridge
|
|
154
|
+
name: monitoring-network
|
|
155
|
+
external: true
|
|
156
|
+
kodus-backend-services:
|
|
157
|
+
driver: bridge
|
|
158
|
+
name: kodus-backend-services
|
|
159
|
+
external: true
|