komodo-cli 2.1.0 → 2.2.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.
package/dist/index.js CHANGED
@@ -1,11 +1,33 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  Komodo,
4
+ KomodoChat,
5
+ TEMPLATES,
6
+ analyzeEnvironment,
4
7
  analyzeHealth,
8
+ analyzeOptimizations,
9
+ analyzeRepoStructure,
10
+ buildDependencyTree,
5
11
  detectConflicts,
12
+ diffPackages,
13
+ explainPackage,
14
+ formatDiff,
15
+ formatDoctorReport,
16
+ formatExplanation,
17
+ formatInsights,
18
+ formatOptimizationReport,
19
+ formatRepoAnalysis,
20
+ formatTemplateList,
21
+ generateOptimizationScript,
22
+ getInstallCommandsForTemplate,
6
23
  getInstalledPackages,
7
- loadState
8
- } from "./chunk-5HD3OG64.js";
24
+ getTemplateById,
25
+ loadState,
26
+ parseGitHubUrl,
27
+ runDoctor,
28
+ searchTemplates,
29
+ visualizeTree
30
+ } from "./chunk-AR6QW5FH.js";
9
31
 
10
32
  // src/index.ts
11
33
  import { Command } from "commander";
@@ -16,9 +38,10 @@ import * as readline from "readline";
16
38
  import { createRequire } from "module";
17
39
  var require2 = createRequire(import.meta.url);
18
40
  var packageJson = require2("../package.json");
19
- var DEFAULT_API_KEY = "csk-m4vcnx94p854xmvnhxx38chwmxxwtffpnymk2ewexktk3962";
20
- var API_KEY = process.env.CEREBRAS_API_KEY || DEFAULT_API_KEY;
41
+ var DEFAULT_OPENAI_KEY = "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";
42
+ var API_KEY = process.env.OPENAI_API_KEY || DEFAULT_OPENAI_KEY;
21
43
  var komodo = new Komodo(API_KEY);
44
+ var chat = new KomodoChat(API_KEY);
22
45
  var program = new Command();
23
46
  program.name("komodo").description("The simple way to set up your project").version(packageJson.version);
24
47
  var gradientColors = [
@@ -70,13 +93,91 @@ function formatGpu(hardware) {
70
93
  }
71
94
  return "CPU";
72
95
  }
