komodo-cli 2.0.6 → 2.1.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.
|
@@ -4931,10 +4931,222 @@ async function listSnapshots(basePath, environmentId) {
|
|
|
4931
4931
|
}
|
|
4932
4932
|
return state.snapshots;
|
|
4933
4933
|
}
|
|
4934
|
+
var DEFAULT_MODEL = "llama-3.3-70b";
|
|
4935
|
+
var DEFAULT_MAX_TOKENS = 2048;
|
|
4936
|
+
var DEFAULT_TEMPERATURE = 0.2;
|
|
4937
|
+
var CerebrasAI = class {
|
|
4938
|
+
apiKey;
|
|
4939
|
+
model;
|
|
4940
|
+
maxTokens;
|
|
4941
|
+
temperature;
|
|
4942
|
+
baseUrl = "https://api.cerebras.ai/v1";
|
|
4943
|
+
constructor(config) {
|
|
4944
|
+
this.apiKey = config.apiKey;
|
|
4945
|
+
this.model = config.model ?? DEFAULT_MODEL;
|
|
4946
|
+
this.maxTokens = config.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
4947
|
+
this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;
|
|
4948
|
+
}
|
|
4949
|
+
/**
|
|
4950
|
+
* Make a chat completion request to Cerebras API
|
|
4951
|
+
*/
|
|
4952
|
+
async chatCompletion(messages) {
|
|
4953
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
4954
|
+
method: "POST",
|
|
4955
|
+
headers: {
|
|
4956
|
+
"Content-Type": "application/json",
|
|
4957
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
4958
|
+
},
|
|
4959
|
+
body: JSON.stringify({
|
|
4960
|
+
model: this.model,
|
|
4961
|
+
messages,
|
|
4962
|
+
max_tokens: this.maxTokens,
|
|
4963
|
+
temperature: this.temperature,
|
|
4964
|
+
top_p: 1
|
|
4965
|
+
})
|
|
4966
|
+
});
|
|
4967
|
+
if (!response.ok) {
|
|
4968
|
+
const error = await response.text();
|
|
4969
|
+
throw new Error(`Cerebras API error: ${response.status} - ${error}`);
|
|
4970
|
+
}
|
|
4971
|
+
const data = await response.json();
|
|
4972
|
+
return data.choices[0]?.message?.content ?? "";
|
|
4973
|
+
}
|
|
4974
|
+
/**
|
|
4975
|
+
* Analyze user intent and return comprehensive package recommendations
|
|
4976
|
+
*/
|
|
4977
|
+
async analyzeIntent(userIntent, hardware) {
|
|
4978
|
+
const systemPrompt = this.buildSystemPrompt(hardware);
|
|
4979
|
+
const userPrompt = this.buildUserPrompt(userIntent, hardware);
|
|
4980
|
+
const messages = [
|
|
4981
|
+
{ role: "system", content: systemPrompt },
|
|
4982
|
+
{ role: "user", content: userPrompt }
|
|
4983
|
+
];
|
|
4984
|
+
const response = await this.chatCompletion(messages);
|
|
4985
|
+
return this.parseAIResponse(response);
|
|
4986
|
+
}
|
|
4987
|
+
/**
|
|
4988
|
+
* Build comprehensive system prompt for the AI
|
|
4989
|
+
*/
|
|
4990
|
+
buildSystemPrompt(hardware) {
|
|
4991
|
+
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.
|
|
4992
|
+
|
|
4993
|
+
You are knowledgeable about:
|
|
4994
|
+
- 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
|
|
4995
|
+
- Node.js packages (npm): React, Vue, Next.js, Express, NestJS, and all frontend/backend JavaScript libraries
|
|
4996
|
+
- Hardware optimization: You know which packages work best with different GPUs (NVIDIA CUDA, AMD ROCm, Apple Metal) and CPUs
|
|
4997
|
+
- Version compatibility: You know which package versions work well together
|
|
4998
|
+
|
|
4999
|
+
CRITICAL RULES:
|
|
5000
|
+
1. Always respond with valid JSON only - no markdown, no explanations outside the JSON
|
|
5001
|
+
2. Be thorough - include ALL necessary packages for a complete working setup
|
|
5002
|
+
3. Consider the user's hardware when recommending packages
|
|
5003
|
+
4. Include dev dependencies if relevant (pytest, eslint, prettier, etc.)
|
|
5004
|
+
5. Recommend specific versions when compatibility matters
|
|
5005
|
+
6. If the request is ambiguous, make reasonable assumptions and explain them
|
|
5006
|
+
|
|
5007
|
+
USER'S HARDWARE:
|
|
5008
|
+
- OS: ${hardware.os}
|
|
5009
|
+
- Architecture: ${hardware.arch}
|
|
5010
|
+
- GPU: ${hardware.gpu}${hardware.gpuName ? ` (${hardware.gpuName})` : ""}${hardware.cudaVersion ? `, CUDA ${hardware.cudaVersion}` : ""}
|
|
5011
|
+
- RAM: ${hardware.totalMemoryGb}GB
|
|
5012
|
+
- CPU Cores: ${hardware.cpuCores}
|
|
5013
|
+
|
|
5014
|
+
Based on this hardware, optimize package recommendations accordingly.`;
|
|
5015
|
+
}
|
|
5016
|
+
/**
|
|
5017
|
+
* Build the user prompt with context
|
|
5018
|
+
*/
|
|
5019
|
+
buildUserPrompt(intent, hardware) {
|
|
5020
|
+
return `The user wants to: "${intent}"
|
|
5021
|
+
|
|
5022
|
+
Analyze this request and respond with a JSON object in this exact format:
|
|
5023
|
+
{
|
|
5024
|
+
"goal": "A short, clear name for what they're building (e.g., 'ML Training Pipeline', 'Next.js Blog')",
|
|
5025
|
+
"description": "A brief description of the project and what it will do",
|
|
5026
|
+
"runtime": "python" or "node",
|
|
5027
|
+
"packages": [
|
|
5028
|
+
{
|
|
5029
|
+
"name": "package-name",
|
|
5030
|
+
"version": "specific version or 'latest'",
|
|
5031
|
+
"reason": "Why this package is needed",
|
|
5032
|
+
"optional": false,
|
|
5033
|
+
"alternatives": ["alternative-package"] // optional field
|
|
5034
|
+
}
|
|
5035
|
+
],
|
|
5036
|
+
"setupSteps": [
|
|
5037
|
+
"Step 1 description",
|
|
5038
|
+
"Step 2 description"
|
|
5039
|
+
],
|
|
5040
|
+
"warnings": [
|
|
5041
|
+
"Any warnings about compatibility, memory requirements, etc."
|
|
5042
|
+
],
|
|
5043
|
+
"tips": [
|
|
5044
|
+
"Helpful tips for using the setup"
|
|
5045
|
+
],
|
|
5046
|
+
"confidence": 0.95
|
|
5047
|
+
}
|
|
5048
|
+
|
|
5049
|
+
IMPORTANT:
|
|
5050
|
+
- Include ALL packages needed for a complete, working setup
|
|
5051
|
+
- Order packages by importance (core packages first)
|
|
5052
|
+
- For Python ML on Apple Silicon, use standard torch (Metal support is built-in)
|
|
5053
|
+
- For Python ML on NVIDIA, recommend torch with CUDA
|
|
5054
|
+
- For web projects, include necessary build tools and dev dependencies
|
|
5055
|
+
- If the request mentions specific technologies, include those
|
|
5056
|
+
- If the request is vague, include a sensible default stack
|
|
5057
|
+
|
|
5058
|
+
Respond ONLY with the JSON object, nothing else.`;
|
|
5059
|
+
}
|
|
5060
|
+
/**
|
|
5061
|
+
* Parse the AI response into structured data
|
|
5062
|
+
*/
|
|
5063
|
+
parseAIResponse(response) {
|
|
5064
|
+
let cleaned = response.trim();
|
|
5065
|
+
if (cleaned.startsWith("```json")) {
|
|
5066
|
+
cleaned = cleaned.slice(7);
|
|
5067
|
+
} else if (cleaned.startsWith("```")) {
|
|
5068
|
+
cleaned = cleaned.slice(3);
|
|
5069
|
+
}
|
|
5070
|
+
if (cleaned.endsWith("```")) {
|
|
5071
|
+
cleaned = cleaned.slice(0, -3);
|
|
5072
|
+
}
|
|
5073
|
+
cleaned = cleaned.trim();
|
|
5074
|
+
try {
|
|
5075
|
+
const parsed = JSON.parse(cleaned);
|
|
5076
|
+
return {
|
|
5077
|
+
goal: parsed.goal || "Project Setup",
|
|
5078
|
+
description: parsed.description || "",
|
|
5079
|
+
runtime: this.normalizeRuntime(parsed.runtime),
|
|
5080
|
+
packages: this.normalizePackages(parsed.packages || []),
|
|
5081
|
+
setupSteps: Array.isArray(parsed.setupSteps) ? parsed.setupSteps : [],
|
|
5082
|
+
warnings: Array.isArray(parsed.warnings) ? parsed.warnings : [],
|
|
5083
|
+
tips: Array.isArray(parsed.tips) ? parsed.tips : [],
|
|
5084
|
+
confidence: typeof parsed.confidence === "number" ? parsed.confidence : 0.8
|
|
5085
|
+
};
|
|
5086
|
+
} catch (error) {
|
|
5087
|
+
console.error("Failed to parse AI response:", error);
|
|
5088
|
+
console.error("Raw response:", response);
|
|
5089
|
+
return {
|
|
5090
|
+
goal: "Project Setup",
|
|
5091
|
+
description: "AI analysis failed - using fallback",
|
|
5092
|
+
runtime: "python",
|
|
5093
|
+
packages: [],
|
|
5094
|
+
setupSteps: [],
|
|
5095
|
+
warnings: ["AI response parsing failed - please try again with a clearer description"],
|
|
5096
|
+
tips: [],
|
|
5097
|
+
confidence: 0
|
|
5098
|
+
};
|
|
5099
|
+
}
|
|
5100
|
+
}
|
|
5101
|
+
/**
|
|
5102
|
+
* Normalize runtime string to valid Runtime type
|
|
5103
|
+
*/
|
|
5104
|
+
normalizeRuntime(runtime) {
|
|
5105
|
+
const lower = (runtime || "").toLowerCase();
|
|
5106
|
+
if (lower === "node" || lower === "nodejs" || lower === "javascript" || lower === "js") {
|
|
5107
|
+
return "node";
|
|
5108
|
+
}
|
|
5109
|
+
return "python";
|
|
5110
|
+
}
|
|
5111
|
+
/**
|
|
5112
|
+
* Normalize and validate package recommendations
|
|
5113
|
+
*/
|
|
5114
|
+
normalizePackages(packages) {
|
|
5115
|
+
if (!Array.isArray(packages)) return [];
|
|
5116
|
+
return packages.filter((pkg) => typeof pkg === "object" && pkg !== null).map((pkg) => ({
|
|
5117
|
+
name: String(pkg["name"] || ""),
|
|
5118
|
+
version: String(pkg["version"] || "latest"),
|
|
5119
|
+
reason: String(pkg["reason"] || "Required dependency"),
|
|
5120
|
+
optional: Boolean(pkg["optional"]),
|
|
5121
|
+
alternatives: Array.isArray(pkg["alternatives"]) ? pkg["alternatives"].map(String) : void 0
|
|
5122
|
+
})).filter((pkg) => pkg.name.length > 0);
|
|
5123
|
+
}
|
|
5124
|
+
/**
|
|
5125
|
+
* Convert AI recommendations to ResolvedPackage format for Komodo
|
|
5126
|
+
*/
|
|
5127
|
+
convertToResolvedPackages(recommendations, runtime) {
|
|
5128
|
+
return recommendations.filter((pkg) => !pkg.optional).map((pkg) => ({
|
|
5129
|
+
name: pkg.name,
|
|
5130
|
+
version: pkg.version,
|
|
5131
|
+
runtime,
|
|
5132
|
+
reason: pkg.reason
|
|
5133
|
+
}));
|
|
5134
|
+
}
|
|
5135
|
+
};
|
|
4934
5136
|
var Komodo = class {
|
|
4935
5137
|
hardware;
|
|
4936
|
-
|
|
5138
|
+
ai = null;
|
|
5139
|
+
constructor(apiKey) {
|
|
4937
5140
|
this.hardware = detectHardware();
|
|
5141
|
+
if (apiKey) {
|
|
5142
|
+
this.ai = new CerebrasAI({ apiKey });
|
|
5143
|
+
}
|
|
5144
|
+
}
|
|
5145
|
+
/**
|
|
5146
|
+
* Initialize or update the AI service with an API key
|
|
5147
|
+
*/
|
|
5148
|
+
setApiKey(apiKey) {
|
|
5149
|
+
this.ai = new CerebrasAI({ apiKey });
|
|
4938
5150
|
}
|
|
4939
5151
|
getHardware() {
|
|
4940
5152
|
return this.hardware;
|
|
@@ -4948,13 +5160,61 @@ var Komodo = class {
|
|
|
4948
5160
|
resolve(intent) {
|
|
4949
5161
|
return resolveIntent(intent, this.hardware);
|
|
4950
5162
|
}
|
|
5163
|
+
/**
|
|
5164
|
+
* Use AI to analyze intent - returns detailed recommendations
|
|
5165
|
+
*/
|
|
5166
|
+
async analyzeWithAI(intent, apiKey) {
|
|
5167
|
+
const ai = apiKey ? new CerebrasAI({ apiKey }) : this.ai;
|
|
5168
|
+
if (!ai) {
|
|
5169
|
+
throw new Error("AI not initialized. Provide an API key or call setApiKey() first.");
|
|
5170
|
+
}
|
|
5171
|
+
return ai.analyzeIntent(intent, this.hardware);
|
|
5172
|
+
}
|
|
4951
5173
|
async install(options) {
|
|
4952
|
-
const {
|
|
5174
|
+
const {
|
|
5175
|
+
intent,
|
|
5176
|
+
path: basePath = process.cwd(),
|
|
5177
|
+
dryRun,
|
|
5178
|
+
useAI = true,
|
|
5179
|
+
apiKey,
|
|
5180
|
+
onProgress,
|
|
5181
|
+
onExplanation,
|
|
5182
|
+
onWarning,
|
|
5183
|
+
onTip
|
|
5184
|
+
} = options;
|
|
4953
5185
|
const targetPath = resolve(basePath);
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
const
|
|
5186
|
+
let aiAnalysis;
|
|
5187
|
+
let resolution;
|
|
5188
|
+
const effectiveApiKey = apiKey || process.env["CEREBRAS_API_KEY"];
|
|
5189
|
+
const shouldUseAI = useAI && effectiveApiKey;
|
|
5190
|
+
if (shouldUseAI) {
|
|
5191
|
+
try {
|
|
5192
|
+
onProgress?.("Understanding what you need...");
|
|
5193
|
+
const ai = new CerebrasAI({ apiKey: effectiveApiKey });
|
|
5194
|
+
aiAnalysis = await ai.analyzeIntent(intent, this.hardware);
|
|
5195
|
+
resolution = {
|
|
5196
|
+
packages: ai.convertToResolvedPackages(aiAnalysis.packages, aiAnalysis.runtime),
|
|
5197
|
+
runtime: aiAnalysis.runtime,
|
|
5198
|
+
pythonVersion: aiAnalysis.runtime === "python" ? "3.11" : void 0,
|
|
5199
|
+
nodeVersion: aiAnalysis.runtime === "node" ? "20" : void 0,
|
|
5200
|
+
warnings: aiAnalysis.warnings,
|
|
5201
|
+
explanations: [aiAnalysis.description, ...aiAnalysis.setupSteps]
|
|
5202
|
+
};
|
|
5203
|
+
for (const tip of aiAnalysis.tips) {
|
|
5204
|
+
onTip?.(tip);
|
|
5205
|
+
}
|
|
5206
|
+
onProgress?.(`Setting up: ${aiAnalysis.goal}`);
|
|
5207
|
+
} catch (error) {
|
|
5208
|
+
onProgress?.("AI analysis unavailable, using smart templates...");
|
|
5209
|
+
const parsed = this.parseIntent(intent);
|
|
5210
|
+
resolution = this.resolve(parsed);
|
|
5211
|
+
}
|
|
5212
|
+
} else {
|
|
5213
|
+
onProgress?.("Parsing intent...");
|
|
5214
|
+
const parsed = this.parseIntent(intent);
|
|
5215
|
+
onProgress?.("Resolving packages for your hardware...");
|
|
5216
|
+
resolution = this.resolve(parsed);
|
|
5217
|
+
}
|
|
4958
5218
|
for (const explanation of resolution.explanations) {
|
|
4959
5219
|
onExplanation?.(explanation);
|
|
4960
5220
|
}
|
|
@@ -4966,23 +5226,26 @@ var Komodo = class {
|
|
|
4966
5226
|
success: false,
|
|
4967
5227
|
error: "Could not determine packages for this intent. Try being more specific.",
|
|
4968
5228
|
resolution,
|
|
4969
|
-
hardware: this.hardware
|
|
5229
|
+
hardware: this.hardware,
|
|
5230
|
+
aiAnalysis
|
|
4970
5231
|
};
|
|
4971
5232
|
}
|
|
4972
5233
|
if (dryRun) {
|
|
4973
5234
|
return {
|
|
4974
5235
|
success: true,
|
|
4975
5236
|
resolution,
|
|
4976
|
-
hardware: this.hardware
|
|
5237
|
+
hardware: this.hardware,
|
|
5238
|
+
aiAnalysis
|
|
4977
5239
|
};
|
|
4978
5240
|
}
|
|
4979
5241
|
if (!existsSync3(targetPath)) {
|
|
4980
5242
|
await mkdir3(targetPath, { recursive: true });
|
|
4981
5243
|
}
|
|
4982
5244
|
const environmentId = randomUUID2();
|
|
5245
|
+
const environmentName = aiAnalysis?.goal ?? intent.slice(0, 50);
|
|
4983
5246
|
const environment = {
|
|
4984
5247
|
id: environmentId,
|
|
4985
|
-
name:
|
|
5248
|
+
name: environmentName,
|
|
4986
5249
|
createdAt: /* @__PURE__ */ new Date(),
|
|
4987
5250
|
runtime: resolution.runtime,
|
|
4988
5251
|
path: targetPath,
|
|
@@ -5002,7 +5265,8 @@ var Komodo = class {
|
|
|
5002
5265
|
success: false,
|
|
5003
5266
|
error: envResult.error,
|
|
5004
5267
|
resolution,
|
|
5005
|
-
hardware: this.hardware
|
|
5268
|
+
hardware: this.hardware,
|
|
5269
|
+
aiAnalysis
|
|
5006
5270
|
};
|
|
5007
5271
|
}
|
|
5008
5272
|
const installResult = await installPythonPackages(
|
|
@@ -5015,7 +5279,8 @@ var Komodo = class {
|
|
|
5015
5279
|
success: false,
|
|
5016
5280
|
error: installResult.error,
|
|
5017
5281
|
resolution,
|
|
5018
|
-
hardware: this.hardware
|
|
5282
|
+
hardware: this.hardware,
|
|
5283
|
+
aiAnalysis
|
|
5019
5284
|
};
|
|
5020
5285
|
}
|
|
5021
5286
|
onProgress?.("Saving lockfile...");
|
|
@@ -5032,7 +5297,8 @@ var Komodo = class {
|
|
|
5032
5297
|
success: false,
|
|
5033
5298
|
error: envResult.error,
|
|
5034
5299
|
resolution,
|
|
5035
|
-
hardware: this.hardware
|
|
5300
|
+
hardware: this.hardware,
|
|
5301
|
+
aiAnalysis
|
|
5036
5302
|
};
|
|
5037
5303
|
}
|
|
5038
5304
|
const installResult = await installNodePackages(
|
|
@@ -5045,7 +5311,8 @@ var Komodo = class {
|
|
|
5045
5311
|
success: false,
|
|
5046
5312
|
error: installResult.error,
|
|
5047
5313
|
resolution,
|
|
5048
|
-
hardware: this.hardware
|
|
5314
|
+
hardware: this.hardware,
|
|
5315
|
+
aiAnalysis
|
|
5049
5316
|
};
|
|
5050
5317
|
}
|
|
5051
5318
|
onProgress?.("Saving lockfile...");
|
|
@@ -5057,19 +5324,21 @@ var Komodo = class {
|
|
|
5057
5324
|
state.activeEnvironmentId = environment.id;
|
|
5058
5325
|
await saveState(targetPath, state);
|
|
5059
5326
|
onProgress?.("Creating snapshot for rollback...");
|
|
5060
|
-
await createSnapshot(targetPath, environment, "Initial install");
|
|
5327
|
+
await createSnapshot(targetPath, environment, aiAnalysis?.goal ?? "Initial install");
|
|
5061
5328
|
return {
|
|
5062
5329
|
success: true,
|
|
5063
5330
|
environment,
|
|
5064
5331
|
resolution,
|
|
5065
|
-
hardware: this.hardware
|
|
5332
|
+
hardware: this.hardware,
|
|
5333
|
+
aiAnalysis
|
|
5066
5334
|
};
|
|
5067
5335
|
} catch (error) {
|
|
5068
5336
|
return {
|
|
5069
5337
|
success: false,
|
|
5070
5338
|
error: error instanceof Error ? error.message : "Installation failed",
|
|
5071
5339
|
resolution,
|
|
5072
|
-
hardware: this.hardware
|
|
5340
|
+
hardware: this.hardware,
|
|
5341
|
+
aiAnalysis
|
|
5073
5342
|
};
|
|
5074
5343
|
}
|
|
5075
5344
|
}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
detectConflicts,
|
|
6
6
|
getInstalledPackages,
|
|
7
7
|
loadState
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-5HD3OG64.js";
|
|
9
9
|
|
|
10
10
|
// src/index.ts
|
|
11
11
|
import { Command } from "commander";
|
|
@@ -16,7 +16,9 @@ import * as readline from "readline";
|
|
|
16
16
|
import { createRequire } from "module";
|
|
17
17
|
var require2 = createRequire(import.meta.url);
|
|
18
18
|
var packageJson = require2("../package.json");
|
|
19
|
-
var
|
|
19
|
+
var DEFAULT_API_KEY = "csk-m4vcnx94p854xmvnhxx38chwmxxwtffpnymk2ewexktk3962";
|
|
20
|
+
var API_KEY = process.env.CEREBRAS_API_KEY || DEFAULT_API_KEY;
|
|
21
|
+
var komodo = new Komodo(API_KEY);
|
|
20
22
|
var program = new Command();
|
|
21
23
|
program.name("komodo").description("The simple way to set up your project").version(packageJson.version);
|
|
22
24
|
var gradientColors = [
|
|
@@ -154,10 +156,13 @@ async function handleInstall(intent, projectPath) {
|
|
|
154
156
|
console.log();
|
|
155
157
|
const explanations = [];
|
|
156
158
|
const warnings = [];
|
|
159
|
+
const tips = [];
|
|
157
160
|
const result = await komodo.install({
|
|
158
161
|
intent,
|
|
159
162
|
path: projectPath,
|
|
160
163
|
dryRun: false,
|
|
164
|
+
useAI: true,
|
|
165
|
+
apiKey: API_KEY,
|
|
161
166
|
onProgress: (message) => {
|
|
162
167
|
const friendly = friendlyMessage(message);
|
|
163
168
|
if (spinner.isSpinning) {
|
|
@@ -170,6 +175,9 @@ async function handleInstall(intent, projectPath) {
|
|
|
170
175
|
},
|
|
171
176
|
onWarning: (warning) => {
|
|
172
177
|
warnings.push(friendlyWarning(warning));
|
|
178
|
+
},
|
|
179
|
+
onTip: (tip) => {
|
|
180
|
+
tips.push(tip);
|
|
173
181
|
}
|
|
174
182
|
});
|
|
175
183
|
if (spinner.isSpinning) {
|
|
@@ -177,10 +185,18 @@ async function handleInstall(intent, projectPath) {
|
|
|
177
185
|
}
|
|
178
186
|
console.log();
|
|
179
187
|
if (result.success) {
|
|
188
|
+
if (result.aiAnalysis) {
|
|
189
|
+
console.log(chalk.hex("#5aff5a").bold(` \u2713 ${result.aiAnalysis.goal}`));
|
|
190
|
+
if (result.aiAnalysis.description) {
|
|
191
|
+
console.log(chalk.dim(` ${result.aiAnalysis.description}`));
|
|
192
|
+
}
|
|
193
|
+
console.log();
|
|
194
|
+
}
|
|
180
195
|
if (result.resolution && result.resolution.packages.length > 0) {
|
|
181
196
|
console.log(chalk.hex("#a5ffa5")(" Set up:"));
|
|
182
197
|
result.resolution.packages.forEach((pkg) => {
|
|
183
|
-
|
|
198
|
+
const reason = pkg.reason ? chalk.dim(` - ${pkg.reason}`) : "";
|
|
199
|
+
console.log(chalk.hex("#5aff5a")(` \u2713 ${friendlyPackageName(pkg.name)}`) + reason);
|
|
184
200
|
});
|
|
185
201
|
console.log();
|
|
186
202
|
}
|
|
@@ -191,6 +207,13 @@ async function handleInstall(intent, projectPath) {
|
|
|
191
207
|
});
|
|
192
208
|
console.log();
|
|
193
209
|
}
|
|
210
|
+
if (tips.length > 0) {
|
|
211
|
+
console.log(chalk.hex("#87cefa")(" Tips:"));
|
|
212
|
+
tips.forEach((t) => {
|
|
213
|
+
console.log(chalk.hex("#87cefa")(` \u{1F4A1} ${t}`));
|
|
214
|
+
});
|
|
215
|
+
console.log();
|
|
216
|
+
}
|
|
194
217
|
if (warnings.length > 0) {
|
|
195
218
|
console.log(chalk.yellow(" Heads up:"));
|
|
196
219
|
warnings.forEach((w) => {
|
|
@@ -318,7 +341,7 @@ async function handleUI(projectPath) {
|
|
|
318
341
|
console.log();
|
|
319
342
|
console.log(chalk.hex("#b4ffb4").dim(" Starting dashboard..."));
|
|
320
343
|
try {
|
|
321
|
-
const { startServer } = await import("./server-
|
|
344
|
+
const { startServer } = await import("./server-JMI7KL56.js");
|
|
322
345
|
await startServer(projectPath, port);
|
|
323
346
|
console.log(chalk.hex("#5aff5a")(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
|
|
324
347
|
console.log();
|
|
@@ -350,10 +373,13 @@ program.argument("[intent]", "What you want to build").option("-p, --path <path>
|
|
|
350
373
|
}
|
|
351
374
|
const explanations = [];
|
|
352
375
|
const warnings = [];
|
|
376
|
+
const tips = [];
|
|
353
377
|
const result = await komodo.install({
|
|
354
378
|
intent,
|
|
355
379
|
path: options.path,
|
|
356
380
|
dryRun: options.preview,
|
|
381
|
+
useAI: true,
|
|
382
|
+
apiKey: API_KEY,
|
|
357
383
|
onProgress: (message) => {
|
|
358
384
|
const friendly = friendlyMessage(message);
|
|
359
385
|
if (spinner.isSpinning) {
|
|
@@ -366,6 +392,9 @@ program.argument("[intent]", "What you want to build").option("-p, --path <path>
|
|
|
366
392
|
},
|
|
367
393
|
onWarning: (warning) => {
|
|
368
394
|
warnings.push(friendlyWarning(warning));
|
|
395
|
+
},
|
|
396
|
+
onTip: (tip) => {
|
|
397
|
+
tips.push(tip);
|
|
369
398
|
}
|
|
370
399
|
});
|
|
371
400
|
if (spinner.isSpinning) {
|
|
@@ -373,10 +402,32 @@ program.argument("[intent]", "What you want to build").option("-p, --path <path>
|
|
|
373
402
|
}
|
|
374
403
|
console.log();
|
|
375
404
|
if (result.success) {
|
|
405
|
+
if (result.aiAnalysis) {
|
|
406
|
+
console.log(chalk.green.bold(` \u2713 ${result.aiAnalysis.goal}`));
|
|
407
|
+
if (result.aiAnalysis.description) {
|
|
408
|
+
console.log(chalk.dim(` ${result.aiAnalysis.description}`));
|
|
409
|
+
}
|
|
410
|
+
console.log();
|
|
411
|
+
}
|
|
376
412
|
if (result.resolution && result.resolution.packages.length > 0) {
|
|
377
413
|
console.log(chalk.bold(" Set up:"));
|
|
378
414
|
result.resolution.packages.forEach((pkg) => {
|
|
379
|
-
|
|
415
|
+
const reason = pkg.reason ? chalk.dim(` - ${pkg.reason}`) : "";
|
|
416
|
+
console.log(chalk.green(` \u2713 ${friendlyPackageName(pkg.name)}`) + reason);
|
|
417
|
+
});
|
|
418
|
+
console.log();
|
|
419
|
+
}
|
|
420
|
+
if (result.aiAnalysis && result.aiAnalysis.setupSteps.length > 0) {
|
|
421
|
+
console.log(chalk.dim(" Next steps:"));
|
|
422
|
+
result.aiAnalysis.setupSteps.forEach((step, i) => {
|
|
423
|
+
console.log(chalk.dim(` ${i + 1}. ${step}`));
|
|
424
|
+
});
|
|
425
|
+
console.log();
|
|
426
|
+
}
|
|
427
|
+
if (tips.length > 0) {
|
|
428
|
+
console.log(chalk.hex("#87cefa")(" Tips:"));
|
|
429
|
+
tips.forEach((t) => {
|
|
430
|
+
console.log(chalk.hex("#87cefa")(` \u{1F4A1} ${t}`));
|
|
380
431
|
});
|
|
381
432
|
console.log();
|
|
382
433
|
}
|
|
@@ -437,7 +488,7 @@ program.command("ui").description("Open the visual dashboard").option("-p, --pat
|
|
|
437
488
|
const url = `http://localhost:${port}`;
|
|
438
489
|
console.log(chalk.dim(" Starting dashboard..."));
|
|
439
490
|
try {
|
|
440
|
-
const { startServer } = await import("./server-
|
|
491
|
+
const { startServer } = await import("./server-JMI7KL56.js");
|
|
441
492
|
await startServer(options.path, port);
|
|
442
493
|
console.log();
|
|
443
494
|
console.log(chalk.green(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
|