komodo-cli 2.1.0 → 2.1.1

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.
@@ -4791,7 +4791,14 @@ async function installNodePackages(envPath, packages, onProgress) {
4791
4791
  try {
4792
4792
  for (const spec of packageSpecs) {
4793
4793
  onProgress?.(`Installing ${spec}...`);
4794
- const args = packageManager === "yarn" ? ["add", spec] : ["install", spec];
4794
+ let args;
4795
+ if (packageManager === "yarn") {
4796
+ args = ["add", spec];
4797
+ } else if (packageManager === "pnpm") {
4798
+ args = ["add", spec];
4799
+ } else {
4800
+ args = ["install", "--legacy-peer-deps", spec];
4801
+ }
4795
4802
  await execa2(packageManager, args, { cwd: envPath });
4796
4803
  installedPackages.push(spec);
4797
4804
  }
@@ -5133,6 +5140,186 @@ Respond ONLY with the JSON object, nothing else.`;
5133
5140
  }));
5134
5141
  }
5135
5142
  };
5143
+ var KomodoChat = class {
5144
+ apiKey;
5145
+ model;
5146
+ baseUrl = "https://api.cerebras.ai/v1";
5147
+ conversationHistory = [];
5148
+ context = null;
5149
+ constructor(apiKey, model = "llama-3.3-70b") {
5150
+ this.apiKey = apiKey;
5151
+ this.model = model;
5152
+ }
5153
+ /**
5154
+ * Set the current environment context
5155
+ */
5156
+ setContext(context) {
5157
+ this.context = context;
5158
+ this.conversationHistory = [];
5159
+ }
5160
+ /**
5161
+ * Clear conversation history
5162
+ */
5163
+ clearHistory() {
5164
+ this.conversationHistory = [];
5165
+ }
5166
+ /**
5167
+ * Send a message and get AI response
5168
+ */
5169
+ async chat(userMessage) {
5170
+ if (!this.context) {
5171
+ return {
5172
+ message: "No environment context set. Please run 'komodo list' or set up a project first."
5173
+ };
5174
+ }
5175
+ const systemPrompt = this.buildSystemPrompt();
5176
+ this.conversationHistory.push({
5177
+ role: "user",
5178
+ content: userMessage
5179
+ });
5180
+ const messages = [
5181
+ { role: "system", content: systemPrompt },
5182
+ ...this.conversationHistory
5183
+ ];
5184
+ try {
5185
+ const response = await this.callAPI(messages);
5186
+ this.conversationHistory.push({
5187
+ role: "assistant",
5188
+ content: response
5189
+ });
5190
+ return this.parseResponse(response);
5191
+ } catch (error) {
5192
+ return {
5193
+ message: `Error communicating with AI: ${error instanceof Error ? error.message : "Unknown error"}`
5194
+ };
5195
+ }
5196
+ }
5197
+ /**
5198
+ * Get a quick analysis of the current environment
5199
+ */
5200
+ async analyzeEnvironment() {
5201
+ return this.chat("Analyze my current environment. What's installed, are there any issues, and what do you recommend?");
5202
+ }
5203
+ /**
5204
+ * Get suggestions for what to do next
5205
+ */
5206
+ async getSuggestions() {
5207
+ return this.chat("Based on what I have installed, what are some things I could build or add next?");
5208
+ }
5209
+ /**
5210
+ * Ask about a specific package
5211
+ */
5212
+ async askAboutPackage(packageName) {
5213
+ return this.chat(`Tell me about ${packageName}. Is it installed? Are there any issues with it? Should I update it?`);
5214
+ }
5215
+ /**
5216
+ * Get help fixing conflicts
5217
+ */
5218
+ async getConflictHelp() {
5219
+ return this.chat("I have some package conflicts. Can you explain what's wrong and how to fix them?");
5220
+ }
5221
+ buildSystemPrompt() {
5222
+ const ctx = this.context;
5223
+ const installedList = ctx.installedPackages.length > 0 ? ctx.installedPackages.map((p) => ` - ${p.name}@${p.version}`).join("\n") : " (none)";
5224
+ const conflictsList = ctx.conflicts.length > 0 ? ctx.conflicts.map((c) => ` - ${c.package1} vs ${c.package2}: ${c.reason}`).join("\n") : " (none)";
5225
+ const issuesList = ctx.healthIssues.length > 0 ? ctx.healthIssues.map((i) => ` - [${i.severity}] ${i.title}: ${i.description}`).join("\n") : " (none)";
5226
+ 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.
5227
+
5228
+ CURRENT ENVIRONMENT:
5229
+ - Project: ${ctx.environmentName || "Unknown"}
5230
+ - Path: ${ctx.projectPath}
5231
+ - Runtime: ${ctx.runtime || "Not set"}
5232
+ - Hardware: ${ctx.hardware.os} ${ctx.hardware.arch}, ${ctx.hardware.gpu !== "none" ? ctx.hardware.gpuName || ctx.hardware.gpu : "CPU only"}, ${ctx.hardware.totalMemoryGb}GB RAM
5233
+
5234
+ INSTALLED PACKAGES (${ctx.installedPackages.length}):
5235
+ ${installedList}
5236
+
5237
+ CONFLICTS (${ctx.conflicts.length}):
5238
+ ${conflictsList}
5239
+
5240
+ HEALTH ISSUES (${ctx.healthIssues.length}):
5241
+ ${issuesList}
5242
+
5243
+ YOUR ROLE:
5244
+ 1. Answer questions about the installed packages and environment
5245
+ 2. Explain conflicts and suggest resolutions
5246
+ 3. Recommend packages to add, update, or remove
5247
+ 4. Provide guidance on best practices
5248
+ 5. Suggest what the user could build with their current setup
5249
+
5250
+ RESPONSE FORMAT:
5251
+ Always respond in a helpful, conversational tone. When suggesting actions, be specific about what commands to run or packages to install/remove.
5252
+
5253
+ If you recommend installing, removing, or updating packages, include a JSON block at the end of your response in this format:
5254
+ \`\`\`json
5255
+ {
5256
+ "actions": [
5257
+ {"type": "install", "packages": ["package1", "package2"]},
5258
+ {"type": "remove", "packages": ["old-package"]},
5259
+ {"type": "update", "packages": [{"name": "pkg", "to": "2.0.0"}]}
5260
+ ]
5261
+ }
5262
+ \`\`\`
5263
+
5264
+ Only include the JSON block if you're recommending specific package changes.`;
5265
+ }
5266
+ async callAPI(messages) {
5267
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
5268
+ method: "POST",
5269
+ headers: {
5270
+ "Content-Type": "application/json",
5271
+ "Authorization": `Bearer ${this.apiKey}`
5272
+ },
5273
+ body: JSON.stringify({
5274
+ model: this.model,
5275
+ messages,
5276
+ max_tokens: 2048,
5277
+ temperature: 0.3,
5278
+ top_p: 1
5279
+ })
5280
+ });
5281
+ if (!response.ok) {
5282
+ throw new Error(`API error: ${response.status}`);
5283
+ }
5284
+ const data = await response.json();
5285
+ return data.choices[0]?.message?.content ?? "";
5286
+ }
5287
+ parseResponse(response) {
5288
+ const result = {
5289
+ message: response
5290
+ };
5291
+ const jsonMatch = response.match(/```json\s*([\s\S]*?)\s*```/);
5292
+ if (jsonMatch && jsonMatch[1]) {
5293
+ try {
5294
+ const actions = JSON.parse(jsonMatch[1]);
5295
+ if (actions.actions) {
5296
+ result.actions = actions.actions;
5297
+ result.packages = {
5298
+ toInstall: [],
5299
+ toRemove: [],
5300
+ toUpdate: []
5301
+ };
5302
+ for (const action of actions.actions) {
5303
+ if (action.type === "install" && action.packages) {
5304
+ result.packages.toInstall.push(...action.packages);
5305
+ } else if (action.type === "remove" && action.packages) {
5306
+ result.packages.toRemove.push(...action.packages);
5307
+ } else if (action.type === "update" && action.packages) {
5308
+ result.packages.toUpdate.push(...action.packages);
5309
+ }
5310
+ }
5311
+ }
5312
+ result.message = response.replace(/```json\s*[\s\S]*?\s*```/, "").trim();
5313
+ } catch {
5314
+ }
5315
+ }
5316
+ const suggestionMatch = response.match(/(?:suggestions?|recommend|could|try)[:.]?\s*\n((?:\s*[-•*]\s*.+\n?)+)/i);
5317
+ if (suggestionMatch && suggestionMatch[1]) {
5318
+ result.suggestions = suggestionMatch[1].split("\n").map((s) => s.replace(/^\s*[-•*]\s*/, "").trim()).filter((s) => s.length > 0);
5319
+ }
5320
+ return result;
5321
+ }
5322
+ };
5136
5323
  var Komodo = class {
5137
5324
  hardware;
5138
5325
  ai = null;
@@ -5522,6 +5709,7 @@ export {
5522
5709
  __commonJS,
5523
5710
  __toESM,
5524
5711
  loadState,
5712
+ KomodoChat,
5525
5713
  Komodo,
5526
5714
  getInstalledPackages,
5527
5715
  detectConflicts,
package/dist/index.js CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  Komodo,
4
+ KomodoChat,
4
5
  analyzeHealth,
5
6
  detectConflicts,
6
7
  getInstalledPackages,
7
8
  loadState
8
- } from "./chunk-5HD3OG64.js";
9
+ } from "./chunk-VHGNG7AW.js";
9
10
 