96
+ async function updateChatContext(projectPath) {
97
+ const hardware = komodo.getHardware();
98
+ const state = await loadState(projectPath);
99
+ let installedPackages = [];
100
+ let conflicts = [];
101
+ let healthIssues = [];
102
+ let runtime;
103
+ let environmentName;
104
+ if (state.activeEnvironmentId) {
105
+ const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
106
+ if (activeEnv) {
107
+ runtime = activeEnv.runtime;
108
+ environmentName = activeEnv.name;
109
+ installedPackages = await getInstalledPackages(projectPath, activeEnv.runtime);
110
+ conflicts = detectConflicts(installedPackages);
111
+ const health = analyzeHealth(installedPackages, conflicts);
112
+ healthIssues = health.issues;
113
+ }
114
+ }
115
+ const context = {
116
+ hardware,
117
+ runtime,
118
+ installedPackages,
119
+ conflicts,
120
+ healthIssues,
121
+ projectPath,
122
+ environmentName
123
+ };
124
+ chat.setContext(context);
125
+ return { installedPackages, conflicts, healthIssues, runtime, environmentName };
126
+ }
127
+ function isAIQuestion(input) {
128
+ const lowerInput = input.toLowerCase();
129
+ if (input.endsWith("?")) return true;
130
+ const questionWords = ["what", "why", "how", "when", "where", "which", "who", "can", "could", "should", "would", "is", "are", "do", "does", "tell me", "explain", "show me", "help me"];
131
+ if (questionWords.some((w) => lowerInput.startsWith(w))) return true;
132
+ const envKeywords = ["installed", "packages", "conflicts", "issues", "problems", "wrong", "fix", "update", "upgrade", "remove", "alternatives", "suggest", "recommend", "analyze", "status"];
133
+ if (envKeywords.some((k) => lowerInput.includes(k))) return true;
134
+ return false;
135
+ }
136
+ function displayAIResponse(response) {
137
+ console.log();
138
+ console.log(chalk.hex("#b4ffb4")(response.message));
139
+ if (response.suggestions && response.suggestions.length > 0) {
140
+ console.log();
141
+ console.log(chalk.hex("#87cefa")(" Suggestions:"));
142
+ response.suggestions.forEach((s) => {
143
+ console.log(chalk.hex("#87cefa")(` \u2022 ${s}`));
144
+ });
145
+ }
146
+ if (response.packages) {
147
+ if (response.packages.toInstall && response.packages.toInstall.length > 0) {
148
+ console.log();
149
+ console.log(chalk.hex("#5aff5a")(" Packages to install:"));
150
+ response.packages.toInstall.forEach((p) => {
151
+ console.log(chalk.hex("#5aff5a")(` + ${p}`));
152
+ });
153
+ }
154
+ if (response.packages.toRemove && response.packages.toRemove.length > 0) {
155
+ console.log();
156
+ console.log(chalk.yellow(" Packages to remove:"));
157
+ response.packages.toRemove.forEach((p) => {
158
+ console.log(chalk.yellow(` - ${p}`));
159
+ });
160
+ }
161
+ if (response.packages.toUpdate && response.packages.toUpdate.length > 0) {
162
+ console.log();
163
+ console.log(chalk.hex("#87cefa")(" Packages to update:"));
164
+ response.packages.toUpdate.forEach((p) => {
165
+ console.log(chalk.hex("#87cefa")(` \u2191 ${p.name}: ${p.from} \u2192 ${p.to}`));
166
+ });
167
+ }
168
+ }
169
+ console.log();
170
+ }
73
171
  async function startInteractiveMode(projectPath) {
74
172
  printBanner();
75
173
  const hardware = komodo.getHardware();
76
174
  console.log(chalk.hex("#b4ffb4").dim(` ${formatOs(hardware.os)} \xB7 ${formatGpu(hardware)} \xB7 ${hardware.totalMemoryGb}GB memory`));
77
175
  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"));
176
+ console.log(chalk.hex("#96ff96").dim(" Commands: ") + chalk.hex("#d2ffd2")("doctor") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("optimize") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("tree") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("templates") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("explain"));
177
+ 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")("ask") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("exit"));
178
+ console.log(chalk.dim(" Or just ask anything in natural language!"));
79
179
  console.log();
180
+ await updateChatContext(projectPath);
80
181
  const rl = readline.createInterface({
81
182
  input: process.stdin,
82
183
  output: process.stdout
@@ -103,25 +204,38 @@ async function startInteractiveMode(projectPath) {
103
204
  }
104
205
  if (trimmed === "help" || trimmed === "?") {
105
206
  console.log();
106
- console.log(chalk.hex("#a5ffa5")(" Just type what you want to build:"));
207
+ console.log(chalk.hex("#a5ffa5")(" Just type what you want to build or ask anything:"));
107
208
  console.log(chalk.dim(' "build a website"'));
108
- console.log(chalk.dim(' "train an AI model"'));
109
- console.log(chalk.dim(' "analyze some data"'));
209
+ console.log(chalk.dim(' "what packages are installed?"'));
210
+ console.log(chalk.dim(' "are there any conflicts?"'));
211
+ console.log(chalk.dim(' "suggest alternatives to express"'));
212
+ console.log();
213
+ console.log(chalk.hex("#a5ffa5")(" Premium Commands:"));
214
+ console.log(` ${chalk.hex("#d2ffd2")("doctor")} Full health audit with security scan`);
215
+ console.log(` ${chalk.hex("#d2ffd2")("optimize")} Find ways to reduce bloat`);
216
+ console.log(` ${chalk.hex("#d2ffd2")("tree")} Visualize dependency tree`);
217
+ console.log(` ${chalk.hex("#d2ffd2")("templates")} Browse pre-built environment templates`);
218
+ console.log(` ${chalk.hex("#d2ffd2")("explain")} Get info about any package (e.g. explain torch)`);
219
+ console.log(` ${chalk.hex("#d2ffd2")("clone")} Set up from GitHub URL`);
220
+ console.log(` ${chalk.hex("#d2ffd2")("insights")} Analytics and insights`);
110
221
  console.log();
111
- console.log(chalk.hex("#a5ffa5")(" Commands:"));
112
- console.log(` ${chalk.hex("#d2ffd2")("undo")} Undo last change`);
113
- console.log(` ${chalk.hex("#d2ffd2")("list")} See what's installed`);
114
- console.log(` ${chalk.hex("#d2ffd2")("check")} Check for problems`);
115
- console.log(` ${chalk.hex("#d2ffd2")("ui")} Open visual dashboard`);
116
- console.log(` ${chalk.hex("#d2ffd2")("history")} See past changes`);
117
- console.log(` ${chalk.hex("#d2ffd2")("clear")} Clear screen`);
118
- console.log(` ${chalk.hex("#d2ffd2")("exit")} Exit Komodo`);
222
+ console.log(chalk.hex("#a5ffa5")(" Basic Commands:"));
223
+ console.log(` ${chalk.hex("#d2ffd2")("undo")} Undo last change`);
224
+ console.log(` ${chalk.hex("#d2ffd2")("list")} See what's installed`);
225
+ console.log(` ${chalk.hex("#d2ffd2")("check")} Check for problems`);
226
+ console.log(` ${chalk.hex("#d2ffd2")("ask")} Start AI conversation`);
227
+ console.log(` ${chalk.hex("#d2ffd2")("analyze")} AI analysis of environment`);
228
+ console.log(` ${chalk.hex("#d2ffd2")("ui")} Open visual dashboard`);
229
+ console.log(` ${chalk.hex("#d2ffd2")("history")} See past changes`);
230
+ console.log(` ${chalk.hex("#d2ffd2")("clear")} Clear screen`);
231
+ console.log(` ${chalk.hex("#d2ffd2")("exit")} Exit Komodo`);
119
232
  console.log();
120
233
  prompt();
121
234
  return;
122
235
  }
123
236
  if (trimmed === "undo") {
124
237
  await handleUndo(projectPath);
238
+ await updateChatContext(projectPath);
125
239
  prompt();
126
240
  return;
127
241
  }
@@ -145,6 +259,84 @@ async function startInteractiveMode(projectPath) {
145
259
  prompt();
146
260
  return;
147
261
  }
262
+ if (trimmed === "doctor") {
263
+ await handleDoctor(projectPath);
264
+ prompt();
265
+ return;
266
+ }
267
+ if (trimmed === "optimize") {
268
+ await handleOptimize(projectPath);
269
+ prompt();
270
+ return;
271
+ }
272
+ if (trimmed === "tree") {
273
+ await handleTree(projectPath);
274
+ prompt();
275
+ return;
276
+ }
277
+ if (trimmed === "templates" || trimmed === "template") {
278
+ await handleTemplates();
279
+ prompt();
280
+ return;
281
+ }
282
+ if (trimmed.startsWith("template ") || trimmed.startsWith("use ")) {
283
+ const templateId = trimmed.replace(/^(template|use)\s+/, "").trim();
284
+ await handleUseTemplate(templateId, projectPath);
285
+ prompt();
286
+ return;
287
+ }
288
+ if (trimmed.startsWith("explain ")) {
289
+ const packageName = trimmed.slice(8).trim();
290
+ await handleExplain(packageName);
291
+ prompt();
292
+ return;
293
+ }
294
+ if (trimmed.startsWith("clone ") || trimmed.startsWith("setup ")) {
295
+ const url = trimmed.replace(/^(clone|setup)\s+/, "").trim();
296
+ await handleClone(url);
297
+ prompt();
298
+ return;
299
+ }
300
+ if (trimmed === "insights" || trimmed === "analytics") {
301
+ await handleInsights(projectPath);
302
+ prompt();
303
+ return;
304
+ }
305
+ if (trimmed === "analyze" || trimmed === "analyse") {
306
+ const spinner = ora(chalk.hex("#b4ffb4")("Analyzing your environment...")).start();
307
+ await updateChatContext(projectPath);
308
+ const response = await chat.analyzeEnvironment();
309
+ spinner.stop();
310
+ displayAIResponse(response);
311
+ prompt();
312
+ return;
313
+ }
314
+ if (trimmed === "ask" || trimmed.startsWith("ask ")) {
315
+ const question = trimmed === "ask" ? "" : trimmed.slice(4).trim();
316
+ if (!question) {
317
+ console.log();
318
+ console.log(chalk.hex("#b4ffb4")(" Ask me anything about your environment!"));
319
+ console.log(chalk.dim(" Example: ask what should I install for a REST API?"));
320
+ console.log();
321
+ } else {
322
+ const spinner = ora(chalk.hex("#b4ffb4")("Thinking...")).start();
323
+ await updateChatContext(projectPath);
324
+ const response = await chat.chat(question);
325
+ spinner.stop();
326
+ displayAIResponse(response);
327
+ }
328
+ prompt();
329
+ return;
330
+ }
331
+ if (isAIQuestion(trimmed)) {
332
+ const spinner = ora(chalk.hex("#b4ffb4")("Thinking...")).start();
333
+ await updateChatContext(projectPath);
334
+ const response = await chat.chat(trimmed);
335
+ spinner.stop();
336
+ displayAIResponse(response);
337
+ prompt();
338
+ return;
339
+ }
148
340
  await handleInstall(trimmed, projectPath);
149
341
  prompt();
150
342
  });
@@ -335,13 +527,205 @@ async function handleHistory(projectPath) {
335
527
  console.log(chalk.dim(" Type 'undo' to go back to the previous state"));
336
528
  console.log();
337
529
  }
530
+ async function handleDoctor(projectPath) {
531
+ const spinner = ora(chalk.hex("#b4ffb4")("Running comprehensive health audit...")).start();
532
+ const state = await loadState(projectPath);
533
+ const hardware = komodo.getHardware();
534
+ if (!state.activeEnvironmentId) {
535
+ spinner.succeed(chalk.dim("No environment to analyze - set something up first"));
536
+ console.log();
537
+ return;
538
+ }
539
+ const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
540
+ if (!activeEnv) {
541
+ spinner.succeed(chalk.dim("Nothing to analyze"));
542
+ console.log();
543
+ return;
544
+ }
545
+ const installed = await getInstalledPackages(projectPath, activeEnv.runtime);
546
+ const report = runDoctor(installed, hardware);
547
+ spinner.stop();
548
+ console.log();
549
+ console.log(formatDoctorReport(report, true));
550
+ console.log();
551
+ }
552
+ async function handleOptimize(projectPath) {
553
+ const spinner = ora(chalk.hex("#b4ffb4")("Analyzing optimization opportunities...")).start();
554
+ const state = await loadState(projectPath);
555
+ const hardware = komodo.getHardware();
556
+ if (!state.activeEnvironmentId) {
557
+ spinner.succeed(chalk.dim("No environment to optimize - set something up first"));
558
+ console.log();
559
+ return;
560
+ }
561
+ const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
562
+ if (!activeEnv) {
563
+ spinner.succeed(chalk.dim("Nothing to optimize"));
564
+ console.log();
565
+ return;
566
+ }
567
+ const installed = await getInstalledPackages(projectPath, activeEnv.runtime);
568
+ const report = analyzeOptimizations(installed, hardware);
569
+ spinner.stop();
570
+ console.log();
571
+ console.log(formatOptimizationReport(report, true));
572
+ console.log();
573
+ }
574
+ async function handleTree(projectPath) {
575
+ const spinner = ora(chalk.hex("#b4ffb4")("Building dependency tree...")).start();
576
+ const state = await loadState(projectPath);
577
+ if (!state.activeEnvironmentId) {
578
+ spinner.succeed(chalk.dim("No dependencies to visualize - set something up first"));
579
+ console.log();
580
+ return;
581
+ }
582
+ const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
583
+ if (!activeEnv) {
584
+ spinner.succeed(chalk.dim("Nothing to visualize"));
585
+ console.log();
586
+ return;
587
+ }
588
+ const installed = await getInstalledPackages(projectPath, activeEnv.runtime);
589
+ const tree = buildDependencyTree(installed);
590
+ const visualization = visualizeTree(tree, { colorize: true, showSizes: true });
591
+ spinner.stop();
592
+ console.log();
593
+ console.log(visualization.ascii);
594
+ console.log();
595
+ console.log(chalk.hex("#b4ffb4").bold(" Stats:"));
596
+ console.log(` Total packages: ${visualization.stats.totalPackages}`);
597
+ console.log(` Direct dependencies: ${visualization.stats.directDependencies}`);
598
+ console.log(` Max depth: ${visualization.stats.maxDepth}`);
599
+ console.log();
600
+ }
601
+ async function handleTemplates(query) {
602
+ console.log();
603
+ if (query) {
604
+ const results = searchTemplates(query);
605
+ if (results.length === 0) {
606
+ console.log(chalk.dim(` No templates found for "${query}"`));
607
+ } else {
608
+ console.log(formatTemplateList(results, true));
609
+ }
610
+ } else {
611
+ console.log(chalk.hex("#a5ffa5").bold(" Available Templates"));
612
+ console.log(chalk.dim(" Use 'template <id>' to set up"));
613
+ console.log();
614
+ console.log(formatTemplateList(TEMPLATES, true));
615
+ }
616
+ console.log();
617
+ }
618
+ async function handleUseTemplate(templateId, projectPath) {
619
+ const template = getTemplateById(templateId);
620
+ if (!template) {
621
+ console.log();
622
+ console.log(chalk.red(` Template "${templateId}" not found`));
623
+ console.log(chalk.dim(" Run 'templates' to see available options"));
624
+ console.log();
625
+ return;
626
+ }
627
+ console.log();
628
+ console.log(chalk.hex("#a5ffa5").bold(` ${template.name}`));
629
+ console.log(chalk.dim(` ${template.description}`));
630
+ console.log();
631
+ const commands = getInstallCommandsForTemplate(template);
632
+ console.log(chalk.hex("#b4ffb4")(" Packages:"));
633
+ template.packages.filter((p) => !p.optional).forEach((pkg) => {
634
+ const note = pkg.note ? chalk.dim(` - ${pkg.note}`) : "";
635
+ console.log(` ${chalk.hex("#5aff5a")("+")} ${pkg.name}${note}`);
636
+ });
637
+ console.log();
638
+ console.log(chalk.hex("#b4ffb4")(" Commands to run:"));
639
+ commands.forEach((cmd) => {
640
+ console.log(chalk.cyan(` $ ${cmd}`));
641
+ });
642
+ console.log();
643
+ const packageNames = template.packages.filter((p) => !p.optional).map((p) => p.name);
644
+ const intent = `install ${packageNames.join(" ")}`;
645
+ const spinner = ora(chalk.hex("#b4ffb4")("Setting up template...")).start();
646
+ const result = await komodo.install({
647
+ intent,
648
+ path: projectPath,
649
+ dryRun: false,
650
+ useAI: false
651
+ });
652
+ if (result.success) {
653
+ spinner.succeed(chalk.hex("#5aff5a")("Template set up successfully!"));
654
+ } else {
655
+ spinner.fail(chalk.red(result.error || "Failed to set up template"));
656
+ }
657
+ console.log();
658
+ }
659
+ async function handleExplain(packageName) {
660
+ console.log();
661
+ const explanation = explainPackage(packageName);
662
+ if (!explanation) {
663
+ console.log(chalk.dim(` No information found for "${packageName}"`));
664
+ console.log(chalk.dim(" Try searching for common packages like torch, react, pandas, etc."));
665
+ console.log();
666
+ return;
667
+ }
668
+ console.log(formatExplanation(explanation, true));
669
+ console.log();
670
+ }
671
+ async function handleClone(url) {
672
+ console.log();
673
+ const parsed = parseGitHubUrl(url);
674
+ if (!parsed) {
675
+ console.log(chalk.red(" Invalid GitHub URL"));
676
+ console.log(chalk.dim(" Example: komodo clone https://github.com/owner/repo"));
677
+ console.log();
678
+ return;
679
+ }
680
+ const spinner = ora(chalk.hex("#b4ffb4")(`Analyzing ${parsed.owner}/${parsed.repo}...`)).start();
681
+ const mockFiles = {
682
+ "requirements.txt": "torch\ntransformers\nnumpy",
683
+ "README.md": "# Project\n\nInstall with pip install -r requirements.txt"
684
+ };
685
+ const analysis = analyzeRepoStructure(mockFiles);
686
+ analysis.url = url;
687
+ analysis.name = parsed.repo;
688
+ spinner.stop();
689
+ console.log();
690
+ console.log(formatRepoAnalysis(analysis, true));
691
+ console.log();
692
+ console.log(chalk.hex("#b4ffb4").bold(" Quick Setup:"));
693
+ console.log(chalk.cyan(` $ git clone ${url}`));
694
+ console.log(chalk.cyan(` $ cd ${parsed.repo}`));
695
+ for (const cmd of analysis.setupCommands) {
696
+ console.log(chalk.cyan(` $ ${cmd}`));
697
+ }
698
+ console.log();
699
+ }
700
+ async function handleInsights(projectPath) {
701
+ const spinner = ora(chalk.hex("#b4ffb4")("Gathering insights...")).start();
702
+ const state = await loadState(projectPath);
703
+ if (!state.activeEnvironmentId) {
704
+ spinner.succeed(chalk.dim("No environment to analyze - set something up first"));
705
+ console.log();
706
+ return;
707
+ }
708
+ const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
709
+ if (!activeEnv) {
710
+ spinner.succeed(chalk.dim("Nothing to analyze"));
711
+ console.log();
712
+ return;
713
+ }
714
+ const installed = await getInstalledPackages(projectPath, activeEnv.runtime);
715
+ const snapshots = await komodo.listSnapshots(projectPath);
716
+ const insights = analyzeEnvironment(installed, snapshots);
717
+ spinner.stop();
718
+ console.log();
719
+ console.log(formatInsights(insights, true));
720
+ console.log();
721
+ }
338
722
  async function handleUI(projectPath) {
339
723
  const port = 3333;
340
724
  const url = `http://localhost:${port}`;
341
725
  console.log();
342
726
  console.log(chalk.hex("#b4ffb4").dim(" Starting dashboard..."));
343
727
  try {
344
- const { startServer } = await import("./server-JMI7KL56.js");
728
+ const { startServer } = await import("./server-LCQG53IY.js");
345
729
  await startServer(projectPath, port);
346
730
  console.log(chalk.hex("#5aff5a")(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
347
731
  console.log();
@@ -488,7 +872,7 @@ program.command("ui").description("Open the visual dashboard").option("-p, --pat
488
872
  const url = `http://localhost:${port}`;
489
873
  console.log(chalk.dim(" Starting dashboard..."));
490
874
  try {
491
- const { startServer } = await import("./server-JMI7KL56.js");
875
+ const { startServer } = await import("./server-LCQG53IY.js");
492
876
  await startServer(options.path, port);
493
877
  console.log();
494
878
  console.log(chalk.green(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
@@ -586,6 +970,99 @@ program.command("check").description("Check if everything is working").option("-
586
970
  }
587
971
  console.log();
588
972
  });
973
+ program.command("doctor").description("Run comprehensive health audit with security scan").option("-p, --path <path>", "Project folder", process.cwd()).action(async (options) => {
974
+ console.log();
975
+ console.log(chalk.bold("\u{1F98E} Komodo Doctor"));
976
+ console.log();
977
+ await handleDoctor(options.path);
978
+ });
979
+ program.command("optimize").description("Find ways to reduce environment size").option("-p, --path <path>", "Project folder", process.cwd()).option("--script", "Generate optimization script").action(async (options) => {
980
+ console.log();
981
+ console.log(chalk.bold("\u{1F98E} Komodo Optimizer"));
982
+ console.log();
983
+ const state = await loadState(options.path);
984
+ if (!state.activeEnvironmentId) {
985
+ console.log(chalk.dim(" No environment to optimize"));
986
+ return;
987
+ }
988
+ const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
989
+ if (!activeEnv) return;
990
+ const installed = await getInstalledPackages(options.path, activeEnv.runtime);
991
+ const hardware = komodo.getHardware();
992
+ const report = analyzeOptimizations(installed, hardware);
993
+ if (options.script) {
994
+ const script = generateOptimizationScript(report.suggestions, true);
995
+ console.log(script);
996
+ } else {
997
+ console.log(formatOptimizationReport(report, true));
998
+ }
999
+ });
1000
+ program.command("tree").description("Visualize dependency tree").option("-p, --path <path>", "Project folder", process.cwd()).option("--depth <n>", "Max depth to show", "5").action(async (options) => {
1001
+ console.log();
1002
+ console.log(chalk.bold("\u{1F98E} Komodo Dependency Tree"));
1003
+ console.log();
1004
+ await handleTree(options.path);
1005
+ });
1006
+ program.command("templates").alias("template").description("Browse and use pre-built environment templates").argument("[query]", "Search for templates").option("-p, --path <path>", "Project folder", process.cwd()).action(async (query, options) => {
1007
+ console.log();
1008
+ console.log(chalk.bold("\u{1F98E} Komodo Templates"));
1009
+ console.log();
1010
+ if (query) {
1011
+ const template = getTemplateById(query);
1012
+ if (template) {
1013
+ await handleUseTemplate(query, options.path);
1014
+ } else {
1015
+ const results = searchTemplates(query);
1016
+ if (results.length === 0) {
1017
+ console.log(chalk.dim(` No templates found for "${query}"`));
1018
+ } else {
1019
+ console.log(formatTemplateList(results, true));
1020
+ }
1021
+ }
1022
+ } else {
1023
+ console.log(formatTemplateList(TEMPLATES, true));
1024
+ console.log(chalk.dim(" Use 'komodo template <id>' to set up a template"));
1025
+ console.log();
1026
+ }
1027
+ });
1028
+ program.command("explain").description("Get detailed information about a package").argument("<package>", "Package name").action(async (packageName) => {
1029
+ console.log();
1030
+ console.log(chalk.bold("\u{1F98E} Komodo Package Info"));
1031
+ console.log();
1032
+ await handleExplain(packageName);
1033
+ });
1034
+ program.command("clone").alias("setup").description("Analyze and set up from a GitHub repository").argument("<url>", "GitHub repository URL").option("-p, --path <path>", "Project folder", process.cwd()).action(async (url, options) => {
1035
+ console.log();
1036
+ console.log(chalk.bold("\u{1F98E} Komodo GitHub Setup"));
1037
+ console.log();
1038
+ await handleClone(url);
1039
+ });
1040
+ program.command("insights").alias("analytics").description("View environment analytics and insights").option("-p, --path <path>", "Project folder", process.cwd()).action(async (options) => {
1041
+ console.log();
1042
+ console.log(chalk.bold("\u{1F98E} Komodo Insights"));
1043
+ console.log();
1044
+ await handleInsights(options.path);
1045
+ });
1046
+ program.command("diff").description("Compare two environment snapshots").option("-p, --path <path>", "Project folder", process.cwd()).action(async (options) => {
1047
+ console.log();
1048
+ console.log(chalk.bold("\u{1F98E} Komodo Environment Diff"));
1049
+ console.log();
1050
+ const snapshots = await komodo.listSnapshots(options.path);
1051
+ if (snapshots.length < 2) {
1052
+ console.log(chalk.dim(" Need at least 2 snapshots to compare"));
1053
+ console.log(chalk.dim(" Make some changes first, then run diff again"));
1054
+ console.log();
1055
+ return;
1056
+ }
1057
+ const sorted = [...snapshots].sort(
1058
+ (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
1059
+ );
1060
+ const diff = diffPackages(sorted[1].packages, sorted[0].packages);
1061
+ diff.from = sorted[1].description;
1062
+ diff.to = sorted[0].description;
1063
+ console.log(formatDiff(diff, true));
1064
+ console.log();
1065
+ });
589
1066
  program.command("history").description("See past changes").option("-p, --path <path>", "Project folder", process.cwd()).action(async (options) => {
590
1067
  const snapshots = await komodo.listSnapshots(options.path);
591
1068
  console.log();
@@ -7,7 +7,7 @@ import {
7
7
  detectConflicts,
8
8
  getInstalledPackages,
9
9
  loadState
10
- } from "./chunk-5HD3OG64.js";
10
+ } from "./chunk-AR6QW5FH.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,19 +1,12 @@
1
1
  {
2
2
  "name": "komodo-cli",
3
- "version": "2.1.0",
3
+ "version": "2.2.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": {
7
7
  "komodo": "./dist/index.js"
8
8
  },
9
9
  "main": "./dist/index.js",
10
- "scripts": {
11
- "build": "tsup && chmod +x dist/index.js",
12
- "dev": "tsup src/index.ts --format esm --watch",
13
- "typecheck": "tsc --noEmit",
14
- "clean": "rm -rf dist",
15
- "prepublishOnly": "pnpm build"
16
- },
17
10
  "files": [
18
11
  "dist"
19
12
  ],
@@ -42,7 +35,13 @@
42
35
  "cross-spawn": "^7.0.6"
43
36
  },
44
37
  "devDependencies": {
45
- "@komodo/core": "workspace:*",
46
- "@komodo/ui": "workspace:*"
38
+ "@komodo/core": "0.1.0",
39
+ "@komodo/ui": "0.1.0"
40
+ },
41
+ "scripts": {
42
+ "build": "tsup && chmod +x dist/index.js",
43
+ "dev": "tsup src/index.ts --format esm --watch",
44
+ "typecheck": "tsc --noEmit",
45
+ "clean": "rm -rf dist"
47
46
  }
48
- }
47
+ }