komodo-cli 2.4.0 → 2.7.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.
|
@@ -4993,7 +4993,11 @@ var CerebrasAI = class {
|
|
|
4993
4993
|
throw new Error(`Cerebras API error: ${response.status} - ${error}`);
|
|
4994
4994
|
}
|
|
4995
4995
|
const data = await response.json();
|
|
4996
|
-
|
|
4996
|
+
const content = data.choices[0]?.message?.content ?? "";
|
|
4997
|
+
if (!content) {
|
|
4998
|
+
throw new Error("Empty response from Cerebras API");
|
|
4999
|
+
}
|
|
5000
|
+
return content;
|
|
4997
5001
|
}
|
|
4998
5002
|
/**
|
|
4999
5003
|
* Analyze user intent and return comprehensive package recommendations
|
|
@@ -5172,7 +5176,6 @@ var KomodoChat = class {
|
|
|
5172
5176
|
*/
|
|
5173
5177
|
setContext(context) {
|
|
5174
5178
|
this.context = context;
|
|
5175
|
-
this.conversationHistory = [];
|
|
5176
5179
|
}
|
|
5177
5180
|
/**
|
|
5178
5181
|
* Clear conversation history
|
|
@@ -5240,7 +5243,9 @@ var KomodoChat = class {
|
|
|
5240
5243
|
const installedList = ctx.installedPackages.length > 0 ? ctx.installedPackages.map((p) => ` - ${p.name}@${p.version}`).join("\n") : " (none)";
|
|
5241
5244
|
const conflictsList = ctx.conflicts.length > 0 ? ctx.conflicts.map((c) => ` - ${c.package1} vs ${c.package2}: ${c.reason}`).join("\n") : " (none)";
|
|
5242
5245
|
const issuesList = ctx.healthIssues.length > 0 ? ctx.healthIssues.map((i) => ` - [${i.severity}] ${i.title}: ${i.description}`).join("\n") : " (none)";
|
|
5243
|
-
return `You are Komodo
|
|
5246
|
+
return `You are Komodo, an AI assistant that manages Python and Node.js environments. You live inside a CLI tool. When users ask you to do something, you DO it -- you don't just explain how.
|
|
5247
|
+
|
|
5248
|
+
You are conversational, friendly, and concise. Think of yourself like a knowledgeable friend who just gets things done. Keep responses short and to the point. No lectures.
|
|
5244
5249
|
|
|
5245
5250
|
CURRENT ENVIRONMENT:
|
|
5246
5251
|
- Project: ${ctx.environmentName || "Unknown"}
|
|
@@ -5257,17 +5262,17 @@ ${conflictsList}
|
|
|
5257
5262
|
HEALTH ISSUES (${ctx.healthIssues.length}):
|
|
5258
5263
|
${issuesList}
|
|
5259
5264
|
|
|
5260
|
-
|
|
5261
|
-
1.
|
|
5262
|
-
2.
|
|
5263
|
-
3.
|
|
5264
|
-
4.
|
|
5265
|
-
5.
|
|
5265
|
+
RULES:
|
|
5266
|
+
1. When the user asks to install, set up, or build something -- DO IT. Include the actions JSON so the system auto-executes. Don't say "you can run pip install X" -- just include it in the actions and say "On it, installing X for you."
|
|
5267
|
+
2. Be concise. 2-4 sentences max for most responses. No walls of text.
|
|
5268
|
+
3. NEVER use markdown. No **bold**, no backticks, no code blocks, no # headers, no bullet points with *. Just plain text with simple dashes if you need lists.
|
|
5269
|
+
4. When you set things up, briefly explain what you're installing and why, then include the actions.
|
|
5270
|
+
5. If something needs a venv, create it. If packages conflict, fix them. Just handle it.
|
|
5271
|
+
6. Remember the conversation -- the user might ask follow-up questions.
|
|
5266
5272
|
|
|
5267
|
-
|
|
5268
|
-
|
|
5273
|
+
ACTION FORMAT:
|
|
5274
|
+
When you need to install, remove, or update packages, append this JSON at the very end of your response (after your message):
|
|
5269
5275
|
|
|
5270
|
-
If you recommend installing, removing, or updating packages, include a JSON block at the end of your response in this format:
|
|
5271
5276
|
\`\`\`json
|
|
5272
5277
|
{
|
|
5273
5278
|
"actions": [
|
|
@@ -5278,7 +5283,7 @@ If you recommend installing, removing, or updating packages, include a JSON bloc
|
|
|
5278
5283
|
}
|
|
5279
5284
|
\`\`\`
|
|
5280
5285
|
|
|
5281
|
-
Only include the JSON block
|
|
5286
|
+
Only include actions when there are actual packages to change. Your conversational text comes first, then the JSON block at the end.`;
|
|
5282
5287
|
}
|
|
5283
5288
|
async callAPI(messages) {
|
|
5284
5289
|
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
@@ -5300,7 +5305,11 @@ Only include the JSON block if you're recommending specific package changes.`;
|
|
|
5300
5305
|
throw new Error(`API error: ${response.status} - ${error}`);
|
|
5301
5306
|
}
|
|
5302
5307
|
const data = await response.json();
|
|
5303
|
-
|
|
5308
|
+
const content = data.choices[0]?.message?.content ?? "";
|
|
5309
|
+
if (!content) {
|
|
5310
|
+
throw new Error("Empty response from AI - try again");
|
|
5311
|
+
}
|
|
5312
|
+
return content;
|
|
5304
5313
|
}
|
|
5305
5314
|
parseResponse(response) {
|
|
5306
5315
|
const result = {
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
runDoctor,
|
|
32
32
|
searchTemplates,
|
|
33
33
|
visualizeTree
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-GGBZF72M.js";
|
|
35
35
|
|
|
36
36
|
// src/index.ts
|
|
37
37
|
import { Command } from "commander";
|
|
@@ -127,345 +127,220 @@ async function updateChatContext(projectPath) {
|
|
|
127
127
|
chat.setContext(context);
|
|
128
128
|
return { installedPackages, conflicts, healthIssues, runtime, environmentName };
|
|
129
129
|
}
|
|
130
|
-
function
|
|
131
|
-
|
|
132
|
-
if (input.endsWith("?")) return true;
|
|
133
|
-
const questionWords = ["what", "why", "how", "when", "where", "which", "who", "can", "could", "should", "would", "is", "are", "do", "does", "tell me", "explain", "show me", "help me"];
|
|
134
|
-
if (questionWords.some((w) => lowerInput.startsWith(w))) return true;
|
|
135
|
-
const envKeywords = ["installed", "packages", "conflicts", "issues", "problems", "wrong", "fix", "update", "upgrade", "remove", "alternatives", "suggest", "recommend", "analyze", "status"];
|
|
136
|
-
if (envKeywords.some((k) => lowerInput.includes(k))) return true;
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
function displayAIResponse(response) {
|
|
140
|
-
console.log();
|
|
141
|
-
console.log(chalk.hex("#b4ffb4")(response.message));
|
|
142
|
-
if (response.suggestions && response.suggestions.length > 0) {
|
|
143
|
-
console.log();
|
|
144
|
-
console.log(chalk.hex("#87cefa")(" Suggestions:"));
|
|
145
|
-
response.suggestions.forEach((s) => {
|
|
146
|
-
console.log(chalk.hex("#87cefa")(` \u2022 ${s}`));
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
if (response.packages) {
|
|
150
|
-
if (response.packages.toInstall && response.packages.toInstall.length > 0) {
|
|
151
|
-
console.log();
|
|
152
|
-
console.log(chalk.hex("#5aff5a")(" Packages to install:"));
|
|
153
|
-
response.packages.toInstall.forEach((p) => {
|
|
154
|
-
console.log(chalk.hex("#5aff5a")(` + ${p}`));
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
if (response.packages.toRemove && response.packages.toRemove.length > 0) {
|
|
158
|
-
console.log();
|
|
159
|
-
console.log(chalk.yellow(" Packages to remove:"));
|
|
160
|
-
response.packages.toRemove.forEach((p) => {
|
|
161
|
-
console.log(chalk.yellow(` - ${p}`));
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
if (response.packages.toUpdate && response.packages.toUpdate.length > 0) {
|
|
165
|
-
console.log();
|
|
166
|
-
console.log(chalk.hex("#87cefa")(" Packages to update:"));
|
|
167
|
-
response.packages.toUpdate.forEach((p) => {
|
|
168
|
-
console.log(chalk.hex("#87cefa")(` \u2191 ${p.name}: ${p.from} \u2192 ${p.to}`));
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
console.log();
|
|
130
|
+
function stripMarkdown(text) {
|
|
131
|
+
return text.replace(/```[\s\S]*?```/g, "").replace(/`([^`]+)`/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/__([^_]+)__/g, "$1").replace(/_([^_]+)_/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/^\s*[-*+]\s+/gm, " - ").replace(/^\s*\d+\.\s+/gm, (m) => m).replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\n{3,}/g, "\n\n").trim();
|
|
173
132
|
}
|
|
174
133
|
async function startInteractiveMode(projectPath) {
|
|
175
134
|
printBanner();
|
|
176
135
|
const hardware = komodo.getHardware();
|
|
177
136
|
console.log(chalk.hex("#b4ffb4").dim(` ${formatOs(hardware.os)} \xB7 ${formatGpu(hardware)} \xB7 ${hardware.totalMemoryGb}GB memory`));
|
|
178
137
|
console.log();
|
|
179
|
-
console.log(chalk.
|
|
180
|
-
console.log(chalk.
|
|
181
|
-
console.log(chalk.dim("
|
|
138
|
+
console.log(chalk.dim(" Type anything naturally. Komodo understands what you need."));
|
|
139
|
+
console.log(chalk.dim(` Try: "set up a venv for pytorch" or "what's installed?"`));
|
|
140
|
+
console.log(chalk.dim(" Type ") + chalk.hex("#d2ffd2")("help") + chalk.dim(" for commands, ") + chalk.hex("#d2ffd2")("exit") + chalk.dim(" to quit."));
|
|
182
141
|
console.log();
|
|
183
142
|
await updateChatContext(projectPath);
|
|
184
143
|
const rl = readline.createInterface({
|
|
185
144
|
input: process.stdin,
|
|
186
145
|
output: process.stdout
|
|
187
146
|
});
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
if (trimmed === "exit" || trimmed === "quit" || trimmed === "q") {
|
|
196
|
-
console.log();
|
|
197
|
-
console.log(chalk.hex("#a5ffa5")(" See you next time! \u{1F98E}"));
|
|
198
|
-
console.log();
|
|
199
|
-
rl.close();
|
|
200
|
-
process.exit(0);
|
|
201
|
-
}
|
|
202
|
-
if (trimmed === "clear" || trimmed === "cls") {
|
|
203
|
-
console.clear();
|
|
204
|
-
printBanner();
|
|
205
|
-
prompt();
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
if (trimmed === "help" || trimmed === "?") {
|
|
209
|
-
console.log();
|
|
210
|
-
console.log(chalk.hex("#a5ffa5")(" Just type what you want to build or ask anything:"));
|
|
211
|
-
console.log(chalk.dim(' "build a website"'));
|
|
212
|
-
console.log(chalk.dim(' "what packages are installed?"'));
|
|
213
|
-
console.log(chalk.dim(' "are there any conflicts?"'));
|
|
214
|
-
console.log(chalk.dim(' "suggest alternatives to express"'));
|
|
215
|
-
console.log();
|
|
216
|
-
console.log(chalk.hex("#a5ffa5")(" Premium Commands:"));
|
|
217
|
-
console.log(` ${chalk.hex("#d2ffd2")("doctor")} Full health audit with security scan`);
|
|
218
|
-
console.log(` ${chalk.hex("#d2ffd2")("optimize")} Find ways to reduce bloat`);
|
|
219
|
-
console.log(` ${chalk.hex("#d2ffd2")("tree")} Visualize dependency tree`);
|
|
220
|
-
console.log(` ${chalk.hex("#d2ffd2")("templates")} Browse pre-built environment templates`);
|
|
221
|
-
console.log(` ${chalk.hex("#d2ffd2")("explain")} Get info about any package (e.g. explain torch)`);
|
|
222
|
-
console.log(` ${chalk.hex("#d2ffd2")("clone")} Set up from GitHub URL`);
|
|
223
|
-
console.log(` ${chalk.hex("#d2ffd2")("insights")} Analytics and insights`);
|
|
224
|
-
console.log();
|
|
225
|
-
console.log(chalk.hex("#a5ffa5")(" Basic Commands:"));
|
|
226
|
-
console.log(` ${chalk.hex("#d2ffd2")("undo")} Undo last change`);
|
|
227
|
-
console.log(` ${chalk.hex("#d2ffd2")("list")} See what's installed`);
|
|
228
|
-
console.log(` ${chalk.hex("#d2ffd2")("check")} Check for problems`);
|
|
229
|
-
console.log(` ${chalk.hex("#d2ffd2")("ask")} Start AI conversation`);
|
|
230
|
-
console.log(` ${chalk.hex("#d2ffd2")("analyze")} AI analysis of environment`);
|
|
231
|
-
console.log(` ${chalk.hex("#d2ffd2")("ui")} Open visual dashboard`);
|
|
232
|
-
console.log(` ${chalk.hex("#d2ffd2")("history")} See past changes`);
|
|
233
|
-
console.log(` ${chalk.hex("#d2ffd2")("clear")} Clear screen`);
|
|
234
|
-
console.log(` ${chalk.hex("#d2ffd2")("exit")} Exit Komodo`);
|
|
235
|
-
console.log();
|
|
236
|
-
prompt();
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
if (trimmed === "undo") {
|
|
240
|
-
await handleUndo(projectPath);
|
|
241
|
-
await updateChatContext(projectPath);
|
|
242
|
-
prompt();
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
if (trimmed === "fix" || trimmed === "repair" || trimmed.includes("broken") || trimmed.includes("nothing works") || trimmed.includes("everything is broken") || trimmed.includes("help me fix")) {
|
|
246
|
-
await handleFix(projectPath);
|
|
247
|
-
await updateChatContext(projectPath);
|
|
248
|
-
prompt();
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
if (trimmed === "conflicts" || trimmed.includes("check conflicts") || trimmed.includes("find conflicts")) {
|
|
252
|
-
await handleConflicts(projectPath);
|
|
253
|
-
prompt();
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
if (trimmed === "list" || trimmed === "ls") {
|
|
257
|
-
await handleList(projectPath);
|
|
258
|
-
prompt();
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
if (trimmed === "check") {
|
|
262
|
-
await handleCheck(projectPath);
|
|
263
|
-
prompt();
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
if (trimmed === "history") {
|
|
267
|
-
await handleHistory(projectPath);
|
|
268
|
-
prompt();
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
if (trimmed === "ui") {
|
|
272
|
-
await handleUI(projectPath);
|
|
273
|
-
prompt();
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
if (trimmed === "doctor") {
|
|
277
|
-
await handleDoctor(projectPath);
|
|
278
|
-
prompt();
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
if (trimmed === "optimize") {
|
|
282
|
-
await handleOptimize(projectPath);
|
|
283
|
-
prompt();
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
if (trimmed === "tree") {
|
|
287
|
-
await handleTree(projectPath);
|
|
288
|
-
prompt();
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
if (trimmed === "templates" || trimmed === "template") {
|
|
292
|
-
await handleTemplates();
|
|
293
|
-
prompt();
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
if (trimmed.startsWith("template ") || trimmed.startsWith("use ")) {
|
|
297
|
-
const templateId = trimmed.replace(/^(template|use)\s+/, "").trim();
|
|
298
|
-
await handleUseTemplate(templateId, projectPath);
|
|
299
|
-
prompt();
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
if (trimmed.startsWith("explain ")) {
|
|
303
|
-
const packageName = trimmed.slice(8).trim();
|
|
304
|
-
await handleExplain(packageName);
|
|
305
|
-
prompt();
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
if (trimmed.startsWith("clone ") || trimmed.startsWith("setup ")) {
|
|
309
|
-
const url = trimmed.replace(/^(clone|setup)\s+/, "").trim();
|
|
310
|
-
await handleClone(url);
|
|
311
|
-
prompt();
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
if (trimmed === "insights" || trimmed === "analytics") {
|
|
315
|
-
await handleInsights(projectPath);
|
|
316
|
-
prompt();
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
if (trimmed === "analyze" || trimmed === "analyse") {
|
|
320
|
-
const spinner = ora(chalk.hex("#b4ffb4")("Analyzing your environment...")).start();
|
|
321
|
-
await updateChatContext(projectPath);
|
|
322
|
-
const response = await chat.analyzeEnvironment();
|
|
323
|
-
spinner.stop();
|
|
324
|
-
displayAIResponse(response);
|
|
325
|
-
prompt();
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
if (trimmed === "ask" || trimmed.startsWith("ask ")) {
|
|
329
|
-
const question = trimmed === "ask" ? "" : trimmed.slice(4).trim();
|
|
330
|
-
if (question) {
|
|
331
|
-
const spinner = ora(chalk.hex("#b4ffb4")("Thinking...")).start();
|
|
332
|
-
await updateChatContext(projectPath);
|
|
333
|
-
const response = await chat.chat(question);
|
|
334
|
-
spinner.stop();
|
|
335
|
-
displayAIResponse(response);
|
|
336
|
-
} else {
|
|
337
|
-
console.log();
|
|
338
|
-
console.log(chalk.hex("#b4ffb4")(" Ask me anything about your environment and what you want to build!"));
|
|
339
|
-
console.log(chalk.dim(" Examples:"));
|
|
340
|
-
console.log(chalk.dim(" \u2022 What should I install for a REST API?"));
|
|
341
|
-
console.log(chalk.dim(" \u2022 How do I train an LLM?"));
|
|
342
|
-
console.log(chalk.dim(" \u2022 Set up a venv for LLADA 8B"));
|
|
343
|
-
console.log(chalk.dim(" \u2022 Type 'exit' to go back to main menu"));
|
|
344
|
-
console.log();
|
|
345
|
-
const chatRl = readline.createInterface({
|
|
346
|
-
input: process.stdin,
|
|
347
|
-
output: process.stdout
|
|
348
|
-
});
|
|
349
|
-
const chatPrompt = () => {
|
|
350
|
-
chatRl.question(chalk.hex("#5aff5a")(" ai> "), async (chatInput) => {
|
|
351
|
-
const chatTrimmed = chatInput.trim();
|
|
352
|
-
if (!chatTrimmed) {
|
|
353
|
-
chatPrompt();
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
if (chatTrimmed === "exit" || chatTrimmed === "quit" || chatTrimmed === "q") {
|
|
357
|
-
chatRl.close();
|
|
358
|
-
console.log();
|
|
359
|
-
prompt();
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
const spinner = ora(chalk.hex("#b4ffb4")("Thinking...")).start();
|
|
363
|
-
try {
|
|
364
|
-
const response = await chat.chat(chatTrimmed);
|
|
365
|
-
spinner.stop();
|
|
366
|
-
displayAIResponse(response);
|
|
367
|
-
} catch (error) {
|
|
368
|
-
spinner.fail();
|
|
369
|
-
console.error(chalk.red("Error: " + (error instanceof Error ? error.message : "Unknown error")));
|
|
370
|
-
}
|
|
371
|
-
chatPrompt();
|
|
372
|
-
});
|
|
373
|
-
};
|
|
374
|
-
chatPrompt();
|
|
375
|
-
}
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
if (isAIQuestion(trimmed)) {
|
|
379
|
-
const spinner = ora(chalk.hex("#b4ffb4")("Thinking...")).start();
|
|
380
|
-
await updateChatContext(projectPath);
|
|
381
|
-
const response = await chat.chat(trimmed);
|
|
382
|
-
spinner.stop();
|
|
383
|
-
displayAIResponse(response);
|
|
384
|
-
prompt();
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
await handleInstall(trimmed, projectPath);
|
|
147
|
+
rl.on("close", () => {
|
|
148
|
+
process.exit(0);
|
|
149
|
+
});
|
|
150
|
+
const handleInput = async (input) => {
|
|
151
|
+
const trimmed = input.trim();
|
|
152
|
+
if (!trimmed) {
|
|
388
153
|
prompt();
|
|
389
|
-
|
|
390
|
-
};
|
|
391
|
-
prompt();
|
|
392
|
-
}
|
|
393
|
-
async function handleInstall(intent, projectPath) {
|
|
394
|
-
const spinner = ora();
|
|
395
|
-
console.log();
|
|
396
|
-
const explanations = [];
|
|
397
|
-
const warnings = [];
|
|
398
|
-
const tips = [];
|
|
399
|
-
const result = await komodo.install({
|
|
400
|
-
intent,
|
|
401
|
-
path: projectPath,
|
|
402
|
-
dryRun: false,
|
|
403
|
-
useAI: true,
|
|
404
|
-
apiKey: CEREBRAS_API_KEY,
|
|
405
|
-
onProgress: (message) => {
|
|
406
|
-
const friendly = friendlyMessage(message);
|
|
407
|
-
if (spinner.isSpinning) {
|
|
408
|
-
spinner.succeed();
|
|
409
|
-
}
|
|
410
|
-
spinner.start(chalk.hex("#b4ffb4")(friendly));
|
|
411
|
-
},
|
|
412
|
-
onExplanation: (explanation) => {
|
|
413
|
-
explanations.push(friendlyExplanation(explanation));
|
|
414
|
-
},
|
|
415
|
-
onWarning: (warning) => {
|
|
416
|
-
warnings.push(friendlyWarning(warning));
|
|
417
|
-
},
|
|
418
|
-
onTip: (tip) => {
|
|
419
|
-
tips.push(tip);
|
|
154
|
+
return;
|
|
420
155
|
}
|
|
421
|
-
|
|
422
|
-
if (spinner.isSpinning) {
|
|
423
|
-
spinner.succeed();
|
|
424
|
-
}
|
|
425
|
-
console.log();
|
|
426
|
-
if (result.success) {
|
|
427
|
-
if (result.aiAnalysis) {
|
|
428
|
-
console.log(chalk.hex("#5aff5a").bold(` \u2713 ${result.aiAnalysis.goal}`));
|
|
429
|
-
if (result.aiAnalysis.description) {
|
|
430
|
-
console.log(chalk.dim(` ${result.aiAnalysis.description}`));
|
|
431
|
-
}
|
|
156
|
+
if (trimmed === "exit" || trimmed === "quit" || trimmed === "q") {
|
|
432
157
|
console.log();
|
|
433
|
-
|
|
434
|
-
if (result.resolution && result.resolution.packages.length > 0) {
|
|
435
|
-
console.log(chalk.hex("#a5ffa5")(" Set up:"));
|
|
436
|
-
result.resolution.packages.forEach((pkg) => {
|
|
437
|
-
const reason = pkg.reason ? chalk.dim(` - ${pkg.reason}`) : "";
|
|
438
|
-
console.log(chalk.hex("#5aff5a")(` \u2713 ${friendlyPackageName(pkg.name)}`) + reason);
|
|
439
|
-
});
|
|
158
|
+
console.log(chalk.hex("#a5ffa5")(" See you next time!"));
|
|
440
159
|
console.log();
|
|
160
|
+
rl.close();
|
|
161
|
+
process.exit(0);
|
|
441
162
|
}
|
|
442
|
-
if (
|
|
443
|
-
console.
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
163
|
+
if (trimmed === "clear" || trimmed === "cls") {
|
|
164
|
+
console.clear();
|
|
165
|
+
printBanner();
|
|
166
|
+
prompt();
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (trimmed === "help" || trimmed === "?") {
|
|
170
|
+
console.log();
|
|
171
|
+
console.log(chalk.hex("#a5ffa5")(" Just type what you want in plain English:"));
|
|
172
|
+
console.log(chalk.dim(' "set up a venv to train llada 8b"'));
|
|
173
|
+
console.log(chalk.dim(' "install pytorch and transformers"'));
|
|
174
|
+
console.log(chalk.dim(' "what packages are installed?"'));
|
|
175
|
+
console.log(chalk.dim(' "are there any conflicts?"'));
|
|
447
176
|
console.log();
|
|
177
|
+
console.log(chalk.hex("#a5ffa5")(" Shortcuts:"));
|
|
178
|
+
console.log(` ${chalk.hex("#d2ffd2")("list")} See installed packages`);
|
|
179
|
+
console.log(` ${chalk.hex("#d2ffd2")("check")} Check for problems`);
|
|
180
|
+
console.log(` ${chalk.hex("#d2ffd2")("fix")} Auto-repair environment`);
|
|
181
|
+
console.log(` ${chalk.hex("#d2ffd2")("conflicts")} Find package conflicts`);
|
|
182
|
+
console.log(` ${chalk.hex("#d2ffd2")("doctor")} Full health audit`);
|
|
183
|
+
console.log(` ${chalk.hex("#d2ffd2")("tree")} Dependency tree`);
|
|
184
|
+
console.log(` ${chalk.hex("#d2ffd2")("undo")} Undo last change`);
|
|
185
|
+
console.log(` ${chalk.hex("#d2ffd2")("clear")} Clear screen`);
|
|
186
|
+
console.log(` ${chalk.hex("#d2ffd2")("exit")} Quit Komodo`);
|
|
187
|
+
console.log();
|
|
188
|
+
prompt();
|
|
189
|
+
return;
|
|
448
190
|
}
|
|
449
|
-
if (
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
191
|
+
if (trimmed === "undo") {
|
|
192
|
+
await handleUndo(projectPath);
|
|
193
|
+
await updateChatContext(projectPath);
|
|
194
|
+
prompt();
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (trimmed === "list" || trimmed === "ls") {
|
|
198
|
+
await handleList(projectPath);
|
|
199
|
+
prompt();
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (trimmed === "check") {
|
|
203
|
+
await handleCheck(projectPath);
|
|
204
|
+
prompt();
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (trimmed === "history") {
|
|
208
|
+
await handleHistory(projectPath);
|
|
209
|
+
prompt();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (trimmed === "doctor") {
|
|
213
|
+
await handleDoctor(projectPath);
|
|
214
|
+
prompt();
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (trimmed === "optimize") {
|
|
218
|
+
await handleOptimize(projectPath);
|
|
219
|
+
prompt();
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (trimmed === "tree") {
|
|
223
|
+
await handleTree(projectPath);
|
|
224
|
+
prompt();
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (trimmed === "templates" || trimmed === "template") {
|
|
228
|
+
await handleTemplates();
|
|
229
|
+
prompt();
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (trimmed.startsWith("template ") || trimmed.startsWith("use ")) {
|
|
233
|
+
const templateId = trimmed.replace(/^(template|use)\s+/, "").trim();
|
|
234
|
+
await handleUseTemplate(templateId, projectPath);
|
|
235
|
+
prompt();
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (trimmed.startsWith("explain ")) {
|
|
239
|
+
const packageName = trimmed.slice(8).trim();
|
|
240
|
+
await handleExplain(packageName);
|
|
241
|
+
prompt();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (trimmed.startsWith("clone ") || trimmed.startsWith("setup ")) {
|
|
245
|
+
const url = trimmed.replace(/^(clone|setup)\s+/, "").trim();
|
|
246
|
+
await handleClone(url);
|
|
247
|
+
prompt();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (trimmed === "insights" || trimmed === "analytics") {
|
|
251
|
+
await handleInsights(projectPath);
|
|
252
|
+
prompt();
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (trimmed === "ui") {
|
|
256
|
+
await handleUI(projectPath);
|
|
257
|
+
prompt();
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const spinner = ora(chalk.hex("#b4ffb4")("Thinking...")).start();
|
|
261
|
+
try {
|
|
262
|
+
await updateChatContext(projectPath);
|
|
263
|
+
const response = await chat.chat(trimmed);
|
|
264
|
+
spinner.stop();
|
|
265
|
+
const cleanMessage = stripMarkdown(response.message);
|
|
266
|
+
console.log();
|
|
267
|
+
console.log(chalk.hex("#b4ffb4")(cleanMessage));
|
|
268
|
+
console.log();
|
|
269
|
+
if (response.packages) {
|
|
270
|
+
const hasActions = response.packages.toInstall && response.packages.toInstall.length > 0 || response.packages.toRemove && response.packages.toRemove.length > 0 || response.packages.toUpdate && response.packages.toUpdate.length > 0;
|
|
271
|
+
if (hasActions) {
|
|
272
|
+
await executePackageActions(response.packages, projectPath);
|
|
273
|
+
await updateChatContext(projectPath);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
} catch (error) {
|
|
277
|
+
spinner.fail(chalk.red("Something went wrong"));
|
|
278
|
+
const errMsg = error instanceof Error ? error.message : "Unknown error";
|
|
279
|
+
console.log();
|
|
280
|
+
console.log(chalk.dim(" " + errMsg));
|
|
281
|
+
console.log(chalk.dim(" Try again or type 'help' for options."));
|
|
454
282
|
console.log();
|
|
455
283
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
284
|
+
prompt();
|
|
285
|
+
};
|
|
286
|
+
const prompt = () => {
|
|
287
|
+
if (rl.closed) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
rl.question(chalk.hex("#5aff5a")("\u276F "), (input) => {
|
|
291
|
+
handleInput(input).catch((err) => {
|
|
292
|
+
console.error(chalk.red("Error:"), err);
|
|
293
|
+
prompt();
|
|
460
294
|
});
|
|
461
|
-
|
|
295
|
+
});
|
|
296
|
+
};
|
|
297
|
+
prompt();
|
|
298
|
+
}
|
|
299
|
+
async function executePackageActions(packages, projectPath) {
|
|
300
|
+
const allActions = [
|
|
301
|
+
...(packages.toInstall || []).map((p) => ({ type: "install", name: p })),
|
|
302
|
+
...(packages.toRemove || []).map((p) => ({ type: "remove", name: p })),
|
|
303
|
+
...(packages.toUpdate || []).map((p) => ({ type: "update", name: p.name, version: p.to }))
|
|
304
|
+
];
|
|
305
|
+
if (allActions.length === 0) return;
|
|
306
|
+
for (const action of allActions) {
|
|
307
|
+
const spinner = ora();
|
|
308
|
+
try {
|
|
309
|
+
if (action.type === "install") {
|
|
310
|
+
spinner.start(chalk.hex("#b4ffb4")(`Installing ${action.name}...`));
|
|
311
|
+
const result = await komodo.install({
|
|
312
|
+
intent: `install ${action.name}`,
|
|
313
|
+
path: projectPath,
|
|
314
|
+
dryRun: false,
|
|
315
|
+
useAI: false,
|
|
316
|
+
apiKey: CEREBRAS_API_KEY
|
|
317
|
+
});
|
|
318
|
+
spinner.succeed(chalk.hex("#5aff5a")(`Installed ${action.name}`));
|
|
319
|
+
} else if (action.type === "remove") {
|
|
320
|
+
spinner.start(chalk.hex("#b4ffb4")(`Removing ${action.name}...`));
|
|
321
|
+
await komodo.install({
|
|
322
|
+
intent: `uninstall ${action.name}`,
|
|
323
|
+
path: projectPath,
|
|
324
|
+
dryRun: false,
|
|
325
|
+
useAI: false,
|
|
326
|
+
apiKey: CEREBRAS_API_KEY
|
|
327
|
+
});
|
|
328
|
+
spinner.succeed(chalk.yellow(`Removed ${action.name}`));
|
|
329
|
+
} else if (action.type === "update") {
|
|
330
|
+
spinner.start(chalk.hex("#b4ffb4")(`Updating ${action.name}...`));
|
|
331
|
+
await komodo.install({
|
|
332
|
+
intent: `update ${action.name} to ${action.version}`,
|
|
333
|
+
path: projectPath,
|
|
334
|
+
dryRun: false,
|
|
335
|
+
useAI: false,
|
|
336
|
+
apiKey: CEREBRAS_API_KEY
|
|
337
|
+
});
|
|
338
|
+
spinner.succeed(chalk.hex("#87cefa")(`Updated ${action.name}`));
|
|
339
|
+
}
|
|
340
|
+
} catch (error) {
|
|
341
|
+
spinner.fail();
|
|
342
|
+
console.error(chalk.red(`Failed to ${action.type} ${action.name}: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
462
343
|
}
|
|
463
|
-
console.log(chalk.hex("#5aff5a")(" \u2713 All set! ") + chalk.dim("Type 'undo' to revert."));
|
|
464
|
-
console.log();
|
|
465
|
-
} else {
|
|
466
|
-
console.log(chalk.red(" \u2717 Couldn't set that up"));
|
|
467
|
-
console.log(chalk.dim(` ${result.error ?? "Try being more specific about what you want to build."}`));
|
|
468
|
-
console.log();
|
|
469
344
|
}
|
|
470
345
|
}
|
|
471
346
|
async function handleUndo(projectPath) {
|
|
@@ -549,135 +424,6 @@ async function handleCheck(projectPath) {
|
|
|
549
424
|
}
|
|
550
425
|
console.log();
|
|
551
426
|
}
|
|
552
|
-
async function handleFix(projectPath) {
|
|
553
|
-
const spinner = ora(chalk.hex("#b4ffb4")("Scanning your project...")).start();
|
|
554
|
-
const state = await loadState(projectPath);
|
|
555
|
-
let runtime;
|
|
556
|
-
if (state.activeEnvironmentId) {
|
|
557
|
-
const env = state.environments.find((e) => e.id === state.activeEnvironmentId);
|
|
558
|
-
runtime = env?.runtime;
|
|
559
|
-
}
|
|
560
|
-
const diagnosis = await diagnoseEnvironment(projectPath, runtime);
|
|
561
|
-
spinner.stop();
|
|
562
|
-
console.log();
|
|
563
|
-
if (diagnosis.status === "healthy") {
|
|
564
|
-
console.log(chalk.hex("#5aff5a")(" \u2713 Everything looks good!"));
|
|
565
|
-
console.log(chalk.dim(" No issues found with your environment."));
|
|
566
|
-
console.log();
|
|
567
|
-
return;
|
|
568
|
-
}
|
|
569
|
-
console.log(chalk.hex("#ffb347")(` Found ${diagnosis.problems.length} issue${diagnosis.problems.length > 1 ? "s" : ""}:`));
|
|
570
|
-
console.log();
|
|
571
|
-
diagnosis.problems.slice(0, 3).forEach((problem) => {
|
|
572
|
-
const icon = problem.severity === "critical" ? chalk.red("\u2717") : problem.severity === "warning" ? chalk.yellow("\u26A0") : chalk.blue("\u2139");
|
|
573
|
-
console.log(` ${icon} ${problem.friendlyTitle}`);
|
|
574
|
-
console.log(chalk.dim(` ${problem.description}`));
|
|
575
|
-
});
|
|
576
|
-
if (diagnosis.problems.length > 3) {
|
|
577
|
-
console.log(chalk.dim(` ...and ${diagnosis.problems.length - 3} more`));
|
|
578
|
-
}
|
|
579
|
-
console.log();
|
|
580
|
-
if (diagnosis.repairPlan.length === 0) {
|
|
581
|
-
console.log(chalk.dim(" No automatic fixes available. Try creating a new environment."));
|
|
582
|
-
console.log();
|
|
583
|
-
return;
|
|
584
|
-
}
|
|
585
|
-
console.log(chalk.hex("#b4ffb4")(` Fixing ${diagnosis.repairPlan.length} issue${diagnosis.repairPlan.length > 1 ? "s" : ""}...`));
|
|
586
|
-
console.log();
|
|
587
|
-
const repairSpinner = ora().start();
|
|
588
|
-
const result = await executeRepair(projectPath, diagnosis, {
|
|
589
|
-
autoBackup: true,
|
|
590
|
-
dryRun: false,
|
|
591
|
-
onProgress: (step, status) => {
|
|
592
|
-
if (status === "starting") {
|
|
593
|
-
repairSpinner.text = chalk.hex("#b4ffb4")(step.friendlyDescription);
|
|
594
|
-
} else if (status === "complete") {
|
|
595
|
-
repairSpinner.succeed(chalk.hex("#5aff5a")(step.friendlyDescription));
|
|
596
|
-
repairSpinner.start();
|
|
597
|
-
} else if (status === "failed") {
|
|
598
|
-
repairSpinner.fail(chalk.red(step.friendlyDescription));
|
|
599
|
-
repairSpinner.start();
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
});
|
|
603
|
-
if (repairSpinner.isSpinning) {
|
|
604
|
-
repairSpinner.stop();
|
|
605
|
-
}
|
|
606
|
-
console.log();
|
|
607
|
-
if (result.success) {
|
|
608
|
-
console.log(chalk.hex("#5aff5a")(` \u2713 All fixed! Resolved ${result.problemsFixed.length} issue${result.problemsFixed.length > 1 ? "s" : ""}.`));
|
|
609
|
-
} else {
|
|
610
|
-
console.log(chalk.yellow(` \u26A0 Partially fixed. Resolved ${result.stepsCompleted}/${result.stepsTotal} issues.`));
|
|
611
|
-
}
|
|
612
|
-
console.log();
|
|
613
|
-
}
|
|
614
|
-
async function handleConflicts(projectPath) {
|
|
615
|
-
const spinner = ora(chalk.hex("#b4ffb4")("Checking for conflicts...")).start();
|
|
616
|
-
const state = await loadState(projectPath);
|
|
617
|
-
let runtime;
|
|
618
|
-
if (state.activeEnvironmentId) {
|
|
619
|
-
const env = state.environments.find((e) => e.id === state.activeEnvironmentId);
|
|
620
|
-
runtime = env?.runtime;
|
|
621
|
-
}
|
|
622
|
-
if (!runtime) {
|
|
623
|
-
spinner.fail("No environment found");
|
|
624
|
-
console.log();
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
const conflicts = await detectRealConflicts(projectPath, runtime);
|
|
628
|
-
spinner.stop();
|
|
629
|
-
console.log();
|
|
630
|
-
if (conflicts.length === 0) {
|
|
631
|
-
console.log(chalk.hex("#5aff5a")(" \u2713 No conflicts found!"));
|
|
632
|
-
console.log(chalk.dim(" All packages are compatible."));
|
|
633
|
-
console.log();
|
|
634
|
-
return;
|
|
635
|
-
}
|
|
636
|
-
console.log(chalk.yellow(` Found ${conflicts.length} conflict${conflicts.length > 1 ? "s" : ""}:`));
|
|
637
|
-
console.log();
|
|
638
|
-
conflicts.slice(0, 3).forEach((conflict) => {
|
|
639
|
-
const icon = conflict.severity === "error" ? chalk.red("\u2717") : chalk.yellow("\u26A0");
|
|
640
|
-
console.log(` ${icon} ${conflict.package1} \u2194 ${conflict.package2}`);
|
|
641
|
-
console.log(chalk.dim(` ${conflict.reason}`));
|
|
642
|
-
if (conflict.suggestion) {
|
|
643
|
-
console.log(chalk.hex("#87cefa")(` \u{1F4A1} ${conflict.suggestion}`));
|
|
644
|
-
}
|
|
645
|
-
});
|
|
646
|
-
if (conflicts.length > 3) {
|
|
647
|
-
console.log(chalk.dim(` ...and ${conflicts.length - 3} more`));
|
|
648
|
-
}
|
|
649
|
-
console.log();
|
|
650
|
-
console.log(chalk.hex("#b4ffb4")(" Attempting to resolve..."));
|
|
651
|
-
console.log();
|
|
652
|
-
const resolveSpinner = ora().start();
|
|
653
|
-
const result = await resolveConflicts(
|
|
654
|
-
projectPath,
|
|
655
|
-
runtime,
|
|
656
|
-
conflicts,
|
|
657
|
-
(message) => {
|
|
658
|
-
resolveSpinner.text = chalk.hex("#b4ffb4")(message);
|
|
659
|
-
}
|
|
660
|
-
);
|
|
661
|
-
if (resolveSpinner.isSpinning) {
|
|
662
|
-
resolveSpinner.stop();
|
|
663
|
-
}
|
|
664
|
-
console.log();
|
|
665
|
-
if (result.success) {
|
|
666
|
-
console.log(chalk.hex("#5aff5a")(" \u2713 All conflicts resolved!"));
|
|
667
|
-
result.resolved.forEach((r) => console.log(chalk.dim(` \u2022 ${r}`)));
|
|
668
|
-
} else {
|
|
669
|
-
if (result.resolved.length > 0) {
|
|
670
|
-
console.log(chalk.hex("#5aff5a")(" Resolved:"));
|
|
671
|
-
result.resolved.forEach((r) => console.log(chalk.dim(` \u2022 ${r}`)));
|
|
672
|
-
console.log();
|
|
673
|
-
}
|
|
674
|
-
console.log(chalk.yellow(" Cannot auto-resolve:"));
|
|
675
|
-
result.remaining.slice(0, 3).forEach(
|
|
676
|
-
(c) => console.log(chalk.dim(` \u2022 ${c.package1} \u2194 ${c.package2}`))
|
|
677
|
-
);
|
|
678
|
-
}
|
|
679
|
-
console.log();
|
|
680
|
-
}
|
|
681
427
|
async function handleHistory(projectPath) {
|
|
682
428
|
const snapshots = await komodo.listSnapshots(projectPath);
|
|
683
429
|
console.log();
|
|
@@ -901,7 +647,7 @@ async function handleUI(projectPath) {
|
|
|
901
647
|
console.log();
|
|
902
648
|
console.log(chalk.hex("#b4ffb4").dim(" Starting dashboard..."));
|
|
903
649
|
try {
|
|
904
|
-
const { startServer } = await import("./server-
|
|
650
|
+
const { startServer } = await import("./server-JOKWCY3W.js");
|
|
905
651
|
await startServer(projectPath, port);
|
|
906
652
|
console.log(chalk.hex("#5aff5a")(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
|
|
907
653
|
console.log();
|
|
@@ -1230,7 +976,7 @@ program.command("ui").description("Open the visual dashboard").option("-p, --pat
|
|
|
1230
976
|
const url = `http://localhost:${port}`;
|
|
1231
977
|
console.log(chalk.dim(" Starting dashboard..."));
|
|
1232
978
|
try {
|
|
1233
|
-
const { startServer } = await import("./server-
|
|
979
|
+
const { startServer } = await import("./server-JOKWCY3W.js");
|
|
1234
980
|
await startServer(options.path, port);
|
|
1235
981
|
console.log();
|
|
1236
982
|
console.log(chalk.green(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
|