10
11
  // src/index.ts
11
12
  import { Command } from "commander";
@@ -19,6 +20,7 @@ var packageJson = require2("../package.json");
19
20
  var DEFAULT_API_KEY = "csk-m4vcnx94p854xmvnhxx38chwmxxwtffpnymk2ewexktk3962";
20
21
  var API_KEY = process.env.CEREBRAS_API_KEY || DEFAULT_API_KEY;
21
22
  var komodo = new Komodo(API_KEY);
23
+ var chat = new KomodoChat(API_KEY);
22
24
  var program = new Command();
23
25
  program.name("komodo").description("The simple way to set up your project").version(packageJson.version);
24
26
  var gradientColors = [
@@ -70,13 +72,90 @@ function formatGpu(hardware) {
70
72
  }
71
73
  return "CPU";
72
74
  }
75
+ async function updateChatContext(projectPath) {
76
+ const hardware = komodo.getHardware();
77
+ const state = await loadState(projectPath);
78
+ let installedPackages = [];
79
+ let conflicts = [];
80
+ let healthIssues = [];
81
+ let runtime;
82
+ let environmentName;
83
+ if (state.activeEnvironmentId) {
84
+ const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
85
+ if (activeEnv) {
86
+ runtime = activeEnv.runtime;
87
+ environmentName = activeEnv.name;
88
+ installedPackages = await getInstalledPackages(projectPath, activeEnv.runtime);
89
+ conflicts = detectConflicts(installedPackages);
90
+ const health = analyzeHealth(installedPackages, conflicts);
91
+ healthIssues = health.issues;
92
+ }
93
+ }
94
+ const context = {
95
+ hardware,
96
+ runtime,
97
+ installedPackages,
98
+ conflicts,
99
+ healthIssues,
100
+ projectPath,
101
+ environmentName
102
+ };
103
+ chat.setContext(context);
104
+ return { installedPackages, conflicts, healthIssues, runtime, environmentName };
105
+ }
106
+ function isAIQuestion(input) {
107
+ const lowerInput = input.toLowerCase();
108
+ if (input.endsWith("?")) return true;
109
+ const questionWords = ["what", "why", "how", "when", "where", "which", "who", "can", "could", "should", "would", "is", "are", "do", "does", "tell me", "explain", "show me", "help me"];
110
+ if (questionWords.some((w) => lowerInput.startsWith(w))) return true;
111
+ const envKeywords = ["installed", "packages", "conflicts", "issues", "problems", "wrong", "fix", "update", "upgrade", "remove", "alternatives", "suggest", "recommend", "analyze", "status"];
112
+ if (envKeywords.some((k) => lowerInput.includes(k))) return true;
113
+ return false;
114
+ }
115
+ function displayAIResponse(response) {
116
+ console.log();
117
+ console.log(chalk.hex("#b4ffb4")(response.message));
118
+ if (response.suggestions && response.suggestions.length > 0) {
119
+ console.log();
120
+ console.log(chalk.hex("#87cefa")(" Suggestions:"));
121
+ response.suggestions.forEach((s) => {
122
+ console.log(chalk.hex("#87cefa")(` \u2022 ${s}`));
123
+ });
124
+ }
125
+ if (response.packages) {
126
+ if (response.packages.toInstall && response.packages.toInstall.length > 0) {
127
+ console.log();
128
+ console.log(chalk.hex("#5aff5a")(" Packages to install:"));
129
+ response.packages.toInstall.forEach((p) => {
130
+ console.log(chalk.hex("#5aff5a")(` + ${p}`));
131
+ });
132
+ }
133
+ if (response.packages.toRemove && response.packages.toRemove.length > 0) {
134
+ console.log();
135
+ console.log(chalk.yellow(" Packages to remove:"));
136
+ response.packages.toRemove.forEach((p) => {
137
+ console.log(chalk.yellow(` - ${p}`));
138
+ });
139
+ }
140
+ if (response.packages.toUpdate && response.packages.toUpdate.length > 0) {
141
+ console.log();
142
+ console.log(chalk.hex("#87cefa")(" Packages to update:"));
143
+ response.packages.toUpdate.forEach((p) => {
144
+ console.log(chalk.hex("#87cefa")(` \u2191 ${p.name}: ${p.from} \u2192 ${p.to}`));
145
+ });
146
+ }
147
+ }
148
+ console.log();
149
+ }
73
150
  async function startInteractiveMode(projectPath) {
74
151
  printBanner();
75
152
  const hardware = komodo.getHardware();
76
153
  console.log(chalk.hex("#b4ffb4").dim(` ${formatOs(hardware.os)} \xB7 ${formatGpu(hardware)} \xB7 ${hardware.totalMemoryGb}GB memory`));
77
154
  console.log();
78
- console.log(chalk.hex("#96ff96").dim(" Commands: ") + chalk.hex("#d2ffd2")("undo") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("list") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("check") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("ui") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("exit"));
155
+ console.log(chalk.hex("#96ff96").dim(" Commands: ") + 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"));
156
+ console.log(chalk.dim(" Or just ask anything in natural language!"));
79
157
  console.log();
158
+ await updateChatContext(projectPath);
80
159
  const rl = readline.createInterface({
81
160
  input: process.stdin,
82
161
  output: process.stdout
@@ -103,15 +182,18 @@ async function startInteractiveMode(projectPath) {
103
182
  }
104
183
  if (trimmed === "help" || trimmed === "?") {
105
184
  console.log();
106
- console.log(chalk.hex("#a5ffa5")(" Just type what you want to build:"));
185
+ console.log(chalk.hex("#a5ffa5")(" Just type what you want to build or ask anything:"));
107
186
  console.log(chalk.dim(' "build a website"'));
108
- console.log(chalk.dim(' "train an AI model"'));
109
- console.log(chalk.dim(' "analyze some data"'));
187
+ console.log(chalk.dim(' "what packages are installed?"'));
188
+ console.log(chalk.dim(' "are there any conflicts?"'));
189
+ console.log(chalk.dim(' "suggest alternatives to express"'));
110
190
  console.log();
111
191
  console.log(chalk.hex("#a5ffa5")(" Commands:"));
112
192
  console.log(` ${chalk.hex("#d2ffd2")("undo")} Undo last change`);
113
193
  console.log(` ${chalk.hex("#d2ffd2")("list")} See what's installed`);
114
194
  console.log(` ${chalk.hex("#d2ffd2")("check")} Check for problems`);
195
+ console.log(` ${chalk.hex("#d2ffd2")("ask")} Start AI conversation`);
196
+ console.log(` ${chalk.hex("#d2ffd2")("analyze")} AI analysis of environment`);
115
197
  console.log(` ${chalk.hex("#d2ffd2")("ui")} Open visual dashboard`);
116
198
  console.log(` ${chalk.hex("#d2ffd2")("history")} See past changes`);
117
199
  console.log(` ${chalk.hex("#d2ffd2")("clear")} Clear screen`);
@@ -122,6 +204,7 @@ async function startInteractiveMode(projectPath) {
122
204
  }
123
205
  if (trimmed === "undo") {
124
206
  await handleUndo(projectPath);
207
+ await updateChatContext(projectPath);
125
208
  prompt();
126
209
  return;
127
210
  }
@@ -145,6 +228,41 @@ async function startInteractiveMode(projectPath) {
145
228
  prompt();
146
229
  return;
147
230
  }
231
+ if (trimmed === "analyze" || trimmed === "analyse") {
232
+ const spinner = ora(chalk.hex("#b4ffb4")("Analyzing your environment...")).start();
233
+ await updateChatContext(projectPath);
234
+ const response = await chat.analyzeEnvironment();
235
+ spinner.stop();
236
+ displayAIResponse(response);
237
+ prompt();
238
+ return;
239
+ }
240
+ if (trimmed === "ask" || trimmed.startsWith("ask ")) {
241
+ const question = trimmed === "ask" ? "" : trimmed.slice(4).trim();
242
+ if (!question) {
243
+ console.log();
244
+ console.log(chalk.hex("#b4ffb4")(" Ask me anything about your environment!"));
245
+ console.log(chalk.dim(" Example: ask what should I install for a REST API?"));
246
+ console.log();
247
+ } else {
248
+ const spinner = ora(chalk.hex("#b4ffb4")("Thinking...")).start();
249
+ await updateChatContext(projectPath);
250
+ const response = await chat.chat(question);
251
+ spinner.stop();
252
+ displayAIResponse(response);
253
+ }
254
+ prompt();
255
+ return;
256
+ }
257
+ if (isAIQuestion(trimmed)) {
258
+ const spinner = ora(chalk.hex("#b4ffb4")("Thinking...")).start();
259
+ await updateChatContext(projectPath);
260
+ const response = await chat.chat(trimmed);
261
+ spinner.stop();
262
+ displayAIResponse(response);
263
+ prompt();
264
+ return;
265
+ }
148
266
  await handleInstall(trimmed, projectPath);
149
267
  prompt();
150
268
  });
@@ -341,7 +459,7 @@ async function handleUI(projectPath) {
341
459
  console.log();
342
460
  console.log(chalk.hex("#b4ffb4").dim(" Starting dashboard..."));
343
461
  try {
344
- const { startServer } = await import("./server-JMI7KL56.js");
462
+ const { startServer } = await import("./server-2Z47U3WP.js");
345
463
  await startServer(projectPath, port);
346
464
  console.log(chalk.hex("#5aff5a")(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
347
465
  console.log();
@@ -488,7 +606,7 @@ program.command("ui").description("Open the visual dashboard").option("-p, --pat
488
606
  const url = `http://localhost:${port}`;
489
607
  console.log(chalk.dim(" Starting dashboard..."));
490
608
  try {
491
- const { startServer } = await import("./server-JMI7KL56.js");
609
+ const { startServer } = await import("./server-2Z47U3WP.js");
492
610
  await startServer(options.path, port);
493
611
  console.log();
494
612
  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-5HD3OG64.js";
10
+ } from "./chunk-VHGNG7AW.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.1.0",
3
+ "version": "2.1.1",
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": {