komodo-cli 2.4.0 → 2.6.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.
@@ -5172,7 +5172,6 @@ var KomodoChat = class {
5172
5172
  */
5173
5173
  setContext(context) {
5174
5174
  this.context = context;
5175
- this.conversationHistory = [];
5176
5175
  }
5177
5176
  /**
5178
5177
  * Clear conversation history
@@ -5240,7 +5239,9 @@ var KomodoChat = class {
5240
5239
  const installedList = ctx.installedPackages.length > 0 ? ctx.installedPackages.map((p) => ` - ${p.name}@${p.version}`).join("\n") : " (none)";
5241
5240
  const conflictsList = ctx.conflicts.length > 0 ? ctx.conflicts.map((c) => ` - ${c.package1} vs ${c.package2}: ${c.reason}`).join("\n") : " (none)";
5242
5241
  const issuesList = ctx.healthIssues.length > 0 ? ctx.healthIssues.map((i) => ` - [${i.severity}] ${i.title}: ${i.description}`).join("\n") : " (none)";
5243
- return `You are Komodo AI, a helpful assistant for managing software development environments. You help users understand their installed packages, resolve conflicts, and make smart decisions about their project dependencies.
5242
+ 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.
5243
+
5244
+ 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
5245
 
5245
5246
  CURRENT ENVIRONMENT:
5246
5247
  - Project: ${ctx.environmentName || "Unknown"}
@@ -5257,17 +5258,17 @@ ${conflictsList}
5257
5258
  HEALTH ISSUES (${ctx.healthIssues.length}):
5258
5259
  ${issuesList}
5259
5260
 
5260
- YOUR ROLE:
5261
- 1. Answer questions about the installed packages and environment
5262
- 2. Explain conflicts and suggest resolutions
5263
- 3. Recommend packages to add, update, or remove
5264
- 4. Provide guidance on best practices
5265
- 5. Suggest what the user could build with their current setup
5261
+ RULES:
5262
+ 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."
5263
+ 2. Be concise. 2-4 sentences max for most responses. No walls of text.
5264
+ 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.
5265
+ 4. When you set things up, briefly explain what you're installing and why, then include the actions.
5266
+ 5. If something needs a venv, create it. If packages conflict, fix them. Just handle it.
5267
+ 6. Remember the conversation -- the user might ask follow-up questions.
5266
5268
 
5267
- RESPONSE FORMAT:
5268
- Always respond in a helpful, conversational tone. When suggesting actions, be specific about what commands to run or packages to install/remove.
5269
+ ACTION FORMAT:
5270
+ When you need to install, remove, or update packages, append this JSON at the very end of your response (after your message):
5269
5271
 
5270
- If you recommend installing, removing, or updating packages, include a JSON block at the end of your response in this format:
5271
5272
  \`\`\`json
5272
5273
  {
5273
5274
  "actions": [
@@ -5278,7 +5279,7 @@ If you recommend installing, removing, or updating packages, include a JSON bloc
5278
5279
  }
5279
5280
  \`\`\`
5280
5281
 
5281
- Only include the JSON block if you're recommending specific package changes.`;
5282
+ Only include actions when there are actual packages to change. Your conversational text comes first, then the JSON block at the end.`;
5282
5283
  }
5283
5284
  async callAPI(messages) {
5284
5285
  const response = await fetch(`${this.baseUrl}/chat/completions`, {
package/dist/index.js CHANGED
@@ -31,7 +31,7 @@ import {
31
31
  runDoctor,
32
32
  searchTemplates,
33
33
  visualizeTree
34
- } from "./chunk-JV7H5NE4.js";
34
+ } from "./chunk-7BIJZKAM.js";
35
35
 
36
36
  // src/index.ts
37
37
  import { Command } from "commander";
@@ -127,58 +127,17 @@ async function updateChatContext(projectPath) {
127
127
  chat.setContext(context);
128
128
  return { installedPackages, conflicts, healthIssues, runtime, environmentName };
129
129
  }
130
- function isAIQuestion(input) {
131
- const lowerInput = input.toLowerCase();
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.hex("#96ff96").dim(" Commands: ") + chalk.hex("#d2ffd2")("fix") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("conflicts") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("doctor") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("optimize") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("tree"));
180
- 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")("clear") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("exit"));
181
- console.log(chalk.dim(" Or just type anything in natural language! The AI understands context."));
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({
@@ -194,7 +153,7 @@ async function startInteractiveMode(projectPath) {
194
153
  }
195
154
  if (trimmed === "exit" || trimmed === "quit" || trimmed === "q") {
196
155
  console.log();
197
- console.log(chalk.hex("#a5ffa5")(" See you next time! \u{1F98E}"));
156
+ console.log(chalk.hex("#a5ffa5")(" See you next time!"));
198
157
  console.log();
199
158
  rl.close();
200
159
  process.exit(0);
@@ -207,31 +166,22 @@ async function startInteractiveMode(projectPath) {
207
166
  }
208
167
  if (trimmed === "help" || trimmed === "?") {
209
168
  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"'));
169
+ console.log(chalk.hex("#a5ffa5")(" Just type what you want in plain English:"));
170
+ console.log(chalk.dim(' "set up a venv to train llada 8b"'));
171
+ console.log(chalk.dim(' "install pytorch and transformers"'));
212
172
  console.log(chalk.dim(' "what packages are installed?"'));
213
173
  console.log(chalk.dim(' "are there any conflicts?"'));
214
- console.log(chalk.dim(' "suggest alternatives to express"'));
215
174
  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`);
175
+ console.log(chalk.hex("#a5ffa5")(" Shortcuts:"));
176
+ console.log(` ${chalk.hex("#d2ffd2")("list")} See installed packages`);
228
177
  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`);
178
+ console.log(` ${chalk.hex("#d2ffd2")("fix")} Auto-repair environment`);
179
+ console.log(` ${chalk.hex("#d2ffd2")("conflicts")} Find package conflicts`);
180
+ console.log(` ${chalk.hex("#d2ffd2")("doctor")} Full health audit`);
181
+ console.log(` ${chalk.hex("#d2ffd2")("tree")} Dependency tree`);
182
+ console.log(` ${chalk.hex("#d2ffd2")("undo")} Undo last change`);
233
183
  console.log(` ${chalk.hex("#d2ffd2")("clear")} Clear screen`);
234
- console.log(` ${chalk.hex("#d2ffd2")("exit")} Exit Komodo`);
184
+ console.log(` ${chalk.hex("#d2ffd2")("exit")} Quit Komodo`);
235
185
  console.log();
236
186
  prompt();
237
187
  return;
@@ -242,17 +192,6 @@ async function startInteractiveMode(projectPath) {
242
192
  prompt();
243
193
  return;
244
194
  }
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
195
  if (trimmed === "list" || trimmed === "ls") {
257
196
  await handleList(projectPath);
258
197
  prompt();
@@ -268,11 +207,6 @@ async function startInteractiveMode(projectPath) {
268
207
  prompt();
269
208
  return;
270
209
  }
271
- if (trimmed === "ui") {
272
- await handleUI(projectPath);
273
- prompt();
274
- return;
275
- }
276
210
  if (trimmed === "doctor") {
277
211
  await handleDoctor(projectPath);
278
212
  prompt();
@@ -316,156 +250,85 @@ async function startInteractiveMode(projectPath) {
316
250
  prompt();
317
251
  return;
318
252
  }
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);
253
+ if (trimmed === "ui") {
254
+ await handleUI(projectPath);
325
255
  prompt();
326
256
  return;
327
257
  }
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();
258
+ const spinner = ora(chalk.hex("#b4ffb4")("Thinking...")).start();
259
+ try {
380
260
  await updateChatContext(projectPath);
381
261
  const response = await chat.chat(trimmed);
382
262
  spinner.stop();
383
- displayAIResponse(response);
384
- prompt();
385
- return;
263
+ const cleanMessage = stripMarkdown(response.message);
264
+ console.log();
265
+ console.log(chalk.hex("#b4ffb4")(cleanMessage));
266
+ console.log();
267
+ if (response.packages) {
268
+ 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;
269
+ if (hasActions) {
270
+ await executePackageActions(response.packages, projectPath);
271
+ await updateChatContext(projectPath);
272
+ }
273
+ }
274
+ } catch (error) {
275
+ spinner.fail(chalk.red("Something went wrong"));
276
+ const errMsg = error instanceof Error ? error.message : "Unknown error";
277
+ console.log();
278
+ console.log(chalk.dim(" " + errMsg));
279
+ console.log(chalk.dim(" Try again or type 'help' for options."));
280
+ console.log();
386
281
  }
387
- await handleInstall(trimmed, projectPath);
388
282
  prompt();
389
283
  });
390
284
  };
391
285
  prompt();
392
286
  }
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();
287
+ async function executePackageActions(packages, projectPath) {
288
+ const allActions = [
289
+ ...(packages.toInstall || []).map((p) => ({ type: "install", name: p })),
290
+ ...(packages.toRemove || []).map((p) => ({ type: "remove", name: p })),
291
+ ...(packages.toUpdate || []).map((p) => ({ type: "update", name: p.name, version: p.to }))
292
+ ];
293
+ if (allActions.length === 0) return;
294
+ for (const action of allActions) {
295
+ const spinner = ora();
296
+ try {
297
+ if (action.type === "install") {
298
+ spinner.start(chalk.hex("#b4ffb4")(`Installing ${action.name}...`));
299
+ const result = await komodo.install({
300
+ intent: `install ${action.name}`,
301
+ path: projectPath,
302
+ dryRun: false,
303
+ useAI: false,
304
+ apiKey: CEREBRAS_API_KEY
305
+ });
306
+ spinner.succeed(chalk.hex("#5aff5a")(`Installed ${action.name}`));
307
+ } else if (action.type === "remove") {
308
+ spinner.start(chalk.hex("#b4ffb4")(`Removing ${action.name}...`));
309
+ await komodo.install({
310
+ intent: `uninstall ${action.name}`,
311
+ path: projectPath,
312
+ dryRun: false,
313
+ useAI: false,
314
+ apiKey: CEREBRAS_API_KEY
315
+ });
316
+ spinner.succeed(chalk.yellow(`Removed ${action.name}`));
317
+ } else if (action.type === "update") {
318
+ spinner.start(chalk.hex("#b4ffb4")(`Updating ${action.name}...`));
319
+ await komodo.install({
320
+ intent: `update ${action.name} to ${action.version}`,
321
+ path: projectPath,
322
+ dryRun: false,
323
+ useAI: false,
324
+ apiKey: CEREBRAS_API_KEY
325
+ });
326
+ spinner.succeed(chalk.hex("#87cefa")(`Updated ${action.name}`));
409
327
  }
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);
420
- }
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
- }
432
- 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
- });
440
- console.log();
441
- }
442
- if (explanations.length > 0) {
443
- console.log(chalk.hex("#b4ffb4").dim(" Good to know:"));
444
- explanations.forEach((e) => {
445
- console.log(chalk.dim(` \u2022 ${e}`));
446
- });
447
- console.log();
448
- }
449
- if (tips.length > 0) {
450
- console.log(chalk.hex("#87cefa")(" Tips:"));
451
- tips.forEach((t) => {
452
- console.log(chalk.hex("#87cefa")(` \u{1F4A1} ${t}`));
453
- });
454
- console.log();
328
+ } catch (error) {
329
+ spinner.fail();
330
+ console.error(chalk.red(`Failed to ${action.type} ${action.name}: ${error instanceof Error ? error.message : "Unknown error"}`));
455
331
  }
456
- if (warnings.length > 0) {
457
- console.log(chalk.yellow(" Heads up:"));
458
- warnings.forEach((w) => {
459
- console.log(chalk.yellow(` \u2022 ${w}`));
460
- });
461
- console.log();
462
- }
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
332
  }
470
333
  }
471
334
  async function handleUndo(projectPath) {
@@ -549,135 +412,6 @@ async function handleCheck(projectPath) {
549
412
  }
550
413
  console.log();
551
414
  }
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
415
  async function handleHistory(projectPath) {
682
416
  const snapshots = await komodo.listSnapshots(projectPath);
683
417
  console.log();
@@ -901,7 +635,7 @@ async function handleUI(projectPath) {
901
635
  console.log();
902
636
  console.log(chalk.hex("#b4ffb4").dim(" Starting dashboard..."));
903
637
  try {
904
- const { startServer } = await import("./server-GJZAY4WK.js");
638
+ const { startServer } = await import("./server-EPYAUU24.js");
905
639
  await startServer(projectPath, port);
906
640
  console.log(chalk.hex("#5aff5a")(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
907
641
  console.log();
@@ -1230,7 +964,7 @@ program.command("ui").description("Open the visual dashboard").option("-p, --pat
1230
964
  const url = `http://localhost:${port}`;
1231
965
  console.log(chalk.dim(" Starting dashboard..."));
1232
966
  try {
1233
- const { startServer } = await import("./server-GJZAY4WK.js");
967
+ const { startServer } = await import("./server-EPYAUU24.js");
1234
968
  await startServer(options.path, port);
1235
969
  console.log();
1236
970
  console.log(chalk.green(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
@@ -7,7 +7,7 @@ import {
7
7
  detectConflicts,
8
8
  getInstalledPackages,
9
9
  loadState
10
- } from "./chunk-JV7H5NE4.js";
10
+ } from "./chunk-7BIJZKAM.js";
11
11
 
12
12
  // ../../node_modules/.pnpm/reusify@1.1.0/node_modules/reusify/reusify.js
13
13
  var require_reusify = __commonJS({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "komodo-cli",
3
- "version": "2.4.0",
3
+ "version": "2.6.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": {