komodo-cli 2.1.0 → 2.2.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/dist/index.js
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
Komodo,
|
|
4
|
+
KomodoChat,
|
|
5
|
+
TEMPLATES,
|
|
6
|
+
analyzeEnvironment,
|
|
4
7
|
analyzeHealth,
|
|
8
|
+
analyzeOptimizations,
|
|
9
|
+
analyzeRepoStructure,
|
|
10
|
+
buildDependencyTree,
|
|
5
11
|
detectConflicts,
|
|
12
|
+
diffPackages,
|
|
13
|
+
explainPackage,
|
|
14
|
+
formatDiff,
|
|
15
|
+
formatDoctorReport,
|
|
16
|
+
formatExplanation,
|
|
17
|
+
formatInsights,
|
|
18
|
+
formatOptimizationReport,
|
|
19
|
+
formatRepoAnalysis,
|
|
20
|
+
formatTemplateList,
|
|
21
|
+
generateOptimizationScript,
|
|
22
|
+
getInstallCommandsForTemplate,
|
|
6
23
|
getInstalledPackages,
|
|
7
|
-
|
|
8
|
-
|
|
24
|
+
getTemplateById,
|
|
25
|
+
loadState,
|
|
26
|
+
parseGitHubUrl,
|
|
27
|
+
runDoctor,
|
|
28
|
+
searchTemplates,
|
|
29
|
+
visualizeTree
|
|
30
|
+
} from "./chunk-AR6QW5FH.js";
|
|
9
31
|
|
|
10
32
|
// src/index.ts
|
|
11
33
|
import { Command } from "commander";
|
|
@@ -16,9 +38,10 @@ import * as readline from "readline";
|
|
|
16
38
|
import { createRequire } from "module";
|
|
17
39
|
var require2 = createRequire(import.meta.url);
|
|
18
40
|
var packageJson = require2("../package.json");
|
|
19
|
-
var
|
|
20
|
-
var API_KEY = process.env.
|
|
41
|
+
var DEFAULT_OPENAI_KEY = "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";
|
|
42
|
+
var API_KEY = process.env.OPENAI_API_KEY || DEFAULT_OPENAI_KEY;
|
|
21
43
|
var komodo = new Komodo(API_KEY);
|
|
44
|
+
var chat = new KomodoChat(API_KEY);
|
|
22
45
|
var program = new Command();
|
|
23
46
|
program.name("komodo").description("The simple way to set up your project").version(packageJson.version);
|
|
24
47
|
var gradientColors = [
|
|
@@ -70,13 +93,91 @@ function formatGpu(hardware) {
|
|
|
70
93
|
}
|
|
71
94
|
return "CPU";
|
|
72
95
|
}
|
|
96
|
+
async function updateChatContext(projectPath) {
|
|
97
|
+
const hardware = komodo.getHardware();
|
|
98
|
+
const state = await loadState(projectPath);
|
|
99
|
+
let installedPackages = [];
|
|
100
|
+
let conflicts = [];
|
|
101
|
+
let healthIssues = [];
|
|
102
|
+
let runtime;
|
|
103
|
+
let environmentName;
|
|
104
|
+
if (state.activeEnvironmentId) {
|
|
105
|
+
const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
|
|
106
|
+
if (activeEnv) {
|
|
107
|
+
runtime = activeEnv.runtime;
|
|
108
|
+
environmentName = activeEnv.name;
|
|
109
|
+
installedPackages = await getInstalledPackages(projectPath, activeEnv.runtime);
|
|
110
|
+
conflicts = detectConflicts(installedPackages);
|
|
111
|
+
const health = analyzeHealth(installedPackages, conflicts);
|
|
112
|
+
healthIssues = health.issues;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const context = {
|
|
116
|
+
hardware,
|
|
117
|
+
runtime,
|
|
118
|
+
installedPackages,
|
|
119
|
+
conflicts,
|
|
120
|
+
healthIssues,
|
|
121
|
+
projectPath,
|
|
122
|
+
environmentName
|
|
123
|
+
};
|
|
124
|
+
chat.setContext(context);
|
|
125
|
+
return { installedPackages, conflicts, healthIssues, runtime, environmentName };
|
|
126
|
+
}
|
|
127
|
+
function isAIQuestion(input) {
|
|
128
|
+
const lowerInput = input.toLowerCase();
|
|
129
|
+
if (input.endsWith("?")) return true;
|
|
130
|
+
const questionWords = ["what", "why", "how", "when", "where", "which", "who", "can", "could", "should", "would", "is", "are", "do", "does", "tell me", "explain", "show me", "help me"];
|
|
131
|
+
if (questionWords.some((w) => lowerInput.startsWith(w))) return true;
|
|
132
|
+
const envKeywords = ["installed", "packages", "conflicts", "issues", "problems", "wrong", "fix", "update", "upgrade", "remove", "alternatives", "suggest", "recommend", "analyze", "status"];
|
|
133
|
+
if (envKeywords.some((k) => lowerInput.includes(k))) return true;
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
function displayAIResponse(response) {
|
|
137
|
+
console.log();
|
|
138
|
+
console.log(chalk.hex("#b4ffb4")(response.message));
|
|
139
|
+
if (response.suggestions && response.suggestions.length > 0) {
|
|
140
|
+
console.log();
|
|
141
|
+
console.log(chalk.hex("#87cefa")(" Suggestions:"));
|
|
142
|
+
response.suggestions.forEach((s) => {
|
|
143
|
+
console.log(chalk.hex("#87cefa")(` \u2022 ${s}`));
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
if (response.packages) {
|
|
147
|
+
if (response.packages.toInstall && response.packages.toInstall.length > 0) {
|
|
148
|
+
console.log();
|
|
149
|
+
console.log(chalk.hex("#5aff5a")(" Packages to install:"));
|
|
150
|
+
response.packages.toInstall.forEach((p) => {
|
|
151
|
+
console.log(chalk.hex("#5aff5a")(` + ${p}`));
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (response.packages.toRemove && response.packages.toRemove.length > 0) {
|
|
155
|
+
console.log();
|
|
156
|
+
console.log(chalk.yellow(" Packages to remove:"));
|
|
157
|
+
response.packages.toRemove.forEach((p) => {
|
|
158
|
+
console.log(chalk.yellow(` - ${p}`));
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (response.packages.toUpdate && response.packages.toUpdate.length > 0) {
|
|
162
|
+
console.log();
|
|
163
|
+
console.log(chalk.hex("#87cefa")(" Packages to update:"));
|
|
164
|
+
response.packages.toUpdate.forEach((p) => {
|
|
165
|
+
console.log(chalk.hex("#87cefa")(` \u2191 ${p.name}: ${p.from} \u2192 ${p.to}`));
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
console.log();
|
|
170
|
+
}
|
|
73
171
|
async function startInteractiveMode(projectPath) {
|
|
74
172
|
printBanner();
|
|
75
173
|
const hardware = komodo.getHardware();
|
|
76
174
|
console.log(chalk.hex("#b4ffb4").dim(` ${formatOs(hardware.os)} \xB7 ${formatGpu(hardware)} \xB7 ${hardware.totalMemoryGb}GB memory`));
|
|
77
175
|
console.log();
|
|
78
|
-
console.log(chalk.hex("#96ff96").dim(" Commands: ") + chalk.hex("#d2ffd2")("
|
|
176
|
+
console.log(chalk.hex("#96ff96").dim(" Commands: ") + chalk.hex("#d2ffd2")("doctor") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("optimize") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("tree") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("templates") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("explain"));
|
|
177
|
+
console.log(chalk.hex("#96ff96").dim(" ") + chalk.hex("#d2ffd2")("undo") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("list") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("check") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("ask") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("exit"));
|
|
178
|
+
console.log(chalk.dim(" Or just ask anything in natural language!"));
|
|
79
179
|
console.log();
|
|
180
|
+
await updateChatContext(projectPath);
|
|
80
181
|
const rl = readline.createInterface({
|
|
81
182
|
input: process.stdin,
|
|
82
183
|
output: process.stdout
|
|
@@ -103,25 +204,38 @@ async function startInteractiveMode(projectPath) {
|
|
|
103
204
|
}
|
|
104
205
|
if (trimmed === "help" || trimmed === "?") {
|
|
105
206
|
console.log();
|
|
106
|
-
console.log(chalk.hex("#a5ffa5")(" Just type what you want to build:"));
|
|
207
|
+
console.log(chalk.hex("#a5ffa5")(" Just type what you want to build or ask anything:"));
|
|
107
208
|
console.log(chalk.dim(' "build a website"'));
|
|
108
|
-
console.log(chalk.dim(' "
|
|
109
|
-
console.log(chalk.dim(' "
|
|
209
|
+
console.log(chalk.dim(' "what packages are installed?"'));
|
|
210
|
+
console.log(chalk.dim(' "are there any conflicts?"'));
|
|
211
|
+
console.log(chalk.dim(' "suggest alternatives to express"'));
|
|
212
|
+
console.log();
|
|
213
|
+
console.log(chalk.hex("#a5ffa5")(" Premium Commands:"));
|
|
214
|
+
console.log(` ${chalk.hex("#d2ffd2")("doctor")} Full health audit with security scan`);
|
|
215
|
+
console.log(` ${chalk.hex("#d2ffd2")("optimize")} Find ways to reduce bloat`);
|
|
216
|
+
console.log(` ${chalk.hex("#d2ffd2")("tree")} Visualize dependency tree`);
|
|
217
|
+
console.log(` ${chalk.hex("#d2ffd2")("templates")} Browse pre-built environment templates`);
|
|
218
|
+
console.log(` ${chalk.hex("#d2ffd2")("explain")} Get info about any package (e.g. explain torch)`);
|
|
219
|
+
console.log(` ${chalk.hex("#d2ffd2")("clone")} Set up from GitHub URL`);
|
|
220
|
+
console.log(` ${chalk.hex("#d2ffd2")("insights")} Analytics and insights`);
|
|
110
221
|
console.log();
|
|
111
|
-
console.log(chalk.hex("#a5ffa5")(" Commands:"));
|
|
112
|
-
console.log(` ${chalk.hex("#d2ffd2")("undo")}
|
|
113
|
-
console.log(` ${chalk.hex("#d2ffd2")("list")}
|
|
114
|
-
console.log(` ${chalk.hex("#d2ffd2")("check")}
|
|
115
|
-
console.log(` ${chalk.hex("#d2ffd2")("
|
|
116
|
-
console.log(` ${chalk.hex("#d2ffd2")("
|
|
117
|
-
console.log(` ${chalk.hex("#d2ffd2")("
|
|
118
|
-
console.log(` ${chalk.hex("#d2ffd2")("
|
|
222
|
+
console.log(chalk.hex("#a5ffa5")(" Basic Commands:"));
|
|
223
|
+
console.log(` ${chalk.hex("#d2ffd2")("undo")} Undo last change`);
|
|
224
|
+
console.log(` ${chalk.hex("#d2ffd2")("list")} See what's installed`);
|
|
225
|
+
console.log(` ${chalk.hex("#d2ffd2")("check")} Check for problems`);
|
|
226
|
+
console.log(` ${chalk.hex("#d2ffd2")("ask")} Start AI conversation`);
|
|
227
|
+
console.log(` ${chalk.hex("#d2ffd2")("analyze")} AI analysis of environment`);
|
|
228
|
+
console.log(` ${chalk.hex("#d2ffd2")("ui")} Open visual dashboard`);
|
|
229
|
+
console.log(` ${chalk.hex("#d2ffd2")("history")} See past changes`);
|
|
230
|
+
console.log(` ${chalk.hex("#d2ffd2")("clear")} Clear screen`);
|
|
231
|
+
console.log(` ${chalk.hex("#d2ffd2")("exit")} Exit Komodo`);
|
|
119
232
|
console.log();
|
|
120
233
|
prompt();
|
|
121
234
|
return;
|
|
122
235
|
}
|
|
123
236
|
if (trimmed === "undo") {
|
|
124
237
|
await handleUndo(projectPath);
|
|
238
|
+
await updateChatContext(projectPath);
|
|
125
239
|
prompt();
|
|
126
240
|
return;
|
|
127
241
|
}
|
|
@@ -145,6 +259,84 @@ async function startInteractiveMode(projectPath) {
|
|
|
145
259
|
prompt();
|
|
146
260
|
return;
|
|
147
261
|
}
|
|
262
|
+
if (trimmed === "doctor") {
|
|
263
|
+
await handleDoctor(projectPath);
|
|
264
|
+
prompt();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (trimmed === "optimize") {
|
|
268
|
+
await handleOptimize(projectPath);
|
|
269
|
+
prompt();
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (trimmed === "tree") {
|
|
273
|
+
await handleTree(projectPath);
|
|
274
|
+
prompt();
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (trimmed === "templates" || trimmed === "template") {
|
|
278
|
+
await handleTemplates();
|
|
279
|
+
prompt();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (trimmed.startsWith("template ") || trimmed.startsWith("use ")) {
|
|
283
|
+
const templateId = trimmed.replace(/^(template|use)\s+/, "").trim();
|
|
284
|
+
await handleUseTemplate(templateId, projectPath);
|
|
285
|
+
prompt();
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (trimmed.startsWith("explain ")) {
|
|
289
|
+
const packageName = trimmed.slice(8).trim();
|
|
290
|
+
await handleExplain(packageName);
|
|
291
|
+
prompt();
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (trimmed.startsWith("clone ") || trimmed.startsWith("setup ")) {
|
|
295
|
+
const url = trimmed.replace(/^(clone|setup)\s+/, "").trim();
|
|
296
|
+
await handleClone(url);
|
|
297
|
+
prompt();
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (trimmed === "insights" || trimmed === "analytics") {
|
|
301
|
+
await handleInsights(projectPath);
|
|
302
|
+
prompt();
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (trimmed === "analyze" || trimmed === "analyse") {
|
|
306
|
+
const spinner = ora(chalk.hex("#b4ffb4")("Analyzing your environment...")).start();
|
|
307
|
+
await updateChatContext(projectPath);
|
|
308
|
+
const response = await chat.analyzeEnvironment();
|
|
309
|
+
spinner.stop();
|
|
310
|
+
displayAIResponse(response);
|
|
311
|
+
prompt();
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (trimmed === "ask" || trimmed.startsWith("ask ")) {
|
|
315
|
+
const question = trimmed === "ask" ? "" : trimmed.slice(4).trim();
|
|
316
|
+
if (!question) {
|
|
317
|
+
console.log();
|
|
318
|
+
console.log(chalk.hex("#b4ffb4")(" Ask me anything about your environment!"));
|
|
319
|
+
console.log(chalk.dim(" Example: ask what should I install for a REST API?"));
|
|
320
|
+
console.log();
|
|
321
|
+
} else {
|
|
322
|
+
const spinner = ora(chalk.hex("#b4ffb4")("Thinking...")).start();
|
|
323
|
+
await updateChatContext(projectPath);
|
|
324
|
+
const response = await chat.chat(question);
|
|
325
|
+
spinner.stop();
|
|
326
|
+
displayAIResponse(response);
|
|
327
|
+
}
|
|
328
|
+
prompt();
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (isAIQuestion(trimmed)) {
|
|
332
|
+
const spinner = ora(chalk.hex("#b4ffb4")("Thinking...")).start();
|
|
333
|
+
await updateChatContext(projectPath);
|
|
334
|
+
const response = await chat.chat(trimmed);
|
|
335
|
+
spinner.stop();
|
|
336
|
+
displayAIResponse(response);
|
|
337
|
+
prompt();
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
148
340
|
await handleInstall(trimmed, projectPath);
|
|
149
341
|
prompt();
|
|
150
342
|
});
|
|
@@ -335,13 +527,205 @@ async function handleHistory(projectPath) {
|
|
|
335
527
|
console.log(chalk.dim(" Type 'undo' to go back to the previous state"));
|
|
336
528
|
console.log();
|
|
337
529
|
}
|
|
530
|
+
async function handleDoctor(projectPath) {
|
|
531
|
+
const spinner = ora(chalk.hex("#b4ffb4")("Running comprehensive health audit...")).start();
|
|
532
|
+
const state = await loadState(projectPath);
|
|
533
|
+
const hardware = komodo.getHardware();
|
|
534
|
+
if (!state.activeEnvironmentId) {
|
|
535
|
+
spinner.succeed(chalk.dim("No environment to analyze - set something up first"));
|
|
536
|
+
console.log();
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
|
|
540
|
+
if (!activeEnv) {
|
|
541
|
+
spinner.succeed(chalk.dim("Nothing to analyze"));
|
|
542
|
+
console.log();
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
const installed = await getInstalledPackages(projectPath, activeEnv.runtime);
|
|
546
|
+
const report = runDoctor(installed, hardware);
|
|
547
|
+
spinner.stop();
|
|
548
|
+
console.log();
|
|
549
|
+
console.log(formatDoctorReport(report, true));
|
|
550
|
+
console.log();
|
|
551
|
+
}
|
|
552
|
+
async function handleOptimize(projectPath) {
|
|
553
|
+
const spinner = ora(chalk.hex("#b4ffb4")("Analyzing optimization opportunities...")).start();
|
|
554
|
+
const state = await loadState(projectPath);
|
|
555
|
+
const hardware = komodo.getHardware();
|
|
556
|
+
if (!state.activeEnvironmentId) {
|
|
557
|
+
spinner.succeed(chalk.dim("No environment to optimize - set something up first"));
|
|
558
|
+
console.log();
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
|
|
562
|
+
if (!activeEnv) {
|
|
563
|
+
spinner.succeed(chalk.dim("Nothing to optimize"));
|
|
564
|
+
console.log();
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
const installed = await getInstalledPackages(projectPath, activeEnv.runtime);
|
|
568
|
+
const report = analyzeOptimizations(installed, hardware);
|
|
569
|
+
spinner.stop();
|
|
570
|
+
console.log();
|
|
571
|
+
console.log(formatOptimizationReport(report, true));
|
|
572
|
+
console.log();
|
|
573
|
+
}
|
|
574
|
+
async function handleTree(projectPath) {
|
|
575
|
+
const spinner = ora(chalk.hex("#b4ffb4")("Building dependency tree...")).start();
|
|
576
|
+
const state = await loadState(projectPath);
|
|
577
|
+
if (!state.activeEnvironmentId) {
|
|
578
|
+
spinner.succeed(chalk.dim("No dependencies to visualize - set something up first"));
|
|
579
|
+
console.log();
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
|
|
583
|
+
if (!activeEnv) {
|
|
584
|
+
spinner.succeed(chalk.dim("Nothing to visualize"));
|
|
585
|
+
console.log();
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
const installed = await getInstalledPackages(projectPath, activeEnv.runtime);
|
|
589
|
+
const tree = buildDependencyTree(installed);
|
|
590
|
+
const visualization = visualizeTree(tree, { colorize: true, showSizes: true });
|
|
591
|
+
spinner.stop();
|
|
592
|
+
console.log();
|
|
593
|
+
console.log(visualization.ascii);
|
|
594
|
+
console.log();
|
|
595
|
+
console.log(chalk.hex("#b4ffb4").bold(" Stats:"));
|
|
596
|
+
console.log(` Total packages: ${visualization.stats.totalPackages}`);
|
|
597
|
+
console.log(` Direct dependencies: ${visualization.stats.directDependencies}`);
|
|
598
|
+
console.log(` Max depth: ${visualization.stats.maxDepth}`);
|
|
599
|
+
console.log();
|
|
600
|
+
}
|
|
601
|
+
async function handleTemplates(query) {
|
|
602
|
+
console.log();
|
|
603
|
+
if (query) {
|
|
604
|
+
const results = searchTemplates(query);
|
|
605
|
+
if (results.length === 0) {
|
|
606
|
+
console.log(chalk.dim(` No templates found for "${query}"`));
|
|
607
|
+
} else {
|
|
608
|
+
console.log(formatTemplateList(results, true));
|
|
609
|
+
}
|
|
610
|
+
} else {
|
|
611
|
+
console.log(chalk.hex("#a5ffa5").bold(" Available Templates"));
|
|
612
|
+
console.log(chalk.dim(" Use 'template <id>' to set up"));
|
|
613
|
+
console.log();
|
|
614
|
+
console.log(formatTemplateList(TEMPLATES, true));
|
|
615
|
+
}
|
|
616
|
+
console.log();
|
|
617
|
+
}
|
|
618
|
+
async function handleUseTemplate(templateId, projectPath) {
|
|
619
|
+
const template = getTemplateById(templateId);
|
|
620
|
+
if (!template) {
|
|
621
|
+
console.log();
|
|
622
|
+
console.log(chalk.red(` Template "${templateId}" not found`));
|
|
623
|
+
console.log(chalk.dim(" Run 'templates' to see available options"));
|
|
624
|
+
console.log();
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
console.log();
|
|
628
|
+
console.log(chalk.hex("#a5ffa5").bold(` ${template.name}`));
|
|
629
|
+
console.log(chalk.dim(` ${template.description}`));
|
|
630
|
+
console.log();
|
|
631
|
+
const commands = getInstallCommandsForTemplate(template);
|
|
632
|
+
console.log(chalk.hex("#b4ffb4")(" Packages:"));
|
|
633
|
+
template.packages.filter((p) => !p.optional).forEach((pkg) => {
|
|
634
|
+
const note = pkg.note ? chalk.dim(` - ${pkg.note}`) : "";
|
|
635
|
+
console.log(` ${chalk.hex("#5aff5a")("+")} ${pkg.name}${note}`);
|
|
636
|
+
});
|
|
637
|
+
console.log();
|
|
638
|
+
console.log(chalk.hex("#b4ffb4")(" Commands to run:"));
|
|
639
|
+
commands.forEach((cmd) => {
|
|
640
|
+
console.log(chalk.cyan(` $ ${cmd}`));
|
|
641
|
+
});
|
|
642
|
+
console.log();
|
|
643
|
+
const packageNames = template.packages.filter((p) => !p.optional).map((p) => p.name);
|
|
644
|
+
const intent = `install ${packageNames.join(" ")}`;
|
|
645
|
+
const spinner = ora(chalk.hex("#b4ffb4")("Setting up template...")).start();
|
|
646
|
+
const result = await komodo.install({
|
|
647
|
+
intent,
|
|
648
|
+
path: projectPath,
|
|
649
|
+
dryRun: false,
|
|
650
|
+
useAI: false
|
|
651
|
+
});
|
|
652
|
+
if (result.success) {
|
|
653
|
+
spinner.succeed(chalk.hex("#5aff5a")("Template set up successfully!"));
|
|
654
|
+
} else {
|
|
655
|
+
spinner.fail(chalk.red(result.error || "Failed to set up template"));
|
|
656
|
+
}
|
|
657
|
+
console.log();
|
|
658
|
+
}
|
|
659
|
+
async function handleExplain(packageName) {
|
|
660
|
+
console.log();
|
|
661
|
+
const explanation = explainPackage(packageName);
|
|
662
|
+
if (!explanation) {
|
|
663
|
+
console.log(chalk.dim(` No information found for "${packageName}"`));
|
|
664
|
+
console.log(chalk.dim(" Try searching for common packages like torch, react, pandas, etc."));
|
|
665
|
+
console.log();
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
console.log(formatExplanation(explanation, true));
|
|
669
|
+
console.log();
|
|
670
|
+
}
|
|
671
|
+
async function handleClone(url) {
|
|
672
|
+
console.log();
|
|
673
|
+
const parsed = parseGitHubUrl(url);
|
|
674
|
+
if (!parsed) {
|
|
675
|
+
console.log(chalk.red(" Invalid GitHub URL"));
|
|
676
|
+
console.log(chalk.dim(" Example: komodo clone https://github.com/owner/repo"));
|
|
677
|
+
console.log();
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
const spinner = ora(chalk.hex("#b4ffb4")(`Analyzing ${parsed.owner}/${parsed.repo}...`)).start();
|
|
681
|
+
const mockFiles = {
|
|
682
|
+
"requirements.txt": "torch\ntransformers\nnumpy",
|
|
683
|
+
"README.md": "# Project\n\nInstall with pip install -r requirements.txt"
|
|
684
|
+
};
|
|
685
|
+
const analysis = analyzeRepoStructure(mockFiles);
|
|
686
|
+
analysis.url = url;
|
|
687
|
+
analysis.name = parsed.repo;
|
|
688
|
+
spinner.stop();
|
|
689
|
+
console.log();
|
|
690
|
+
console.log(formatRepoAnalysis(analysis, true));
|
|
691
|
+
console.log();
|
|
692
|
+
console.log(chalk.hex("#b4ffb4").bold(" Quick Setup:"));
|
|
693
|
+
console.log(chalk.cyan(` $ git clone ${url}`));
|
|
694
|
+
console.log(chalk.cyan(` $ cd ${parsed.repo}`));
|
|
695
|
+
for (const cmd of analysis.setupCommands) {
|
|
696
|
+
console.log(chalk.cyan(` $ ${cmd}`));
|
|
697
|
+
}
|
|
698
|
+
console.log();
|
|
699
|
+
}
|
|
700
|
+
async function handleInsights(projectPath) {
|
|
701
|
+
const spinner = ora(chalk.hex("#b4ffb4")("Gathering insights...")).start();
|
|
702
|
+
const state = await loadState(projectPath);
|
|
703
|
+
if (!state.activeEnvironmentId) {
|
|
704
|
+
spinner.succeed(chalk.dim("No environment to analyze - set something up first"));
|
|
705
|
+
console.log();
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
|
|
709
|
+
if (!activeEnv) {
|
|
710
|
+
spinner.succeed(chalk.dim("Nothing to analyze"));
|
|
711
|
+
console.log();
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
const installed = await getInstalledPackages(projectPath, activeEnv.runtime);
|
|
715
|
+
const snapshots = await komodo.listSnapshots(projectPath);
|
|
716
|
+
const insights = analyzeEnvironment(installed, snapshots);
|
|
717
|
+
spinner.stop();
|
|
718
|
+
console.log();
|
|
719
|
+
console.log(formatInsights(insights, true));
|
|
720
|
+
console.log();
|
|
721
|
+
}
|
|
338
722
|
async function handleUI(projectPath) {
|
|
339
723
|
const port = 3333;
|
|
340
724
|
const url = `http://localhost:${port}`;
|
|
341
725
|
console.log();
|
|
342
726
|
console.log(chalk.hex("#b4ffb4").dim(" Starting dashboard..."));
|
|
343
727
|
try {
|
|
344
|
-
const { startServer } = await import("./server-
|
|
728
|
+
const { startServer } = await import("./server-LCQG53IY.js");
|
|
345
729
|
await startServer(projectPath, port);
|
|
346
730
|
console.log(chalk.hex("#5aff5a")(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
|
|
347
731
|
console.log();
|
|
@@ -488,7 +872,7 @@ program.command("ui").description("Open the visual dashboard").option("-p, --pat
|
|
|
488
872
|
const url = `http://localhost:${port}`;
|
|
489
873
|
console.log(chalk.dim(" Starting dashboard..."));
|
|
490
874
|
try {
|
|
491
|
-
const { startServer } = await import("./server-
|
|
875
|
+
const { startServer } = await import("./server-LCQG53IY.js");
|
|
492
876
|
await startServer(options.path, port);
|
|
493
877
|
console.log();
|
|
494
878
|
console.log(chalk.green(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
|
|
@@ -586,6 +970,99 @@ program.command("check").description("Check if everything is working").option("-
|
|
|
586
970
|
}
|
|
587
971
|
console.log();
|
|
588
972
|
});
|
|
973
|
+
program.command("doctor").description("Run comprehensive health audit with security scan").option("-p, --path <path>", "Project folder", process.cwd()).action(async (options) => {
|
|
974
|
+
console.log();
|
|
975
|
+
console.log(chalk.bold("\u{1F98E} Komodo Doctor"));
|
|
976
|
+
console.log();
|
|
977
|
+
await handleDoctor(options.path);
|
|
978
|
+
});
|
|
979
|
+
program.command("optimize").description("Find ways to reduce environment size").option("-p, --path <path>", "Project folder", process.cwd()).option("--script", "Generate optimization script").action(async (options) => {
|
|
980
|
+
console.log();
|
|
981
|
+
console.log(chalk.bold("\u{1F98E} Komodo Optimizer"));
|
|
982
|
+
console.log();
|
|
983
|
+
const state = await loadState(options.path);
|
|
984
|
+
if (!state.activeEnvironmentId) {
|
|
985
|
+
console.log(chalk.dim(" No environment to optimize"));
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
|
|
989
|
+
if (!activeEnv) return;
|
|
990
|
+
const installed = await getInstalledPackages(options.path, activeEnv.runtime);
|
|
991
|
+
const hardware = komodo.getHardware();
|
|
992
|
+
const report = analyzeOptimizations(installed, hardware);
|
|
993
|
+
if (options.script) {
|
|
994
|
+
const script = generateOptimizationScript(report.suggestions, true);
|
|
995
|
+
console.log(script);
|
|
996
|
+
} else {
|
|
997
|
+
console.log(formatOptimizationReport(report, true));
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
program.command("tree").description("Visualize dependency tree").option("-p, --path <path>", "Project folder", process.cwd()).option("--depth <n>", "Max depth to show", "5").action(async (options) => {
|
|
1001
|
+
console.log();
|
|
1002
|
+
console.log(chalk.bold("\u{1F98E} Komodo Dependency Tree"));
|
|
1003
|
+
console.log();
|
|
1004
|
+
await handleTree(options.path);
|
|
1005
|
+
});
|
|
1006
|
+
program.command("templates").alias("template").description("Browse and use pre-built environment templates").argument("[query]", "Search for templates").option("-p, --path <path>", "Project folder", process.cwd()).action(async (query, options) => {
|
|
1007
|
+
console.log();
|
|
1008
|
+
console.log(chalk.bold("\u{1F98E} Komodo Templates"));
|
|
1009
|
+
console.log();
|
|
1010
|
+
if (query) {
|
|
1011
|
+
const template = getTemplateById(query);
|
|
1012
|
+
if (template) {
|
|
1013
|
+
await handleUseTemplate(query, options.path);
|
|
1014
|
+
} else {
|
|
1015
|
+
const results = searchTemplates(query);
|
|
1016
|
+
if (results.length === 0) {
|
|
1017
|
+
console.log(chalk.dim(` No templates found for "${query}"`));
|
|
1018
|
+
} else {
|
|
1019
|
+
console.log(formatTemplateList(results, true));
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
} else {
|
|
1023
|
+
console.log(formatTemplateList(TEMPLATES, true));
|
|
1024
|
+
console.log(chalk.dim(" Use 'komodo template <id>' to set up a template"));
|
|
1025
|
+
console.log();
|
|
1026
|
+
}
|
|
1027
|
+
});
|
|
1028
|
+
program.command("explain").description("Get detailed information about a package").argument("<package>", "Package name").action(async (packageName) => {
|
|
1029
|
+
console.log();
|
|
1030
|
+
console.log(chalk.bold("\u{1F98E} Komodo Package Info"));
|
|
1031
|
+
console.log();
|
|
1032
|
+
await handleExplain(packageName);
|
|
1033
|
+
});
|
|
1034
|
+
program.command("clone").alias("setup").description("Analyze and set up from a GitHub repository").argument("<url>", "GitHub repository URL").option("-p, --path <path>", "Project folder", process.cwd()).action(async (url, options) => {
|
|
1035
|
+
console.log();
|
|
1036
|
+
console.log(chalk.bold("\u{1F98E} Komodo GitHub Setup"));
|
|
1037
|
+
console.log();
|
|
1038
|
+
await handleClone(url);
|
|
1039
|
+
});
|
|
1040
|
+
program.command("insights").alias("analytics").description("View environment analytics and insights").option("-p, --path <path>", "Project folder", process.cwd()).action(async (options) => {
|
|
1041
|
+
console.log();
|
|
1042
|
+
console.log(chalk.bold("\u{1F98E} Komodo Insights"));
|
|
1043
|
+
console.log();
|
|
1044
|
+
await handleInsights(options.path);
|
|
1045
|
+
});
|
|
1046
|
+
program.command("diff").description("Compare two environment snapshots").option("-p, --path <path>", "Project folder", process.cwd()).action(async (options) => {
|
|
1047
|
+
console.log();
|
|
1048
|
+
console.log(chalk.bold("\u{1F98E} Komodo Environment Diff"));
|
|
1049
|
+
console.log();
|
|
1050
|
+
const snapshots = await komodo.listSnapshots(options.path);
|
|
1051
|
+
if (snapshots.length < 2) {
|
|
1052
|
+
console.log(chalk.dim(" Need at least 2 snapshots to compare"));
|
|
1053
|
+
console.log(chalk.dim(" Make some changes first, then run diff again"));
|
|
1054
|
+
console.log();
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
const sorted = [...snapshots].sort(
|
|
1058
|
+
(a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
|
|
1059
|
+
);
|
|
1060
|
+
const diff = diffPackages(sorted[1].packages, sorted[0].packages);
|
|
1061
|
+
diff.from = sorted[1].description;
|
|
1062
|
+
diff.to = sorted[0].description;
|
|
1063
|
+
console.log(formatDiff(diff, true));
|
|
1064
|
+
console.log();
|
|
1065
|
+
});
|
|
589
1066
|
program.command("history").description("See past changes").option("-p, --path <path>", "Project folder", process.cwd()).action(async (options) => {
|
|
590
1067
|
const snapshots = await komodo.listSnapshots(options.path);
|
|
591
1068
|
console.log();
|
package/package.json
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "komodo-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "The simple way to set up your project. Just say what you want to build.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"komodo": "./dist/index.js"
|
|
8
8
|
},
|
|
9
9
|
"main": "./dist/index.js",
|
|
10
|
-
"scripts": {
|
|
11
|
-
"build": "tsup && chmod +x dist/index.js",
|
|
12
|
-
"dev": "tsup src/index.ts --format esm --watch",
|
|
13
|
-
"typecheck": "tsc --noEmit",
|
|
14
|
-
"clean": "rm -rf dist",
|
|
15
|
-
"prepublishOnly": "pnpm build"
|
|
16
|
-
},
|
|
17
10
|
"files": [
|
|
18
11
|
"dist"
|
|
19
12
|
],
|
|
@@ -42,7 +35,13 @@
|
|
|
42
35
|
"cross-spawn": "^7.0.6"
|
|
43
36
|
},
|
|
44
37
|
"devDependencies": {
|
|
45
|
-
"@komodo/core": "
|
|
46
|
-
"@komodo/ui": "
|
|
38
|
+
"@komodo/core": "0.1.0",
|
|
39
|
+
"@komodo/ui": "0.1.0"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsup && chmod +x dist/index.js",
|
|
43
|
+
"dev": "tsup src/index.ts --format esm --watch",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"clean": "rm -rf dist"
|
|
47
46
|
}
|
|
48
|
-
}
|
|
47
|
+
}
|