komodo-cli 2.0.6 → 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
|
-
|
|
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
|
}
|
|
@@ -4931,10 +4938,402 @@ async function listSnapshots(basePath, environmentId) {
|
|
|
4931
4938
|
}
|
|
4932
4939
|
return state.snapshots;
|
|
4933
4940
|
}
|
|
4941
|
+
var DEFAULT_MODEL = "llama-3.3-70b";
|
|
4942
|
+
var DEFAULT_MAX_TOKENS = 2048;
|
|
4943
|
+
var DEFAULT_TEMPERATURE = 0.2;
|
|
4944
|
+
var CerebrasAI = class {
|
|
4945
|
+
apiKey;
|
|
4946
|
+
model;
|
|
4947
|
+
maxTokens;
|
|
4948
|
+
temperature;
|
|
4949
|
+
baseUrl = "https://api.cerebras.ai/v1";
|
|
4950
|
+
constructor(config) {
|
|
4951
|
+
this.apiKey = config.apiKey;
|
|
4952
|
+
this.model = config.model ?? DEFAULT_MODEL;
|
|
4953
|
+
this.maxTokens = config.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
4954
|
+
this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;
|
|
4955
|
+
}
|
|
4956
|
+
/**
|
|
4957
|
+
* Make a chat completion request to Cerebras API
|
|
4958
|
+
*/
|
|
4959
|
+
async chatCompletion(messages) {
|
|
4960
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
4961
|
+
method: "POST",
|
|
4962
|
+
headers: {
|
|
4963
|
+
"Content-Type": "application/json",
|
|
4964
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
4965
|
+
},
|
|
4966
|
+
body: JSON.stringify({
|
|
4967
|
+
model: this.model,
|
|
4968
|
+
messages,
|
|
4969
|
+
max_tokens: this.maxTokens,
|
|
4970
|
+
temperature: this.temperature,
|
|
4971
|
+
top_p: 1
|
|
4972
|
+
})
|
|
4973
|
+
});
|
|
4974
|
+
if (!response.ok) {
|
|
4975
|
+
const error = await response.text();
|
|
4976
|
+
throw new Error(`Cerebras API error: ${response.status} - ${error}`);
|
|
4977
|
+
}
|
|
4978
|
+
const data = await response.json();
|
|
4979
|
+
return data.choices[0]?.message?.content ?? "";
|
|
4980
|
+
}
|
|
4981
|
+
/**
|
|
4982
|
+
* Analyze user intent and return comprehensive package recommendations
|
|
4983
|
+
*/
|
|
4984
|
+
async analyzeIntent(userIntent, hardware) {
|
|
4985
|
+
const systemPrompt = this.buildSystemPrompt(hardware);
|
|
4986
|
+
const userPrompt = this.buildUserPrompt(userIntent, hardware);
|
|
4987
|
+
const messages = [
|
|
4988
|
+
{ role: "system", content: systemPrompt },
|
|
4989
|
+
{ role: "user", content: userPrompt }
|
|
4990
|
+
];
|
|
4991
|
+
const response = await this.chatCompletion(messages);
|
|
4992
|
+
return this.parseAIResponse(response);
|
|
4993
|
+
}
|
|
4994
|
+
/**
|
|
4995
|
+
* Build comprehensive system prompt for the AI
|
|
4996
|
+
*/
|
|
4997
|
+
buildSystemPrompt(hardware) {
|
|
4998
|
+
return `You are Komodo AI, an expert software environment setup assistant. Your job is to understand what the user wants to build and recommend the exact packages and setup they need.
|
|
4999
|
+
|
|
5000
|
+
You are knowledgeable about:
|
|
5001
|
+
- Python packages (PyPI): ML/AI frameworks (PyTorch, TensorFlow, JAX, transformers, langchain), web frameworks (FastAPI, Django, Flask), data science (pandas, numpy, scikit-learn), and all common Python packages
|
|
5002
|
+
- Node.js packages (npm): React, Vue, Next.js, Express, NestJS, and all frontend/backend JavaScript libraries
|
|
5003
|
+
- Hardware optimization: You know which packages work best with different GPUs (NVIDIA CUDA, AMD ROCm, Apple Metal) and CPUs
|
|
5004
|
+
- Version compatibility: You know which package versions work well together
|
|
5005
|
+
|
|
5006
|
+
CRITICAL RULES:
|
|
5007
|
+
1. Always respond with valid JSON only - no markdown, no explanations outside the JSON
|
|
5008
|
+
2. Be thorough - include ALL necessary packages for a complete working setup
|
|
5009
|
+
3. Consider the user's hardware when recommending packages
|
|
5010
|
+
4. Include dev dependencies if relevant (pytest, eslint, prettier, etc.)
|
|
5011
|
+
5. Recommend specific versions when compatibility matters
|
|
5012
|
+
6. If the request is ambiguous, make reasonable assumptions and explain them
|
|
5013
|
+
|
|
5014
|
+
USER'S HARDWARE:
|
|
5015
|
+
- OS: ${hardware.os}
|
|
5016
|
+
- Architecture: ${hardware.arch}
|
|
5017
|
+
- GPU: ${hardware.gpu}${hardware.gpuName ? ` (${hardware.gpuName})` : ""}${hardware.cudaVersion ? `, CUDA ${hardware.cudaVersion}` : ""}
|
|
5018
|
+
- RAM: ${hardware.totalMemoryGb}GB
|
|
5019
|
+
- CPU Cores: ${hardware.cpuCores}
|
|
5020
|
+
|
|
5021
|
+
Based on this hardware, optimize package recommendations accordingly.`;
|
|
5022
|
+
}
|
|
5023
|
+
/**
|
|
5024
|
+
* Build the user prompt with context
|
|
5025
|
+
*/
|
|
5026
|
+
buildUserPrompt(intent, hardware) {
|
|
5027
|
+
return `The user wants to: "${intent}"
|
|
5028
|
+
|
|
5029
|
+
Analyze this request and respond with a JSON object in this exact format:
|
|
5030
|
+
{
|
|
5031
|
+
"goal": "A short, clear name for what they're building (e.g., 'ML Training Pipeline', 'Next.js Blog')",
|
|
5032
|
+
"description": "A brief description of the project and what it will do",
|
|
5033
|
+
"runtime": "python" or "node",
|
|
5034
|
+
"packages": [
|
|
5035
|
+
{
|
|
5036
|
+
"name": "package-name",
|
|
5037
|
+
"version": "specific version or 'latest'",
|
|
5038
|
+
"reason": "Why this package is needed",
|
|
5039
|
+
"optional": false,
|
|
5040
|
+
"alternatives": ["alternative-package"] // optional field
|
|
5041
|
+
}
|
|
5042
|
+
],
|
|
5043
|
+
"setupSteps": [
|
|
5044
|
+
"Step 1 description",
|
|
5045
|
+
"Step 2 description"
|
|
5046
|
+
],
|
|
5047
|
+
"warnings": [
|
|
5048
|
+
"Any warnings about compatibility, memory requirements, etc."
|
|
5049
|
+
],
|
|
5050
|
+
"tips": [
|
|
5051
|
+
"Helpful tips for using the setup"
|
|
5052
|
+
],
|
|
5053
|
+
"confidence": 0.95
|
|
5054
|
+
}
|
|
5055
|
+
|
|
5056
|
+
IMPORTANT:
|
|
5057
|
+
- Include ALL packages needed for a complete, working setup
|
|
5058
|
+
- Order packages by importance (core packages first)
|
|
5059
|
+
- For Python ML on Apple Silicon, use standard torch (Metal support is built-in)
|
|
5060
|
+
- For Python ML on NVIDIA, recommend torch with CUDA
|
|
5061
|
+
- For web projects, include necessary build tools and dev dependencies
|
|
5062
|
+
- If the request mentions specific technologies, include those
|
|
5063
|
+
- If the request is vague, include a sensible default stack
|
|
5064
|
+
|
|
5065
|
+
Respond ONLY with the JSON object, nothing else.`;
|
|
5066
|
+
}
|
|
5067
|
+
/**
|
|
5068
|
+
* Parse the AI response into structured data
|
|
5069
|
+
*/
|
|
5070
|
+
parseAIResponse(response) {
|
|
5071
|
+
let cleaned = response.trim();
|
|
5072
|
+
if (cleaned.startsWith("```json")) {
|
|
5073
|
+
cleaned = cleaned.slice(7);
|
|
5074
|
+
} else if (cleaned.startsWith("```")) {
|
|
5075
|
+
cleaned = cleaned.slice(3);
|
|
5076
|
+
}
|
|
5077
|
+
if (cleaned.endsWith("```")) {
|
|
5078
|
+
cleaned = cleaned.slice(0, -3);
|
|
5079
|
+
}
|
|
5080
|
+
cleaned = cleaned.trim();
|
|
5081
|
+
try {
|
|
5082
|
+
const parsed = JSON.parse(cleaned);
|
|
5083
|
+
return {
|
|
5084
|
+
goal: parsed.goal || "Project Setup",
|
|
5085
|
+
description: parsed.description || "",
|
|
5086
|
+
runtime: this.normalizeRuntime(parsed.runtime),
|
|
5087
|
+
packages: this.normalizePackages(parsed.packages || []),
|
|
5088
|
+
setupSteps: Array.isArray(parsed.setupSteps) ? parsed.setupSteps : [],
|
|
5089
|
+
warnings: Array.isArray(parsed.warnings) ? parsed.warnings : [],
|
|
5090
|
+
tips: Array.isArray(parsed.tips) ? parsed.tips : [],
|
|
5091
|
+
confidence: typeof parsed.confidence === "number" ? parsed.confidence : 0.8
|
|
5092
|
+
};
|
|
5093
|
+
} catch (error) {
|
|
5094
|
+
console.error("Failed to parse AI response:", error);
|
|
5095
|
+
console.error("Raw response:", response);
|
|
5096
|
+
return {
|
|
5097
|
+
goal: "Project Setup",
|
|
5098
|
+
description: "AI analysis failed - using fallback",
|
|
5099
|
+
runtime: "python",
|
|
5100
|
+
packages: [],
|
|
5101
|
+
setupSteps: [],
|
|
5102
|
+
warnings: ["AI response parsing failed - please try again with a clearer description"],
|
|
5103
|
+
tips: [],
|
|
5104
|
+
confidence: 0
|
|
5105
|
+
};
|
|
5106
|
+
}
|
|
5107
|
+
}
|
|
5108
|
+
/**
|
|
5109
|
+
* Normalize runtime string to valid Runtime type
|
|
5110
|
+
*/
|
|
5111
|
+
normalizeRuntime(runtime) {
|
|
5112
|
+
const lower = (runtime || "").toLowerCase();
|
|
5113
|
+
if (lower === "node" || lower === "nodejs" || lower === "javascript" || lower === "js") {
|
|
5114
|
+
return "node";
|
|
5115
|
+
}
|
|
5116
|
+
return "python";
|
|
5117
|
+
}
|
|
5118
|
+
/**
|
|
5119
|
+
* Normalize and validate package recommendations
|
|
5120
|
+
*/
|
|
5121
|
+
normalizePackages(packages) {
|
|
5122
|
+
if (!Array.isArray(packages)) return [];
|
|
5123
|
+
return packages.filter((pkg) => typeof pkg === "object" && pkg !== null).map((pkg) => ({
|
|
5124
|
+
name: String(pkg["name"] || ""),
|
|
5125
|
+
version: String(pkg["version"] || "latest"),
|
|
5126
|
+
reason: String(pkg["reason"] || "Required dependency"),
|
|
5127
|
+
optional: Boolean(pkg["optional"]),
|
|
5128
|
+
alternatives: Array.isArray(pkg["alternatives"]) ? pkg["alternatives"].map(String) : void 0
|
|
5129
|
+
})).filter((pkg) => pkg.name.length > 0);
|
|
5130
|
+
}
|
|
5131
|
+
/**
|
|
5132
|
+
* Convert AI recommendations to ResolvedPackage format for Komodo
|
|
5133
|
+
*/
|
|
5134
|
+
convertToResolvedPackages(recommendations, runtime) {
|
|
5135
|
+
return recommendations.filter((pkg) => !pkg.optional).map((pkg) => ({
|
|
5136
|
+
name: pkg.name,
|
|
5137
|
+
version: pkg.version,
|
|
5138
|
+
runtime,
|
|
5139
|
+
reason: pkg.reason
|
|
5140
|
+
}));
|
|
5141
|
+
}
|
|
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
|
+
};
|
|
4934
5323
|
var Komodo = class {
|
|
4935
5324
|
hardware;
|
|
4936
|
-
|
|
5325
|
+
ai = null;
|
|
5326
|
+
constructor(apiKey) {
|
|
4937
5327
|
this.hardware = detectHardware();
|
|
5328
|
+
if (apiKey) {
|
|
5329
|
+
this.ai = new CerebrasAI({ apiKey });
|
|
5330
|
+
}
|
|
5331
|
+
}
|
|
5332
|
+
/**
|
|
5333
|
+
* Initialize or update the AI service with an API key
|
|
5334
|
+
*/
|
|
5335
|
+
setApiKey(apiKey) {
|
|
5336
|
+
this.ai = new CerebrasAI({ apiKey });
|
|
4938
5337
|
}
|
|
4939
5338
|
getHardware() {
|
|
4940
5339
|
return this.hardware;
|
|
@@ -4948,13 +5347,61 @@ var Komodo = class {
|
|
|
4948
5347
|
resolve(intent) {
|
|
4949
5348
|
return resolveIntent(intent, this.hardware);
|
|
4950
5349
|
}
|
|
5350
|
+
/**
|
|
5351
|
+
* Use AI to analyze intent - returns detailed recommendations
|
|
5352
|
+
*/
|
|
5353
|
+
async analyzeWithAI(intent, apiKey) {
|
|
5354
|
+
const ai = apiKey ? new CerebrasAI({ apiKey }) : this.ai;
|
|
5355
|
+
if (!ai) {
|
|
5356
|
+
throw new Error("AI not initialized. Provide an API key or call setApiKey() first.");
|
|
5357
|
+
}
|
|
5358
|
+
return ai.analyzeIntent(intent, this.hardware);
|
|
5359
|
+
}
|
|
4951
5360
|
async install(options) {
|
|
4952
|
-
const {
|
|
5361
|
+
const {
|
|
5362
|
+
intent,
|
|
5363
|
+
path: basePath = process.cwd(),
|
|
5364
|
+
dryRun,
|
|
5365
|
+
useAI = true,
|
|
5366
|
+
apiKey,
|
|
5367
|
+
onProgress,
|
|
5368
|
+
onExplanation,
|
|
5369
|
+
onWarning,
|
|
5370
|
+
onTip
|
|
5371
|
+
} = options;
|
|
4953
5372
|
const targetPath = resolve(basePath);
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
const
|
|
5373
|
+
let aiAnalysis;
|
|
5374
|
+
let resolution;
|
|
5375
|
+
const effectiveApiKey = apiKey || process.env["CEREBRAS_API_KEY"];
|
|
5376
|
+
const shouldUseAI = useAI && effectiveApiKey;
|
|
5377
|
+
if (shouldUseAI) {
|
|
5378
|
+
try {
|
|
5379
|
+
onProgress?.("Understanding what you need...");
|
|
5380
|
+
const ai = new CerebrasAI({ apiKey: effectiveApiKey });
|
|
5381
|
+
aiAnalysis = await ai.analyzeIntent(intent, this.hardware);
|
|
5382
|
+
resolution = {
|
|
5383
|
+
packages: ai.convertToResolvedPackages(aiAnalysis.packages, aiAnalysis.runtime),
|
|
5384
|
+
runtime: aiAnalysis.runtime,
|
|
5385
|
+
pythonVersion: aiAnalysis.runtime === "python" ? "3.11" : void 0,
|
|
5386
|
+
nodeVersion: aiAnalysis.runtime === "node" ? "20" : void 0,
|
|
5387
|
+
warnings: aiAnalysis.warnings,
|
|
5388
|
+
explanations: [aiAnalysis.description, ...aiAnalysis.setupSteps]
|
|
5389
|
+
};
|
|
5390
|
+
for (const tip of aiAnalysis.tips) {
|
|
5391
|
+
onTip?.(tip);
|
|
5392
|
+
}
|
|
5393
|
+
onProgress?.(`Setting up: ${aiAnalysis.goal}`);
|
|
5394
|
+
} catch (error) {
|
|
5395
|
+
onProgress?.("AI analysis unavailable, using smart templates...");
|
|
5396
|
+
const parsed = this.parseIntent(intent);
|
|
5397
|
+
resolution = this.resolve(parsed);
|
|
5398
|
+
}
|
|
5399
|
+
} else {
|
|
5400
|
+
onProgress?.("Parsing intent...");
|
|
5401
|
+
const parsed = this.parseIntent(intent);
|
|
5402
|
+
onProgress?.("Resolving packages for your hardware...");
|
|
5403
|
+
resolution = this.resolve(parsed);
|
|
5404
|
+
}
|
|
4958
5405
|
for (const explanation of resolution.explanations) {
|
|
4959
5406
|
onExplanation?.(explanation);
|
|
4960
5407
|
}
|
|
@@ -4966,23 +5413,26 @@ var Komodo = class {
|
|
|
4966
5413
|
success: false,
|
|
4967
5414
|
error: "Could not determine packages for this intent. Try being more specific.",
|
|
4968
5415
|
resolution,
|
|
4969
|
-
hardware: this.hardware
|
|
5416
|
+
hardware: this.hardware,
|
|
5417
|
+
aiAnalysis
|
|
4970
5418
|
};
|
|
4971
5419
|
}
|
|
4972
5420
|
if (dryRun) {
|
|
4973
5421
|
return {
|
|
4974
5422
|
success: true,
|
|
4975
5423
|
resolution,
|
|
4976
|
-
hardware: this.hardware
|
|
5424
|
+
hardware: this.hardware,
|
|
5425
|
+
aiAnalysis
|
|
4977
5426
|
};
|
|
4978
5427
|
}
|
|
4979
5428
|
if (!existsSync3(targetPath)) {
|
|
4980
5429
|
await mkdir3(targetPath, { recursive: true });
|
|
4981
5430
|
}
|
|
4982
5431
|
const environmentId = randomUUID2();
|
|
5432
|
+
const environmentName = aiAnalysis?.goal ?? intent.slice(0, 50);
|
|
4983
5433
|
const environment = {
|
|
4984
5434
|
id: environmentId,
|
|
4985
|
-
name:
|
|
5435
|
+
name: environmentName,
|
|
4986
5436
|
createdAt: /* @__PURE__ */ new Date(),
|
|
4987
5437
|
runtime: resolution.runtime,
|
|
4988
5438
|
path: targetPath,
|
|
@@ -5002,7 +5452,8 @@ var Komodo = class {
|
|
|
5002
5452
|
success: false,
|
|
5003
5453
|
error: envResult.error,
|
|
5004
5454
|
resolution,
|
|
5005
|
-
hardware: this.hardware
|
|
5455
|
+
hardware: this.hardware,
|
|
5456
|
+
aiAnalysis
|
|
5006
5457
|
};
|
|
5007
5458
|
}
|
|
5008
5459
|
const installResult = await installPythonPackages(
|
|
@@ -5015,7 +5466,8 @@ var Komodo = class {
|
|
|
5015
5466
|
success: false,
|
|
5016
5467
|
error: installResult.error,
|
|
5017
5468
|
resolution,
|
|
5018
|
-
hardware: this.hardware
|
|
5469
|
+
hardware: this.hardware,
|
|
5470
|
+
aiAnalysis
|
|
5019
5471
|
};
|
|
5020
5472
|
}
|
|
5021
5473
|
onProgress?.("Saving lockfile...");
|
|
@@ -5032,7 +5484,8 @@ var Komodo = class {
|
|
|
5032
5484
|
success: false,
|
|
5033
5485
|
error: envResult.error,
|
|
5034
5486
|
resolution,
|
|
5035
|
-
hardware: this.hardware
|
|
5487
|
+
hardware: this.hardware,
|
|
5488
|
+
aiAnalysis
|
|
5036
5489
|
};
|
|
5037
5490
|
}
|
|
5038
5491
|
const installResult = await installNodePackages(
|
|
@@ -5045,7 +5498,8 @@ var Komodo = class {
|
|
|
5045
5498
|
success: false,
|
|
5046
5499
|
error: installResult.error,
|
|
5047
5500
|
resolution,
|
|
5048
|
-
hardware: this.hardware
|
|
5501
|
+
hardware: this.hardware,
|
|
5502
|
+
aiAnalysis
|
|
5049
5503
|
};
|
|
5050
5504
|
}
|
|
5051
5505
|
onProgress?.("Saving lockfile...");
|
|
@@ -5057,19 +5511,21 @@ var Komodo = class {
|
|
|
5057
5511
|
state.activeEnvironmentId = environment.id;
|
|
5058
5512
|
await saveState(targetPath, state);
|
|
5059
5513
|
onProgress?.("Creating snapshot for rollback...");
|
|
5060
|
-
await createSnapshot(targetPath, environment, "Initial install");
|
|
5514
|
+
await createSnapshot(targetPath, environment, aiAnalysis?.goal ?? "Initial install");
|
|
5061
5515
|
return {
|
|
5062
5516
|
success: true,
|
|
5063
5517
|
environment,
|
|
5064
5518
|
resolution,
|
|
5065
|
-
hardware: this.hardware
|
|
5519
|
+
hardware: this.hardware,
|
|
5520
|
+
aiAnalysis
|
|
5066
5521
|
};
|
|
5067
5522
|
} catch (error) {
|
|
5068
5523
|
return {
|
|
5069
5524
|
success: false,
|
|
5070
5525
|
error: error instanceof Error ? error.message : "Installation failed",
|
|
5071
5526
|
resolution,
|
|
5072
|
-
hardware: this.hardware
|
|
5527
|
+
hardware: this.hardware,
|
|
5528
|
+
aiAnalysis
|
|
5073
5529
|
};
|
|
5074
5530
|
}
|
|
5075
5531
|
}
|
|
@@ -5253,6 +5709,7 @@ export {
|
|
|
5253
5709
|
__commonJS,
|
|
5254
5710
|
__toESM,
|
|
5255
5711
|
loadState,
|
|
5712
|
+
KomodoChat,
|
|
5256
5713
|
Komodo,
|
|
5257
5714
|
getInstalledPackages,
|
|
5258
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-
|
|
9
|
+
} from "./chunk-VHGNG7AW.js";
|
|
9
10
|
|
|
10
11
|
// src/index.ts
|
|
11
12
|
import { Command } from "commander";
|
|
@@ -16,7 +17,10 @@ import * as readline from "readline";
|
|
|
16
17
|
import { createRequire } from "module";
|
|
17
18
|
var require2 = createRequire(import.meta.url);
|
|
18
19
|
var packageJson = require2("../package.json");
|
|
19
|
-
var
|
|
20
|
+
var DEFAULT_API_KEY = "csk-m4vcnx94p854xmvnhxx38chwmxxwtffpnymk2ewexktk3962";
|
|
21
|
+
var API_KEY = process.env.CEREBRAS_API_KEY || DEFAULT_API_KEY;
|
|
22
|
+
var komodo = new Komodo(API_KEY);
|
|
23
|
+
var chat = new KomodoChat(API_KEY);
|
|
20
24
|
var program = new Command();
|
|
21
25
|
program.name("komodo").description("The simple way to set up your project").version(packageJson.version);
|
|
22
26
|
var gradientColors = [
|
|
@@ -68,13 +72,90 @@ function formatGpu(hardware) {
|
|
|
68
72
|
}
|
|
69
73
|
return "CPU";
|
|
70
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
|
+
}
|
|
71
150
|
async function startInteractiveMode(projectPath) {
|
|
72
151
|
printBanner();
|
|
73
152
|
const hardware = komodo.getHardware();
|
|
74
153
|
console.log(chalk.hex("#b4ffb4").dim(` ${formatOs(hardware.os)} \xB7 ${formatGpu(hardware)} \xB7 ${hardware.totalMemoryGb}GB memory`));
|
|
75
154
|
console.log();
|
|
76
|
-
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")("
|
|
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!"));
|
|
77
157
|
console.log();
|
|
158
|
+
await updateChatContext(projectPath);
|
|
78
159
|
const rl = readline.createInterface({
|
|
79
160
|
input: process.stdin,
|
|
80
161
|
output: process.stdout
|
|
@@ -101,15 +182,18 @@ async function startInteractiveMode(projectPath) {
|
|
|
101
182
|
}
|
|
102
183
|
if (trimmed === "help" || trimmed === "?") {
|
|
103
184
|
console.log();
|
|
104
|
-
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:"));
|
|
105
186
|
console.log(chalk.dim(' "build a website"'));
|
|
106
|
-
console.log(chalk.dim(' "
|
|
107
|
-
console.log(chalk.dim(' "
|
|
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"'));
|
|
108
190
|
console.log();
|
|
109
191
|
console.log(chalk.hex("#a5ffa5")(" Commands:"));
|
|
110
192
|
console.log(` ${chalk.hex("#d2ffd2")("undo")} Undo last change`);
|
|
111
193
|
console.log(` ${chalk.hex("#d2ffd2")("list")} See what's installed`);
|
|
112
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`);
|
|
113
197
|
console.log(` ${chalk.hex("#d2ffd2")("ui")} Open visual dashboard`);
|
|
114
198
|
console.log(` ${chalk.hex("#d2ffd2")("history")} See past changes`);
|
|
115
199
|
console.log(` ${chalk.hex("#d2ffd2")("clear")} Clear screen`);
|
|
@@ -120,6 +204,7 @@ async function startInteractiveMode(projectPath) {
|
|
|
120
204
|
}
|
|
121
205
|
if (trimmed === "undo") {
|
|
122
206
|
await handleUndo(projectPath);
|
|
207
|
+
await updateChatContext(projectPath);
|
|
123
208
|
prompt();
|
|
124
209
|
return;
|
|
125
210
|
}
|
|
@@ -143,6 +228,41 @@ async function startInteractiveMode(projectPath) {
|
|
|
143
228
|
prompt();
|
|
144
229
|
return;
|
|
145
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
|
+
}
|
|
146
266
|
await handleInstall(trimmed, projectPath);
|
|
147
267
|
prompt();
|
|
148
268
|
});
|
|
@@ -154,10 +274,13 @@ async function handleInstall(intent, projectPath) {
|
|
|
154
274
|
console.log();
|
|
155
275
|
const explanations = [];
|
|
156
276
|
const warnings = [];
|
|
277
|
+
const tips = [];
|
|
157
278
|
const result = await komodo.install({
|
|
158
279
|
intent,
|
|
159
280
|
path: projectPath,
|
|
160
281
|
dryRun: false,
|
|
282
|
+
useAI: true,
|
|
283
|
+
apiKey: API_KEY,
|
|
161
284
|
onProgress: (message) => {
|
|
162
285
|
const friendly = friendlyMessage(message);
|
|
163
286
|
if (spinner.isSpinning) {
|
|
@@ -170,6 +293,9 @@ async function handleInstall(intent, projectPath) {
|
|
|
170
293
|
},
|
|
171
294
|
onWarning: (warning) => {
|
|
172
295
|
warnings.push(friendlyWarning(warning));
|
|
296
|
+
},
|
|
297
|
+
onTip: (tip) => {
|
|
298
|
+
tips.push(tip);
|
|
173
299
|
}
|
|
174
300
|
});
|
|
175
301
|
if (spinner.isSpinning) {
|
|
@@ -177,10 +303,18 @@ async function handleInstall(intent, projectPath) {
|
|
|
177
303
|
}
|
|
178
304
|
console.log();
|
|
179
305
|
if (result.success) {
|
|
306
|
+
if (result.aiAnalysis) {
|
|
307
|
+
console.log(chalk.hex("#5aff5a").bold(` \u2713 ${result.aiAnalysis.goal}`));
|
|
308
|
+
if (result.aiAnalysis.description) {
|
|
309
|
+
console.log(chalk.dim(` ${result.aiAnalysis.description}`));
|
|
310
|
+
}
|
|
311
|
+
console.log();
|
|
312
|
+
}
|
|
180
313
|
if (result.resolution && result.resolution.packages.length > 0) {
|
|
181
314
|
console.log(chalk.hex("#a5ffa5")(" Set up:"));
|
|
182
315
|
result.resolution.packages.forEach((pkg) => {
|
|
183
|
-
|
|
316
|
+
const reason = pkg.reason ? chalk.dim(` - ${pkg.reason}`) : "";
|
|
317
|
+
console.log(chalk.hex("#5aff5a")(` \u2713 ${friendlyPackageName(pkg.name)}`) + reason);
|
|
184
318
|
});
|
|
185
319
|
console.log();
|
|
186
320
|
}
|
|
@@ -191,6 +325,13 @@ async function handleInstall(intent, projectPath) {
|
|
|
191
325
|
});
|
|
192
326
|
console.log();
|
|
193
327
|
}
|
|
328
|
+
if (tips.length > 0) {
|
|
329
|
+
console.log(chalk.hex("#87cefa")(" Tips:"));
|
|
330
|
+
tips.forEach((t) => {
|
|
331
|
+
console.log(chalk.hex("#87cefa")(` \u{1F4A1} ${t}`));
|
|
332
|
+
});
|
|
333
|
+
console.log();
|
|
334
|
+
}
|
|
194
335
|
if (warnings.length > 0) {
|
|
195
336
|
console.log(chalk.yellow(" Heads up:"));
|
|
196
337
|
warnings.forEach((w) => {
|
|
@@ -318,7 +459,7 @@ async function handleUI(projectPath) {
|
|
|
318
459
|
console.log();
|
|
319
460
|
console.log(chalk.hex("#b4ffb4").dim(" Starting dashboard..."));
|
|
320
461
|
try {
|
|
321
|
-
const { startServer } = await import("./server-
|
|
462
|
+
const { startServer } = await import("./server-2Z47U3WP.js");
|
|
322
463
|
await startServer(projectPath, port);
|
|
323
464
|
console.log(chalk.hex("#5aff5a")(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
|
|
324
465
|
console.log();
|
|
@@ -350,10 +491,13 @@ program.argument("[intent]", "What you want to build").option("-p, --path <path>
|
|
|
350
491
|
}
|
|
351
492
|
const explanations = [];
|
|
352
493
|
const warnings = [];
|
|
494
|
+
const tips = [];
|
|
353
495
|
const result = await komodo.install({
|
|
354
496
|
intent,
|
|
355
497
|
path: options.path,
|
|
356
498
|
dryRun: options.preview,
|
|
499
|
+
useAI: true,
|
|
500
|
+
apiKey: API_KEY,
|
|
357
501
|
onProgress: (message) => {
|
|
358
502
|
const friendly = friendlyMessage(message);
|
|
359
503
|
if (spinner.isSpinning) {
|
|
@@ -366,6 +510,9 @@ program.argument("[intent]", "What you want to build").option("-p, --path <path>
|
|
|
366
510
|
},
|
|
367
511
|
onWarning: (warning) => {
|
|
368
512
|
warnings.push(friendlyWarning(warning));
|
|
513
|
+
},
|
|
514
|
+
onTip: (tip) => {
|
|
515
|
+
tips.push(tip);
|
|
369
516
|
}
|
|
370
517
|
});
|
|
371
518
|
if (spinner.isSpinning) {
|
|
@@ -373,10 +520,32 @@ program.argument("[intent]", "What you want to build").option("-p, --path <path>
|
|
|
373
520
|
}
|
|
374
521
|
console.log();
|
|
375
522
|
if (result.success) {
|
|
523
|
+
if (result.aiAnalysis) {
|
|
524
|
+
console.log(chalk.green.bold(` \u2713 ${result.aiAnalysis.goal}`));
|
|
525
|
+
if (result.aiAnalysis.description) {
|
|
526
|
+
console.log(chalk.dim(` ${result.aiAnalysis.description}`));
|
|
527
|
+
}
|
|
528
|
+
console.log();
|
|
529
|
+
}
|
|
376
530
|
if (result.resolution && result.resolution.packages.length > 0) {
|
|
377
531
|
console.log(chalk.bold(" Set up:"));
|
|
378
532
|
result.resolution.packages.forEach((pkg) => {
|
|
379
|
-
|
|
533
|
+
const reason = pkg.reason ? chalk.dim(` - ${pkg.reason}`) : "";
|
|
534
|
+
console.log(chalk.green(` \u2713 ${friendlyPackageName(pkg.name)}`) + reason);
|
|
535
|
+
});
|
|
536
|
+
console.log();
|
|
537
|
+
}
|
|
538
|
+
if (result.aiAnalysis && result.aiAnalysis.setupSteps.length > 0) {
|
|
539
|
+
console.log(chalk.dim(" Next steps:"));
|
|
540
|
+
result.aiAnalysis.setupSteps.forEach((step, i) => {
|
|
541
|
+
console.log(chalk.dim(` ${i + 1}. ${step}`));
|
|
542
|
+
});
|
|
543
|
+
console.log();
|
|
544
|
+
}
|
|
545
|
+
if (tips.length > 0) {
|
|
546
|
+
console.log(chalk.hex("#87cefa")(" Tips:"));
|
|
547
|
+
tips.forEach((t) => {
|
|
548
|
+
console.log(chalk.hex("#87cefa")(` \u{1F4A1} ${t}`));
|
|
380
549
|
});
|
|
381
550
|
console.log();
|
|
382
551
|
}
|
|
@@ -437,7 +606,7 @@ program.command("ui").description("Open the visual dashboard").option("-p, --pat
|
|
|
437
606
|
const url = `http://localhost:${port}`;
|
|
438
607
|
console.log(chalk.dim(" Starting dashboard..."));
|
|
439
608
|
try {
|
|
440
|
-
const { startServer } = await import("./server-
|
|
609
|
+
const { startServer } = await import("./server-2Z47U3WP.js");
|
|
441
610
|
await startServer(options.path, port);
|
|
442
611
|
console.log();
|
|
443
612
|
console.log(chalk.green(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
|