@kodus/cli 0.0.12 → 0.1.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 +387 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +26 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/auth/index.d.ts +3 -0
- package/dist/commands/auth/index.d.ts.map +1 -0
- package/dist/commands/auth/index.js +36 -0
- package/dist/commands/auth/index.js.map +1 -0
- package/dist/commands/auth/login.d.ts +7 -0
- package/dist/commands/auth/login.d.ts.map +1 -0
- package/dist/commands/auth/login.js +97 -0
- package/dist/commands/auth/login.js.map +1 -0
- package/dist/commands/auth/logout.d.ts +2 -0
- package/dist/commands/auth/logout.d.ts.map +1 -0
- package/dist/commands/auth/logout.js +24 -0
- package/dist/commands/auth/logout.js.map +1 -0
- package/dist/commands/auth/signup.d.ts +2 -0
- package/dist/commands/auth/signup.d.ts.map +1 -0
- package/dist/commands/auth/signup.js +74 -0
- package/dist/commands/auth/signup.js.map +1 -0
- package/dist/commands/auth/status.d.ts +2 -0
- package/dist/commands/auth/status.d.ts.map +1 -0
- package/dist/commands/auth/status.js +91 -0
- package/dist/commands/auth/status.js.map +1 -0
- package/dist/commands/auth/team-key.d.ts +5 -0
- package/dist/commands/auth/team-key.d.ts.map +1 -0
- package/dist/commands/auth/team-key.js +59 -0
- package/dist/commands/auth/team-key.js.map +1 -0
- package/dist/commands/auth/token.d.ts +2 -0
- package/dist/commands/auth/token.d.ts.map +1 -0
- package/dist/commands/auth/token.js +31 -0
- package/dist/commands/auth/token.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +47 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/pr.d.ts +3 -0
- package/dist/commands/pr.d.ts.map +1 -0
- package/dist/commands/pr.js +75 -0
- package/dist/commands/pr.js.map +1 -0
- package/dist/commands/review.d.ts +3 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +245 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/telemetry.d.ts +3 -0
- package/dist/commands/telemetry.d.ts.map +1 -0
- package/dist/commands/telemetry.js +76 -0
- package/dist/commands/telemetry.js.map +1 -0
- package/dist/commands/upgrade.d.ts +3 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +35 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +3 -0
- package/dist/constants.js.map +1 -0
- package/dist/formatters/json.d.ts +7 -0
- package/dist/formatters/json.d.ts.map +1 -0
- package/dist/formatters/json.js +7 -0
- package/dist/formatters/json.js.map +1 -0
- package/dist/formatters/markdown.d.ts +7 -0
- package/dist/formatters/markdown.d.ts.map +1 -0
- package/dist/formatters/markdown.js +93 -0
- package/dist/formatters/markdown.js.map +1 -0
- package/dist/formatters/prompt.d.ts +12 -0
- package/dist/formatters/prompt.d.ts.map +1 -0
- package/dist/formatters/prompt.js +90 -0
- package/dist/formatters/prompt.js.map +1 -0
- package/dist/formatters/terminal.d.ts +7 -0
- package/dist/formatters/terminal.d.ts.map +1 -0
- package/dist/formatters/terminal.js +127 -0
- package/dist/formatters/terminal.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/services/api/api.interface.d.ts +46 -0
- package/dist/services/api/api.interface.d.ts.map +1 -0
- package/dist/services/api/api.interface.js +2 -0
- package/dist/services/api/api.interface.js.map +1 -0
- package/dist/services/api/api.mock.d.ts +8 -0
- package/dist/services/api/api.mock.d.ts.map +1 -0
- package/dist/services/api/api.mock.js +249 -0
- package/dist/services/api/api.mock.js.map +1 -0
- package/dist/services/api/api.real.d.ts +8 -0
- package/dist/services/api/api.real.d.ts.map +1 -0
- package/dist/services/api/api.real.js +253 -0
- package/dist/services/api/api.real.js.map +1 -0
- package/dist/services/api/index.d.ts +4 -0
- package/dist/services/api/index.d.ts.map +1 -0
- package/dist/services/api/index.js +9 -0
- package/dist/services/api/index.js.map +1 -0
- package/dist/services/auth.service.d.ts +19 -0
- package/dist/services/auth.service.d.ts.map +1 -0
- package/dist/services/auth.service.js +90 -0
- package/dist/services/auth.service.js.map +1 -0
- package/dist/services/context.service.d.ts +22 -0
- package/dist/services/context.service.d.ts.map +1 -0
- package/dist/services/context.service.js +104 -0
- package/dist/services/context.service.js.map +1 -0
- package/dist/services/fix.service.d.ts +31 -0
- package/dist/services/fix.service.d.ts.map +1 -0
- package/dist/services/fix.service.js +120 -0
- package/dist/services/fix.service.js.map +1 -0
- package/dist/services/git.service.d.ts +32 -0
- package/dist/services/git.service.d.ts.map +1 -0
- package/dist/services/git.service.js +261 -0
- package/dist/services/git.service.js.map +1 -0
- package/dist/services/review.service.d.ts +26 -0
- package/dist/services/review.service.d.ts.map +1 -0
- package/dist/services/review.service.js +82 -0
- package/dist/services/review.service.js.map +1 -0
- package/dist/services/telemetry.service.d.ts +73 -0
- package/dist/services/telemetry.service.d.ts.map +1 -0
- package/dist/services/telemetry.service.js +229 -0
- package/dist/services/telemetry.service.js.map +1 -0
- package/dist/types/index.d.ts +143 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +15 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/interactive.d.ts +26 -0
- package/dist/ui/interactive.d.ts.map +1 -0
- package/dist/ui/interactive.js +365 -0
- package/dist/ui/interactive.js.map +1 -0
- package/dist/utils/config.d.ts +10 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +54 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/credentials.d.ts +6 -0
- package/dist/utils/credentials.d.ts.map +1 -0
- package/dist/utils/credentials.js +54 -0
- package/dist/utils/credentials.js.map +1 -0
- package/dist/utils/rate-limit.d.ts +5 -0
- package/dist/utils/rate-limit.d.ts.map +1 -0
- package/dist/utils/rate-limit.js +47 -0
- package/dist/utils/rate-limit.js.map +1 -0
- package/dist/utils/review-loading.d.ts +19 -0
- package/dist/utils/review-loading.d.ts.map +1 -0
- package/dist/utils/review-loading.js +140 -0
- package/dist/utils/review-loading.js.map +1 -0
- package/package.json +39 -33
- package/index.js +0 -15
- package/license.md +0 -21
- package/readme.md +0 -128
- package/scripts/setup-db.sh +0 -77
- package/src/commands/install.js +0 -357
- package/src/config/default.js +0 -66
- package/src/utils/helpers.js +0 -128
- package/templates/.env.example +0 -142
- package/templates/docker-compose.yml +0 -139
package/src/commands/install.js
DELETED
|
@@ -1,357 +0,0 @@
|
|
|
1
|
-
import inquirer from "inquirer";
|
|
2
|
-
import chalk from "chalk";
|
|
3
|
-
import ora from "ora";
|
|
4
|
-
import fs from "fs-extra";
|
|
5
|
-
import path from "path";
|
|
6
|
-
import { execSync } from "child_process";
|
|
7
|
-
import { DEFAULT_CONFIG, DOCKER_NETWORKS, CRITICAL_ERRORS } from "../config/default.js";
|
|
8
|
-
import {
|
|
9
|
-
generateBase64Secret,
|
|
10
|
-
generateHexSecret,
|
|
11
|
-
generateWebhookToken,
|
|
12
|
-
generateDbPassword,
|
|
13
|
-
copyTemplates,
|
|
14
|
-
createDockerNetworks,
|
|
15
|
-
updateEnvFile,
|
|
16
|
-
} from "../utils/helpers.js";
|
|
17
|
-
import { fileURLToPath } from 'url';
|
|
18
|
-
import { dirname } from 'path';
|
|
19
|
-
|
|
20
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
21
|
-
const __dirname = dirname(__filename);
|
|
22
|
-
|
|
23
|
-
const maxAttempts = 30; // 5 minutes with 10 second intervals
|
|
24
|
-
|
|
25
|
-
const waitForService = async (serviceName, successMessage, errorMessage) => {
|
|
26
|
-
const spinner = ora(`Waiting for ${serviceName} to be ready`).start();
|
|
27
|
-
let isReady = false;
|
|
28
|
-
let attempts = 0;
|
|
29
|
-
|
|
30
|
-
while (!isReady && attempts < maxAttempts) {
|
|
31
|
-
try {
|
|
32
|
-
const logs = execSync(`docker-compose logs ${serviceName}`, { stdio: "pipe" }).toString();
|
|
33
|
-
|
|
34
|
-
if (logs.includes(successMessage)) {
|
|
35
|
-
isReady = true;
|
|
36
|
-
spinner.succeed(`${serviceName} is ready`);
|
|
37
|
-
} else {
|
|
38
|
-
attempts++;
|
|
39
|
-
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
40
|
-
}
|
|
41
|
-
} catch (error) {
|
|
42
|
-
attempts++;
|
|
43
|
-
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (!isReady) {
|
|
48
|
-
spinner.fail(errorMessage);
|
|
49
|
-
console.error(chalk.yellow("\nTroubleshooting steps:"));
|
|
50
|
-
console.error(chalk.white(`1. Check ${serviceName} logs: docker-compose logs ${serviceName}`));
|
|
51
|
-
console.error(chalk.white(`2. Verify ${serviceName} container is running: docker-compose ps ${serviceName}`));
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const copyEnvFile = async () => {
|
|
57
|
-
const envExamplePath = path.join(__dirname, '../../templates/.env.example');
|
|
58
|
-
const envPath = path.join(process.cwd(), '.env');
|
|
59
|
-
|
|
60
|
-
if (!fs.existsSync(envExamplePath)) {
|
|
61
|
-
console.error(chalk.red('Error: .env.example file not found in templates directory'));
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
await fs.copy(envExamplePath, envPath);
|
|
67
|
-
console.log(chalk.green('.env file created successfully from template'));
|
|
68
|
-
} catch (error) {
|
|
69
|
-
console.error(chalk.red('Error copying .env file:', error.message));
|
|
70
|
-
process.exit(1);
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export const setupEnvironment = async () => {
|
|
75
|
-
try {
|
|
76
|
-
// Check prerequisites
|
|
77
|
-
console.log(chalk.blue("\n🔍 Checking prerequisites..."));
|
|
78
|
-
const spinner = ora("Checking Docker installation").start();
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
execSync("docker --version", { stdio: "ignore" });
|
|
82
|
-
spinner.succeed("Docker is installed");
|
|
83
|
-
} catch (error) {
|
|
84
|
-
spinner.fail("Docker is not installed");
|
|
85
|
-
console.error(
|
|
86
|
-
chalk.red(
|
|
87
|
-
"\nPlease install Docker first: https://docs.docker.com/get-docker/"
|
|
88
|
-
)
|
|
89
|
-
);
|
|
90
|
-
process.exit(1);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Copy template files
|
|
94
|
-
const templateSpinner = ora("Copying template files").start();
|
|
95
|
-
try {
|
|
96
|
-
copyTemplates(process.cwd());
|
|
97
|
-
templateSpinner.succeed("Template files copied");
|
|
98
|
-
} catch (error) {
|
|
99
|
-
templateSpinner.fail("Failed to copy template files");
|
|
100
|
-
console.error(chalk.red("\nError details:"));
|
|
101
|
-
console.error(chalk.white(error.message));
|
|
102
|
-
process.exit(1);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
await copyEnvFile();
|
|
106
|
-
|
|
107
|
-
// Environment type selection
|
|
108
|
-
const { envType } = await inquirer.prompt([
|
|
109
|
-
{
|
|
110
|
-
type: "list",
|
|
111
|
-
name: "envType",
|
|
112
|
-
message: "What type of environment are you setting up?",
|
|
113
|
-
choices: [
|
|
114
|
-
{ name: "Local (localhost)", value: "local" },
|
|
115
|
-
{ name: "External (with public URL)", value: "external" },
|
|
116
|
-
],
|
|
117
|
-
default: "local",
|
|
118
|
-
},
|
|
119
|
-
]);
|
|
120
|
-
|
|
121
|
-
let baseUrl = "http://localhost:3000";
|
|
122
|
-
if (envType === "external") {
|
|
123
|
-
const { url } = await inquirer.prompt([
|
|
124
|
-
{
|
|
125
|
-
type: "input",
|
|
126
|
-
name: "url",
|
|
127
|
-
message: "Enter your public URL (e.g., https://kodus.yourdomain.com):",
|
|
128
|
-
validate: (input) => {
|
|
129
|
-
try {
|
|
130
|
-
const url = new URL(input);
|
|
131
|
-
if (!url.protocol.startsWith('http')) {
|
|
132
|
-
return "URL must start with http:// or https://";
|
|
133
|
-
}
|
|
134
|
-
if (!url.hostname.includes('.')) {
|
|
135
|
-
return "URL must include a valid domain name";
|
|
136
|
-
}
|
|
137
|
-
return true;
|
|
138
|
-
} catch (e) {
|
|
139
|
-
return "Please enter a valid URL (e.g., https://kodus.yourdomain.com)";
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
]);
|
|
144
|
-
baseUrl = url;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Git service selection
|
|
148
|
-
const { gitService } = await inquirer.prompt([
|
|
149
|
-
{
|
|
150
|
-
type: "list",
|
|
151
|
-
name: "gitService",
|
|
152
|
-
message: "Which Git service will you use?",
|
|
153
|
-
choices: [
|
|
154
|
-
{ name: "GitHub", value: "github" },
|
|
155
|
-
{ name: "GitLab", value: "gitlab" },
|
|
156
|
-
{ name: "Bitbucket", value: "bitbucket" },
|
|
157
|
-
],
|
|
158
|
-
},
|
|
159
|
-
]);
|
|
160
|
-
|
|
161
|
-
// Git service configuration
|
|
162
|
-
let gitConfig = {};
|
|
163
|
-
|
|
164
|
-
if (envType === "local") {
|
|
165
|
-
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."));
|
|
166
|
-
console.log(chalk.yellow("For local or self-hosted Git instances, no additional configuration is needed."));
|
|
167
|
-
console.log(chalk.yellow("The webhook URL will be:"));
|
|
168
|
-
console.log(chalk.white(`${baseUrl}/api/webhook/${gitService}`));
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Configure webhook URL based on the selected Git service
|
|
172
|
-
if (gitService === "github") {
|
|
173
|
-
gitConfig = {
|
|
174
|
-
API_GITHUB_CODE_MANAGEMENT_WEBHOOK: `${baseUrl}/api/webhook/${gitService}`,
|
|
175
|
-
};
|
|
176
|
-
} else if (gitService === "gitlab") {
|
|
177
|
-
gitConfig = {
|
|
178
|
-
API_GITLAB_CODE_MANAGEMENT_WEBHOOK: `${baseUrl}/api/webhook/${gitService}`,
|
|
179
|
-
};
|
|
180
|
-
} else if (gitService === "bitbucket") {
|
|
181
|
-
gitConfig = {
|
|
182
|
-
GLOBAL_BITBUCKET_CODE_MANAGEMENT_WEBHOOK: `${baseUrl}/api/webhook/${gitService}`,
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Database configuration
|
|
187
|
-
const { useDefaultDb } = await inquirer.prompt([
|
|
188
|
-
{
|
|
189
|
-
type: "confirm",
|
|
190
|
-
name: "useDefaultDb",
|
|
191
|
-
message: "Would you like to use default database configurations?",
|
|
192
|
-
default: true,
|
|
193
|
-
},
|
|
194
|
-
]);
|
|
195
|
-
|
|
196
|
-
// LLM API Keys configuration
|
|
197
|
-
console.log(chalk.blue("\n🔑 Configuring LLM API Keys..."));
|
|
198
|
-
const llmKeys = await inquirer.prompt([
|
|
199
|
-
{
|
|
200
|
-
type: "input",
|
|
201
|
-
name: "openAiKey",
|
|
202
|
-
message: "Enter your OpenAI API key (optional):",
|
|
203
|
-
default: "",
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
type: "input",
|
|
207
|
-
name: "googleAiKey",
|
|
208
|
-
message: "Enter your Google AI API key (optional):",
|
|
209
|
-
default: "",
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
type: "input",
|
|
213
|
-
name: "anthropicKey",
|
|
214
|
-
message: "Enter your Anthropic API key (optional):",
|
|
215
|
-
default: "",
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
type: "input",
|
|
219
|
-
name: "novitaKey",
|
|
220
|
-
message: "Enter your Novita AI API key (optional):",
|
|
221
|
-
default: "",
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
type: "input",
|
|
225
|
-
name: "vertexKey",
|
|
226
|
-
message: "Enter your Vertex AI API key (optional):",
|
|
227
|
-
default: "",
|
|
228
|
-
},
|
|
229
|
-
]);
|
|
230
|
-
|
|
231
|
-
// Update environment variables with generated values
|
|
232
|
-
const envUpdates = {
|
|
233
|
-
NEXTAUTH_SECRET: generateBase64Secret(),
|
|
234
|
-
JWT_SECRET_KEY: generateBase64Secret(),
|
|
235
|
-
API_CRYPTO_KEY: generateHexSecret(),
|
|
236
|
-
API_JWT_SECRET: generateBase64Secret(),
|
|
237
|
-
API_JWT_REFRESHSECRET: generateBase64Secret(),
|
|
238
|
-
CODE_MANAGEMENT_SECRET: generateHexSecret(),
|
|
239
|
-
CODE_MANAGEMENT_WEBHOOK_TOKEN: generateWebhookToken(),
|
|
240
|
-
API_PG_DB_PASSWORD: generateDbPassword(),
|
|
241
|
-
API_MG_DB_PASSWORD: generateDbPassword(),
|
|
242
|
-
RABBITMQ_DEFAULT_PASS: generateDbPassword(),
|
|
243
|
-
GRAFANA_ADMIN_PASSWORD: generateDbPassword(),
|
|
244
|
-
API_OPEN_AI_APIKEY: llmKeys.openAiKey,
|
|
245
|
-
API_GOOGLE_AI_API_KEY: llmKeys.googleAiKey,
|
|
246
|
-
API_ANTHROPIC_API_KEY: llmKeys.anthropicKey,
|
|
247
|
-
API_NOVITA_AI_API_KEY: llmKeys.novitaKey,
|
|
248
|
-
API_VERTEX_AI_API_KEY: llmKeys.vertexKey,
|
|
249
|
-
...gitConfig,
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
const envSpinner = ora("Updating environment variables").start();
|
|
253
|
-
await updateEnvFile(envUpdates);
|
|
254
|
-
envSpinner.succeed("Environment variables updated");
|
|
255
|
-
|
|
256
|
-
// Create Docker networks
|
|
257
|
-
createDockerNetworks(DOCKER_NETWORKS);
|
|
258
|
-
|
|
259
|
-
// Start containers
|
|
260
|
-
const dockerSpinner = ora("Starting containers").start();
|
|
261
|
-
try {
|
|
262
|
-
execSync("docker-compose up -d", { stdio: "pipe" });
|
|
263
|
-
dockerSpinner.succeed("Containers started");
|
|
264
|
-
} catch (error) {
|
|
265
|
-
dockerSpinner.fail("Failed to start containers");
|
|
266
|
-
console.error(chalk.red("\nError details:"));
|
|
267
|
-
console.error(chalk.white(error.stdout?.toString() || error.message));
|
|
268
|
-
process.exit(1);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Wait for services to be ready
|
|
272
|
-
await waitForService(
|
|
273
|
-
"db_kodus_postgres",
|
|
274
|
-
"database system is ready to accept connections",
|
|
275
|
-
"PostgreSQL failed to start"
|
|
276
|
-
);
|
|
277
|
-
|
|
278
|
-
await waitForService(
|
|
279
|
-
"db_kodus_mongodb",
|
|
280
|
-
"Waiting for connections",
|
|
281
|
-
"MongoDB failed to start"
|
|
282
|
-
);
|
|
283
|
-
|
|
284
|
-
await waitForService(
|
|
285
|
-
"kodus_web",
|
|
286
|
-
"✓ Ready in",
|
|
287
|
-
"Web service failed to start"
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
// Setup database
|
|
291
|
-
const dbSpinner = ora("Setting up database").start();
|
|
292
|
-
try {
|
|
293
|
-
const moduleRoot = dirname(dirname(__dirname)); // Sobe 2 níveis: commands -> src -> root
|
|
294
|
-
const scriptPath = path.join(moduleRoot, 'scripts', 'setup-db.sh');
|
|
295
|
-
|
|
296
|
-
if (!fs.existsSync(scriptPath)) {
|
|
297
|
-
dbSpinner.fail('setup-db.sh script not found!');
|
|
298
|
-
console.error(chalk.red(`\nScript expected at: ${scriptPath}`));
|
|
299
|
-
process.exit(1);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
execSync(`sh ${scriptPath}`, { stdio: "pipe" });
|
|
303
|
-
dbSpinner.succeed("Database setup completed");
|
|
304
|
-
} catch (error) {
|
|
305
|
-
dbSpinner.fail("Failed to setup database");
|
|
306
|
-
console.error(chalk.red("\nError details:"));
|
|
307
|
-
console.error(chalk.white(error.stdout?.toString() || error.message));
|
|
308
|
-
process.exit(1);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Installation complete
|
|
312
|
-
console.log(chalk.green("\n✨ Installation completed successfully!"));
|
|
313
|
-
|
|
314
|
-
console.log(chalk.blue("\n📝 Installation Summary:"));
|
|
315
|
-
console.log(chalk.white(` - Environment: ${envType === "local" ? "Local" : "External"}`));
|
|
316
|
-
if (envType === "external") {
|
|
317
|
-
console.log(chalk.white(` - Base URL: ${baseUrl}`));
|
|
318
|
-
}
|
|
319
|
-
console.log(chalk.white(` - Git Service: ${gitService.charAt(0).toUpperCase() + gitService.slice(1)}`));
|
|
320
|
-
console.log(chalk.white(` - Database: ${useDefaultDb ? "Default configuration" : "Custom configuration"}`));
|
|
321
|
-
|
|
322
|
-
console.log(chalk.blue("\n🔗 Access URLs:"));
|
|
323
|
-
console.log(chalk.white(` - Web Interface: ${baseUrl}`));
|
|
324
|
-
console.log(chalk.white(" - Grafana Dashboard: http://localhost:3001"));
|
|
325
|
-
console.log(chalk.white(" - RabbitMQ Management: http://localhost:15672"));
|
|
326
|
-
|
|
327
|
-
console.log(chalk.blue("\n📚 Next Steps:"));
|
|
328
|
-
console.log(chalk.white(" 1. Access the web interface"));
|
|
329
|
-
console.log(chalk.white(" 2. Set up your first user"));
|
|
330
|
-
console.log(chalk.white(" 3. Start using Kodus!"));
|
|
331
|
-
|
|
332
|
-
const { startServices } = await inquirer.prompt([
|
|
333
|
-
{
|
|
334
|
-
type: "confirm",
|
|
335
|
-
name: "startServices",
|
|
336
|
-
message: "Would you like to start the services now?",
|
|
337
|
-
default: true,
|
|
338
|
-
},
|
|
339
|
-
]);
|
|
340
|
-
|
|
341
|
-
if (startServices) {
|
|
342
|
-
execSync("docker-compose up -d", { stdio: "ignore" });
|
|
343
|
-
|
|
344
|
-
// Wait for web service to be ready after restart
|
|
345
|
-
await waitForService(
|
|
346
|
-
"kodus_web",
|
|
347
|
-
"✓ Ready in",
|
|
348
|
-
"Web service failed to start"
|
|
349
|
-
);
|
|
350
|
-
|
|
351
|
-
console.log(chalk.green("\nServices started successfully!"));
|
|
352
|
-
}
|
|
353
|
-
} catch (error) {
|
|
354
|
-
console.error(chalk.red("\n❌ Installation failed:"), error.message);
|
|
355
|
-
process.exit(1);
|
|
356
|
-
}
|
|
357
|
-
};
|
package/src/config/default.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
export const DEFAULT_CONFIG = {
|
|
2
|
-
// Base configuration
|
|
3
|
-
WEB_NODE_ENV: "development",
|
|
4
|
-
WEB_HOSTNAME_API: "localhost",
|
|
5
|
-
WEB_PORT_API: "3001",
|
|
6
|
-
WEB_PORT: "3000",
|
|
7
|
-
WEB_NEXTAUTH_URL: "http://localhost:3000",
|
|
8
|
-
|
|
9
|
-
API_NODE_ENV: "development",
|
|
10
|
-
API_LOG_LEVEL: "error",
|
|
11
|
-
API_LOG_PRETTY: "true",
|
|
12
|
-
API_HOST: "0.0.0.0",
|
|
13
|
-
API_PORT: "3001",
|
|
14
|
-
API_RATE_MAX_REQUEST: "100",
|
|
15
|
-
API_RATE_INTERVAL: "1000",
|
|
16
|
-
API_JWT_EXPIRES_IN: "365d",
|
|
17
|
-
API_JWT_REFRESH_EXPIRES_IN: "7d",
|
|
18
|
-
|
|
19
|
-
GLOBAL_API_CONTAINER_NAME: "kodus-orchestrator-prod",
|
|
20
|
-
|
|
21
|
-
// Database
|
|
22
|
-
API_DATABASE_ENV: "development",
|
|
23
|
-
API_PG_DB_USERNAME: "kodusdev",
|
|
24
|
-
API_PG_DB_DATABASE: "kodus_db",
|
|
25
|
-
API_PG_DB_HOST: "db_kodus_postgres",
|
|
26
|
-
API_PG_DB_PORT: "5432",
|
|
27
|
-
|
|
28
|
-
API_MG_DB_USERNAME: "kodusdev",
|
|
29
|
-
API_MG_DB_DATABASE: "kodus_db",
|
|
30
|
-
API_MG_DB_HOST: "db_kodus_mongodb",
|
|
31
|
-
API_MG_DB_PORT: "27017",
|
|
32
|
-
API_MG_DB_PRODUCTION_CONFIG: "",
|
|
33
|
-
|
|
34
|
-
// LLM Models
|
|
35
|
-
API_LLM_MODEL_CHATGPT_3_5_TURBO: "gpt-4o-mini",
|
|
36
|
-
API_LLM_MODEL_CHATGPT_3_5_TURBO_16K: "gpt-4o-mini",
|
|
37
|
-
API_LLM_MODEL_CHATGPT_4: "gpt-4o-mini",
|
|
38
|
-
API_LLM_MODEL_CHATGPT_4_TURBO: "gpt-4o-mini",
|
|
39
|
-
API_LLM_MODEL_CHATGPT_4_ALL: "gpt-4o",
|
|
40
|
-
API_LLM_MODEL_CHATGPT_4_ALL_MINI: "gpt-4o-mini",
|
|
41
|
-
API_LLM_MODEL_CLAUDE_3_5_SONNET: "claude-3-5-sonnet-20241022",
|
|
42
|
-
API_LLM_MODEL_CLAUDE_3_5_SONNET_20241022: "claude-3-5-sonnet-20241022",
|
|
43
|
-
API_LLM_MODEL_GEMINI_1_5_PRO: "gpt-4o-mini",
|
|
44
|
-
API_LLM_MODEL_GEMINI_1_5_PRO_EXP: "gpt-4o-mini",
|
|
45
|
-
|
|
46
|
-
// Ports
|
|
47
|
-
WEB_PORT: "3000",
|
|
48
|
-
API_PORT: "3001",
|
|
49
|
-
|
|
50
|
-
// RabbitMQ
|
|
51
|
-
RABBITMQ_DEFAULT_USER: "kodus",
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export const DOCKER_NETWORKS = [
|
|
55
|
-
'shared-network',
|
|
56
|
-
'monitoring-network',
|
|
57
|
-
'kodus-backend-services'
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
export const CRITICAL_ERRORS = [
|
|
61
|
-
"password authentication failed",
|
|
62
|
-
"Unable to connect to the database",
|
|
63
|
-
"FATAL:",
|
|
64
|
-
"MongoServerError:",
|
|
65
|
-
"connection refused"
|
|
66
|
-
];
|
package/src/utils/helpers.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import crypto from 'crypto';
|
|
2
|
-
import fs from 'fs-extra';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { execSync } from 'child_process';
|
|
5
|
-
import ora from 'ora';
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
import { fileURLToPath } from 'url';
|
|
8
|
-
import { dirname } from 'path';
|
|
9
|
-
|
|
10
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
-
const __dirname = dirname(__filename);
|
|
12
|
-
|
|
13
|
-
// Base64 secret key (for JWT and auth)
|
|
14
|
-
export const generateBase64Secret = () => crypto.randomBytes(32).toString('base64');
|
|
15
|
-
|
|
16
|
-
// Hex secret key (for crypto and management)
|
|
17
|
-
export const generateHexSecret = () => crypto.randomBytes(32).toString('hex');
|
|
18
|
-
|
|
19
|
-
// URL-safe base64 secret (for webhook tokens)
|
|
20
|
-
export const generateWebhookToken = () => {
|
|
21
|
-
const base64 = crypto.randomBytes(32).toString('base64');
|
|
22
|
-
return base64.replace(/=/g, '').replace(/\+/g, '_').replace(/\//g, '-');
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const generateDbPassword = () =>
|
|
26
|
-
crypto
|
|
27
|
-
.randomBytes(16)
|
|
28
|
-
.toString("base64")
|
|
29
|
-
.replace(/[^a-zA-Z0-9]/g, "")
|
|
30
|
-
.slice(0, 16);
|
|
31
|
-
|
|
32
|
-
export const copyTemplates = (targetDir) => {
|
|
33
|
-
try {
|
|
34
|
-
const moduleDir = dirname(dirname(dirname(__filename))); // Sobe 3 níveis: utils -> src -> root
|
|
35
|
-
const templatesDir = path.join(moduleDir, 'templates');
|
|
36
|
-
|
|
37
|
-
if (!fs.existsSync(templatesDir)) {
|
|
38
|
-
console.error(chalk.red(`Templates directory not found at: ${templatesDir}`));
|
|
39
|
-
console.error(chalk.yellow('Current directory structure:'));
|
|
40
|
-
console.error(chalk.white(fs.readdirSync(moduleDir)));
|
|
41
|
-
throw new Error('Templates directory not found');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const sourceFile = path.join(templatesDir, 'docker-compose.yml');
|
|
45
|
-
const targetFile = path.join(targetDir, 'docker-compose.yml');
|
|
46
|
-
|
|
47
|
-
if (!fs.existsSync(sourceFile)) {
|
|
48
|
-
console.error(chalk.red(`Template file not found at: ${sourceFile}`));
|
|
49
|
-
console.error(chalk.yellow('Files in templates directory:'));
|
|
50
|
-
console.error(chalk.white(fs.readdirSync(templatesDir)));
|
|
51
|
-
throw new Error('Template file not found');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
fs.copySync(sourceFile, targetFile);
|
|
55
|
-
} catch (error) {
|
|
56
|
-
console.error(chalk.red('Error copying templates:'), error);
|
|
57
|
-
throw error;
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export const backupEnv = () => {
|
|
62
|
-
const envPath = path.join(process.cwd(), '.env');
|
|
63
|
-
if (fs.existsSync(envPath)) {
|
|
64
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
65
|
-
const backupPath = path.join(process.cwd(), `.env.backup.${timestamp}`);
|
|
66
|
-
fs.copySync(envPath, backupPath);
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
return false;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export const restoreEnv = (backupFile) => {
|
|
73
|
-
const backupPath = path.join(process.cwd(), backupFile);
|
|
74
|
-
if (fs.existsSync(backupPath)) {
|
|
75
|
-
const envPath = path.join(process.cwd(), '.env');
|
|
76
|
-
fs.copySync(backupPath, envPath);
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
return false;
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export const getLatestVersion = () => {
|
|
83
|
-
try {
|
|
84
|
-
const result = execSync("git describe --tags --abbrev=0", { stdio: "pipe" })
|
|
85
|
-
.toString()
|
|
86
|
-
.trim();
|
|
87
|
-
return result;
|
|
88
|
-
} catch (error) {
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
export const getCurrentVersion = () => {
|
|
94
|
-
try {
|
|
95
|
-
const result = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
96
|
-
stdio: "pipe",
|
|
97
|
-
})
|
|
98
|
-
.toString()
|
|
99
|
-
.trim();
|
|
100
|
-
return result;
|
|
101
|
-
} catch (error) {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
export const createDockerNetworks = (networks) => {
|
|
107
|
-
const networkSpinner = ora("Creating Docker networks").start();
|
|
108
|
-
|
|
109
|
-
for (const network of networks) {
|
|
110
|
-
try {
|
|
111
|
-
// Check if network exists
|
|
112
|
-
execSync(`docker network inspect ${network}`, { stdio: 'ignore' });
|
|
113
|
-
} catch (error) {
|
|
114
|
-
// Network doesn't exist, create it
|
|
115
|
-
try {
|
|
116
|
-
execSync(`docker network create ${network}`, { stdio: 'pipe' });
|
|
117
|
-
console.log(chalk.green(`\nCreated network: ${network}`));
|
|
118
|
-
} catch (createError) {
|
|
119
|
-
networkSpinner.fail(`Failed to create network: ${network}`);
|
|
120
|
-
console.error(chalk.red("\nError details:"));
|
|
121
|
-
console.error(chalk.white(createError.stdout?.toString() || createError.message));
|
|
122
|
-
process.exit(1);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
networkSpinner.succeed("Docker networks created");
|
|
128
|
-
};
|
package/templates/.env.example
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# =============================================
|
|
2
|
-
# Environment Configuration Example File
|
|
3
|
-
# Copy this file to .env and adjust the values
|
|
4
|
-
# =============================================
|
|
5
|
-
|
|
6
|
-
## ---- BASIC SYSTEM CONFIGURATION ----
|
|
7
|
-
|
|
8
|
-
# Web Application Settings
|
|
9
|
-
WEB_NODE_ENV="self-hosted" # self-hosted, development, production
|
|
10
|
-
WEB_HOSTNAME_API="localhost" # API hostname
|
|
11
|
-
WEB_PORT_API=3001 # API port
|
|
12
|
-
WEB_PORT=3000 # Web application port
|
|
13
|
-
GLOBAL_API_CONTAINER_NAME="kodus-orchestrator" # API container name
|
|
14
|
-
|
|
15
|
-
# Authentication Settings
|
|
16
|
-
NEXTAUTH_URL="http://localhost:3000" # Base URL for authentication
|
|
17
|
-
NEXTAUTH_SECRET="" # NextAuth secret key (generate with: openssl rand -base64 32)
|
|
18
|
-
JWT_SECRET_KEY="" # JWT secret key (generate with: openssl rand -base64 32)
|
|
19
|
-
|
|
20
|
-
## ---- API CONFIGURATION ----
|
|
21
|
-
|
|
22
|
-
# General API Settings
|
|
23
|
-
API_NODE_ENV="development" # development, production, test
|
|
24
|
-
API_LOG_LEVEL=error # error, warn, info, debug
|
|
25
|
-
API_LOG_PRETTY=true # Log formatting
|
|
26
|
-
API_HOST=0.0.0.0 # API host
|
|
27
|
-
API_PORT=3001 # API port
|
|
28
|
-
API_RATE_MAX_REQUEST=100 # Request rate limit
|
|
29
|
-
API_RATE_INTERVAL=1000 # Rate limit interval in ms
|
|
30
|
-
API_CLOUD_MODE=false # Enable/disable cloud mode
|
|
31
|
-
API_CRYPTO_KEY= # Crypto key for encryption/decryption
|
|
32
|
-
|
|
33
|
-
# JWT Configuration
|
|
34
|
-
API_JWT_EXPIRES_IN=365d # Token expiration time
|
|
35
|
-
API_JWT_SECRET=secret # JWT secret key
|
|
36
|
-
API_JWT_REFRESHSECRET=refreshSecret # Refresh token secret key
|
|
37
|
-
API_JWT_REFRESH_EXPIRES_IN=7d # Refresh token expiration time
|
|
38
|
-
|
|
39
|
-
## ---- DATABASE CONFIGURATION ----
|
|
40
|
-
|
|
41
|
-
# PostgreSQL Settings
|
|
42
|
-
API_DATABASE_ENV="development" # development, production, test
|
|
43
|
-
API_PG_DB_HOST=db_kodus_postgres # PostgreSQL host
|
|
44
|
-
API_PG_DB_PORT=5432 # PostgreSQL port
|
|
45
|
-
API_PG_DB_USERNAME=kodusdev # Database username
|
|
46
|
-
API_PG_DB_PASSWORD= # Database password
|
|
47
|
-
API_PG_DB_DATABASE=kodus_db # Database name
|
|
48
|
-
|
|
49
|
-
# MongoDB Settings
|
|
50
|
-
API_MG_DB_HOST=db_kodus_mongodb # MongoDB host
|
|
51
|
-
API_MG_DB_PORT=27017 # MongoDB port
|
|
52
|
-
API_MG_DB_USERNAME=kodusdev # Database username
|
|
53
|
-
API_MG_DB_PASSWORD= # Database password
|
|
54
|
-
API_MG_DB_DATABASE=kodus # Database name
|
|
55
|
-
API_MG_DB_PRODUCTION_CONFIG='' # Additional production settings
|
|
56
|
-
|
|
57
|
-
## ---- LLM API KEYS ----
|
|
58
|
-
|
|
59
|
-
# API Keys for LLM Providers
|
|
60
|
-
API_OPEN_AI_APIKEY= # OpenAI API key
|
|
61
|
-
API_GOOGLE_AI_API_KEY= # Google AI API key
|
|
62
|
-
API_ANTHROPIC_API_KEY= # Anthropic API key
|
|
63
|
-
API_NOVITA_AI_API_KEY= # Novita AI API key
|
|
64
|
-
API_VERTEX_AI_API_KEY= # Vertex AI API key
|
|
65
|
-
|
|
66
|
-
# Available LLM Models
|
|
67
|
-
API_LLM_MODEL_CHATGPT_3_5_TURBO=gpt-4o-mini
|
|
68
|
-
API_LLM_MODEL_CHATGPT_3_5_TURBO_16K=gpt-4o-mini
|
|
69
|
-
API_LLM_MODEL_CHATGPT_4=gpt-4o-mini
|
|
70
|
-
API_LLM_MODEL_CHATGPT_4_TURBO=gpt-4o-mini
|
|
71
|
-
API_LLM_MODEL_CHATGPT_4_ALL=gpt-4o
|
|
72
|
-
API_LLM_MODEL_CHATGPT_4_ALL_MINI=gpt-4o-mini
|
|
73
|
-
API_LLM_MODEL_CLAUDE_3_5_SONNET=claude-3-5-sonnet-20241022
|
|
74
|
-
API_LLM_MODEL_CLAUDE_3_5_SONNET_20241022=claude-3-5-sonnet-20241022
|
|
75
|
-
API_LLM_MODEL_GEMINI_1_5_PRO=gpt-4o-mini
|
|
76
|
-
API_LLM_MODEL_GEMINI_1_5_PRO_EXP=gpt-4o-mini
|
|
77
|
-
|
|
78
|
-
## ---- CRON CONFIGURATION ----
|
|
79
|
-
# Format: minute hour day_of_month month day_of_week
|
|
80
|
-
# Example: 0 1 * * 5 = Every Friday at 01:00
|
|
81
|
-
|
|
82
|
-
API_CRON_AUTOMATION_INTERACTION_MONITOR=0 1 * * 5
|
|
83
|
-
API_CRON_AUTOMATION_ISSUES_DETAILS=0 1 * * 5
|
|
84
|
-
API_CRON_COMPILE_SPRINT=0 1 * * 5
|
|
85
|
-
API_CRON_METRICS=* 5 * * *
|
|
86
|
-
API_CRON_AUTOMATION_DAILY_CHECKIN=* 5 * * *
|
|
87
|
-
API_CRON_SPRINT_RETRO=* 5 * * *
|
|
88
|
-
API_CRON_TEAM_ARTIFACTS_WEEKLY=* 5 * * *
|
|
89
|
-
API_CRON_TEAM_ARTIFACTS_DAILY=* 5 * * *
|
|
90
|
-
API_CRON_AUTOMATION_TEAM_PROGRESS_TRACKER=* 5 * * *
|
|
91
|
-
API_CRON_ORGANIZATION_METRICS=* 5 * * *
|
|
92
|
-
API_CRON_AUTOMATION_EXECUTIVE_CHECKIN=* 5 * * *
|
|
93
|
-
API_CRON_ORGANIZATION_ARTIFACTS_WEEKLY=* 5 * * *
|
|
94
|
-
API_CRON_ORGANIZATION_ARTIFACTS_DAILY=* 5 * * *
|
|
95
|
-
API_CRON_ENRICH_TEAM_ARTIFACTS_WEEKLY=* 5 * * *
|
|
96
|
-
API_CRON_SYNC_CODE_REVIEW_REACTIONS=* 5 * * *
|
|
97
|
-
API_CRON_KODY_LEARNING=0 0 * * 6
|
|
98
|
-
API_CRON_CHECK_IF_PR_SHOULD_BE_APPROVED=/2 * * * # A CADA 2 MINUTOS;
|
|
99
|
-
## ---- GIT INTEGRATIONS ----
|
|
100
|
-
|
|
101
|
-
CODE_MANAGEMENT_SECRET=
|
|
102
|
-
CODE_MANAGEMENT_WEBHOOK_TOKEN=
|
|
103
|
-
|
|
104
|
-
# GitHub Settings (Fill only if using GitHub)
|
|
105
|
-
API_GITHUB_CODE_MANAGEMENT_WEBHOOK= # GitHub webhook URL
|
|
106
|
-
API_GITHUB_APP_ID= # GitHub App ID
|
|
107
|
-
API_GITHUB_CLIENT_SECRET= # GitHub App Client Secret
|
|
108
|
-
API_GITHUB_PRIVATE_KEY="" # GitHub App Private Key
|
|
109
|
-
WEB_GITHUB_INSTALL_URL="" # GitHub App Installation URL
|
|
110
|
-
WEB_OAUTH_GITHUB_CLIENT_ID="" # GitHub OAuth Client ID
|
|
111
|
-
WEB_OAUTH_GITHUB_CLIENT_SECRET="" # GitHub OAuth Client Secret
|
|
112
|
-
|
|
113
|
-
# GitLab Settings (Fill only if using GitLab)
|
|
114
|
-
API_GITLAB_TOKEN_URL="https://gitlab.com/oauth/token"
|
|
115
|
-
API_GITLAB_CODE_MANAGEMENT_WEBHOOK= # GitLab webhook URL
|
|
116
|
-
WEB_GITLAB_SCOPES="read_api read_user read_repository"
|
|
117
|
-
WEB_GITLAB_OAUTH_URL="https://gitlab.com/oauth/authorize"
|
|
118
|
-
WEB_OAUTH_GITLAB_CLIENT_ID="" # GitLab OAuth Client ID
|
|
119
|
-
WEB_OAUTH_GITLAB_CLIENT_SECRET="" # GitLab OAuth Client Secret
|
|
120
|
-
|
|
121
|
-
# Bitbucket Settings (Fill only if using Bitbucket)
|
|
122
|
-
WEB_BITBUCKET_INSTALL_URL="" # Bitbucket Installation URL
|
|
123
|
-
GLOBAL_BITBUCKET_CODE_MANAGEMENT_WEBHOOK= # Bitbucket webhook URL
|
|
124
|
-
|
|
125
|
-
## ---- ADDITIONAL INTEGRATIONS ----
|
|
126
|
-
|
|
127
|
-
# Communication Integrations
|
|
128
|
-
WEB_CONNECTION_SLACK="" # Slack connection URL
|
|
129
|
-
WEB_CONNECTION_DISCORD="" # Discord connection URL
|
|
130
|
-
|
|
131
|
-
# JIRA Integration
|
|
132
|
-
WEB_JIRA_SCOPES="read%3Aissue-type%3Ajira%20read%3Aproject%3Ajira%20read%3Aproject.property%3Ajira%20read%3Auser%3Ajira%20read%3Aapplication-role%3Ajira%20read%3Aavatar%3Ajira%20read%3Agroup%3Ajira%20read%3Aissue-type-hierarchy%3Ajira%20read%3Aproject-category%3Ajira%20read%3Aproject-version%3Ajira%20read%3Aproject.component%3Ajira%20read%3Aissue-details%3Ajira%20read%3Aaudit-log%3Ajira%20read%3Afield-configuration%3Ajira%20read%3Aissue-meta%3Ajira%20read%3Aissue-security-level%3Ajira%20read%3Aissue.vote%3Ajira%20read%3Aissue.changelog%3Ajira%20read%3Aissue%3Ajira%20read%3Astatus%3Ajira%20read%3Afield%3Ajira%20write%3Awebhook%3Ajira%20read%3Awebhook%3Ajira%20read%3Aissue-status%3Ajira%20read%3Aboard-scope.admin%3Ajira-software%20read%3Ajql%3Ajira%20delete%3Awebhook%3Ajira%20read%3Acomment.property%3Ajira%20read%3Aproject-role%3Ajira%20read%3Aepic%3Ajira-software%20read%3Aboard-scope%3Ajira-software%20read%3Asprint%3Ajira-software%20read%3Afield.default-value%3Ajira%20read%3Afield.option%3Ajira%20read%3Aissue%3Ajira-software%20read%3Acomment%3Ajira%20read%3Aattachment%3Ajira%20read%3Aissue-worklog%3Ajira%20write%3Aissue-link-type%3Ajira%20write%3Afield%3Ajira%20write%3Aworkflow%3Ajira%20write%3Aproject%3Ajira"
|
|
133
|
-
|
|
134
|
-
# Support Settings
|
|
135
|
-
WEB_ANALYTICS_HOSTNAME="" # Analytics hostname
|
|
136
|
-
WEB_SUPPORT_DOCS_URL="https://docs.kodus.io" # Documentation URL
|
|
137
|
-
WEB_SUPPORT_DISCORD_INVITE_URL="https://discord.gg/CceCdAke" # Discord invite URL
|
|
138
|
-
WEB_SUPPORT_TALK_TO_FOUNDER_URL="https://cal.com/gabrielmalinosqui/30min" # Scheduling URL
|
|
139
|
-
|
|
140
|
-
# RabbitMQ Configuration
|
|
141
|
-
API_RABBITMQ_URI= # RabbitMQ connection URI
|
|
142
|
-
API_RABBITMQ_ENABLED=false # Enable/disable RabbitMQ
|