komodo-cli 2.2.0 → 2.3.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
@@ -9,7 +9,10 @@ import {
9
9
  analyzeRepoStructure,
10
10
  buildDependencyTree,
11
11
  detectConflicts,
12
+ detectRealConflicts,
13
+ diagnoseEnvironment,
12
14
  diffPackages,
15
+ executeRepair,
13
16
  explainPackage,
14
17
  formatDiff,
15
18
  formatDoctorReport,
@@ -24,10 +27,11 @@ import {
24
27
  getTemplateById,
25
28
  loadState,
26
29
  parseGitHubUrl,
30
+ resolveConflicts,
27
31
  runDoctor,
28
32
  searchTemplates,
29
33
  visualizeTree
30
- } from "./chunk-AR6QW5FH.js";
34
+ } from "./chunk-G2KKBIAH.js";
31
35
 
32
36
  // src/index.ts
33
37
  import { Command } from "commander";
@@ -173,7 +177,7 @@ async function startInteractiveMode(projectPath) {
173
177
  const hardware = komodo.getHardware();
174
178
  console.log(chalk.hex("#b4ffb4").dim(` ${formatOs(hardware.os)} \xB7 ${formatGpu(hardware)} \xB7 ${hardware.totalMemoryGb}GB memory`));
175
179
  console.log();
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"));
180
+ console.log(chalk.hex("#96ff96").dim(" Commands: ") + chalk.hex("#d2ffd2")("fix") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("conflicts") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("doctor") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("optimize") + chalk.dim(" \xB7 ") + chalk.hex("#d2ffd2")("tree"));
177
181
  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
182
  console.log(chalk.dim(" Or just ask anything in natural language!"));
179
183
  console.log();
@@ -239,6 +243,17 @@ async function startInteractiveMode(projectPath) {
239
243
  prompt();
240
244
  return;
241
245
  }
246
+ if (trimmed === "fix" || trimmed === "repair" || trimmed.includes("broken") || trimmed.includes("nothing works") || trimmed.includes("everything is broken") || trimmed.includes("help me fix")) {
247
+ await handleFix(projectPath);
248
+ await updateChatContext(projectPath);
249
+ prompt();
250
+ return;
251
+ }
252
+ if (trimmed === "conflicts" || trimmed.includes("check conflicts") || trimmed.includes("find conflicts")) {
253
+ await handleConflicts(projectPath);
254
+ prompt();
255
+ return;
256
+ }
242
257
  if (trimmed === "list" || trimmed === "ls") {
243
258
  await handleList(projectPath);
244
259
  prompt();
@@ -502,6 +517,135 @@ async function handleCheck(projectPath) {
502
517
  }
503
518
  console.log();
504
519
  }
520
+ async function handleFix(projectPath) {
521
+ const spinner = ora(chalk.hex("#b4ffb4")("Scanning your project...")).start();
522
+ const state = await loadState(projectPath);
523
+ let runtime;
524
+ if (state.activeEnvironmentId) {
525
+ const env = state.environments.find((e) => e.id === state.activeEnvironmentId);
526
+ runtime = env?.runtime;
527
+ }
528
+ const diagnosis = await diagnoseEnvironment(projectPath, runtime);
529
+ spinner.stop();
530
+ console.log();
531
+ if (diagnosis.status === "healthy") {
532
+ console.log(chalk.hex("#5aff5a")(" \u2713 Everything looks good!"));
533
+ console.log(chalk.dim(" No issues found with your environment."));
534
+ console.log();
535
+ return;
536
+ }
537
+ console.log(chalk.hex("#ffb347")(` Found ${diagnosis.problems.length} issue${diagnosis.problems.length > 1 ? "s" : ""}:`));
538
+ console.log();
539
+ diagnosis.problems.slice(0, 3).forEach((problem) => {
540
+ const icon = problem.severity === "critical" ? chalk.red("\u2717") : problem.severity === "warning" ? chalk.yellow("\u26A0") : chalk.blue("\u2139");
541
+ console.log(` ${icon} ${problem.friendlyTitle}`);
542
+ console.log(chalk.dim(` ${problem.description}`));
543
+ });
544
+ if (diagnosis.problems.length > 3) {
545
+ console.log(chalk.dim(` ...and ${diagnosis.problems.length - 3} more`));
546
+ }
547
+ console.log();
548
+ if (diagnosis.repairPlan.length === 0) {
549
+ console.log(chalk.dim(" No automatic fixes available. Try creating a new environment."));
550
+ console.log();
551
+ return;
552
+ }
553
+ console.log(chalk.hex("#b4ffb4")(` Fixing ${diagnosis.repairPlan.length} issue${diagnosis.repairPlan.length > 1 ? "s" : ""}...`));
554
+ console.log();
555
+ const repairSpinner = ora().start();
556
+ const result = await executeRepair(projectPath, diagnosis, {
557
+ autoBackup: true,
558
+ dryRun: false,
559
+ onProgress: (step, status) => {
560
+ if (status === "starting") {
561
+ repairSpinner.text = chalk.hex("#b4ffb4")(step.friendlyDescription);
562
+ } else if (status === "complete") {
563
+ repairSpinner.succeed(chalk.hex("#5aff5a")(step.friendlyDescription));
564
+ repairSpinner.start();
565
+ } else if (status === "failed") {
566
+ repairSpinner.fail(chalk.red(step.friendlyDescription));
567
+ repairSpinner.start();
568
+ }
569
+ }
570
+ });
571
+ if (repairSpinner.isSpinning) {
572
+ repairSpinner.stop();
573
+ }
574
+ console.log();
575
+ if (result.success) {
576
+ console.log(chalk.hex("#5aff5a")(` \u2713 All fixed! Resolved ${result.problemsFixed.length} issue${result.problemsFixed.length > 1 ? "s" : ""}.`));
577
+ } else {
578
+ console.log(chalk.yellow(` \u26A0 Partially fixed. Resolved ${result.stepsCompleted}/${result.stepsTotal} issues.`));
579
+ }
580
+ console.log();
581
+ }
582
+ async function handleConflicts(projectPath) {
583
+ const spinner = ora(chalk.hex("#b4ffb4")("Checking for conflicts...")).start();
584
+ const state = await loadState(projectPath);
585
+ let runtime;
586
+ if (state.activeEnvironmentId) {
587
+ const env = state.environments.find((e) => e.id === state.activeEnvironmentId);
588
+ runtime = env?.runtime;
589
+ }
590
+ if (!runtime) {
591
+ spinner.fail("No environment found");
592
+ console.log();
593
+ return;
594
+ }
595
+ const conflicts = await detectRealConflicts(projectPath, runtime);
596
+ spinner.stop();
597
+ console.log();
598
+ if (conflicts.length === 0) {
599
+ console.log(chalk.hex("#5aff5a")(" \u2713 No conflicts found!"));
600
+ console.log(chalk.dim(" All packages are compatible."));
601
+ console.log();
602
+ return;
603
+ }
604
+ console.log(chalk.yellow(` Found ${conflicts.length} conflict${conflicts.length > 1 ? "s" : ""}:`));
605
+ console.log();
606
+ conflicts.slice(0, 3).forEach((conflict) => {
607
+ const icon = conflict.severity === "error" ? chalk.red("\u2717") : chalk.yellow("\u26A0");
608
+ console.log(` ${icon} ${conflict.package1} \u2194 ${conflict.package2}`);
609
+ console.log(chalk.dim(` ${conflict.reason}`));
610
+ if (conflict.suggestion) {
611
+ console.log(chalk.hex("#87cefa")(` \u{1F4A1} ${conflict.suggestion}`));
612
+ }
613
+ });
614
+ if (conflicts.length > 3) {
615
+ console.log(chalk.dim(` ...and ${conflicts.length - 3} more`));
616
+ }
617
+ console.log();
618
+ console.log(chalk.hex("#b4ffb4")(" Attempting to resolve..."));
619
+ console.log();
620
+ const resolveSpinner = ora().start();
621
+ const result = await resolveConflicts(
622
+ projectPath,
623
+ runtime,
624
+ conflicts,
625
+ (message) => {
626
+ resolveSpinner.text = chalk.hex("#b4ffb4")(message);
627
+ }
628
+ );
629
+ if (resolveSpinner.isSpinning) {
630
+ resolveSpinner.stop();
631
+ }
632
+ console.log();
633
+ if (result.success) {
634
+ console.log(chalk.hex("#5aff5a")(" \u2713 All conflicts resolved!"));
635
+ result.resolved.forEach((r) => console.log(chalk.dim(` \u2022 ${r}`)));
636
+ } else {
637
+ if (result.resolved.length > 0) {
638
+ console.log(chalk.hex("#5aff5a")(" Resolved:"));
639
+ result.resolved.forEach((r) => console.log(chalk.dim(` \u2022 ${r}`)));
640
+ console.log();
641
+ }
642
+ console.log(chalk.yellow(" Cannot auto-resolve:"));
643
+ result.remaining.slice(0, 3).forEach(
644
+ (c) => console.log(chalk.dim(` \u2022 ${c.package1} \u2194 ${c.package2}`))
645
+ );
646
+ }
647
+ console.log();
648
+ }
505
649
  async function handleHistory(projectPath) {
506
650
  const snapshots = await komodo.listSnapshots(projectPath);
507
651
  console.log();
@@ -725,7 +869,7 @@ async function handleUI(projectPath) {
725
869
  console.log();
726
870
  console.log(chalk.hex("#b4ffb4").dim(" Starting dashboard..."));
727
871
  try {
728
- const { startServer } = await import("./server-LCQG53IY.js");
872
+ const { startServer } = await import("./server-YR5YMDJ7.js");
729
873
  await startServer(projectPath, port);
730
874
  console.log(chalk.hex("#5aff5a")(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
731
875
  console.log();
@@ -864,6 +1008,188 @@ program.command("undo").description("Undo your last change").option("-p, --path
864
1008
  process.exit(1);
865
1009
  }
866
1010
  });
1011
+ program.command("fix").alias("repair").description("Fix a broken environment").option("-p, --path <path>", "Project folder", process.cwd()).option("--dry-run", "Show what would be fixed without making changes").action(async (options) => {
1012
+ console.log();
1013
+ console.log(chalk.bold("\u{1F98E} Komodo Fix"));
1014
+ console.log();
1015
+ const spinner = ora("Scanning your project...").start();
1016
+ const state = await loadState(options.path);
1017
+ let runtime;
1018
+ if (state.activeEnvironmentId) {
1019
+ const env = state.environments.find((e) => e.id === state.activeEnvironmentId);
1020
+ runtime = env?.runtime;
1021
+ }
1022
+ const diagnosis = await diagnoseEnvironment(options.path, runtime);
1023
+ spinner.stop();
1024
+ if (diagnosis.status === "healthy") {
1025
+ console.log(chalk.green(" \u2713 Everything looks good!"));
1026
+ console.log();
1027
+ console.log(chalk.dim(" No issues found with your environment."));
1028
+ console.log();
1029
+ return;
1030
+ }
1031
+ console.log(chalk.bold(` Found ${diagnosis.problems.length} issue${diagnosis.problems.length > 1 ? "s" : ""}:`));
1032
+ console.log();
1033
+ diagnosis.problems.forEach((problem) => {
1034
+ const icon = problem.severity === "critical" ? "\u2717" : problem.severity === "warning" ? "\u26A0" : "\u2139";
1035
+ const color = problem.severity === "critical" ? chalk.red : problem.severity === "warning" ? chalk.yellow : chalk.blue;
1036
+ console.log(color(` ${icon} ${problem.friendlyTitle}`));
1037
+ console.log(chalk.dim(` ${problem.description}`));
1038
+ console.log();
1039
+ });
1040
+ if (diagnosis.repairPlan.length === 0) {
1041
+ console.log(chalk.yellow(" No automatic fixes available."));
1042
+ console.log();
1043
+ console.log(chalk.dim(" Try:"));
1044
+ console.log(chalk.dim(" \u2022 Check the technical details above"));
1045
+ console.log(chalk.dim(" \u2022 Create a new environment: komodo <your-intent>"));
1046
+ console.log();
1047
+ return;
1048
+ }
1049
+ if (options.dryRun) {
1050
+ console.log(chalk.cyan(" Would fix:"));
1051
+ console.log();
1052
+ diagnosis.repairPlan.forEach((step, i) => {
1053
+ console.log(chalk.dim(` ${i + 1}. ${step.friendlyDescription}`));
1054
+ });
1055
+ console.log();
1056
+ console.log(chalk.dim(` Estimated time: ${diagnosis.estimatedTime}`));
1057
+ console.log();
1058
+ console.log(chalk.cyan(" Run without --dry-run to apply these fixes."));
1059
+ console.log();
1060
+ return;
1061
+ }
1062
+ console.log(chalk.bold(` Fix all ${diagnosis.problems.length} issue${diagnosis.problems.length > 1 ? "s" : ""}?`));
1063
+ console.log(chalk.dim(` Estimated time: ${diagnosis.estimatedTime}`));
1064
+ console.log();
1065
+ const rl = readline.createInterface({
1066
+ input: process.stdin,
1067
+ output: process.stdout
1068
+ });
1069
+ const answer = await new Promise((resolve) => {
1070
+ rl.question(chalk.dim(" Continue? (Y/n) "), resolve);
1071
+ });
1072
+ rl.close();
1073
+ if (answer.toLowerCase() === "n" || answer.toLowerCase() === "no") {
1074
+ console.log();
1075
+ console.log(chalk.dim(" Cancelled."));
1076
+ console.log();
1077
+ return;
1078
+ }
1079
+ console.log();
1080
+ const repairSpinner = ora().start();
1081
+ const result = await executeRepair(options.path, diagnosis, {
1082
+ autoBackup: true,
1083
+ dryRun: false,
1084
+ onProgress: (step, status) => {
1085
+ if (status === "starting") {
1086
+ repairSpinner.text = step.friendlyDescription;
1087
+ } else if (status === "complete") {
1088
+ repairSpinner.succeed(step.friendlyDescription);
1089
+ repairSpinner.start();
1090
+ } else if (status === "failed") {
1091
+ repairSpinner.fail(step.friendlyDescription);
1092
+ repairSpinner.start();
1093
+ }
1094
+ }
1095
+ });
1096
+ if (repairSpinner.isSpinning) {
1097
+ repairSpinner.stop();
1098
+ }
1099
+ console.log();
1100
+ if (result.success) {
1101
+ console.log(
1102
+ boxen(
1103
+ chalk.green("All fixed!") + "\n\n" + chalk.dim(`Fixed ${result.problemsFixed.length} issue${result.problemsFixed.length > 1 ? "s" : ""}.`) + "\n\n" + chalk.dim("Changed your mind? Run: ") + chalk.white("komodo undo"),
1104
+ { padding: 1, borderStyle: "round", borderColor: "green" }
1105
+ )
1106
+ );
1107
+ } else {
1108
+ console.log(
1109
+ boxen(
1110
+ chalk.yellow("Partially fixed") + "\n\n" + chalk.dim(`Fixed ${result.stepsCompleted}/${result.stepsTotal} issues.`) + (result.problemsRemaining.length > 0 ? "\n\n" + chalk.dim("Remaining issues:") + "\n" + result.problemsRemaining.map((p) => chalk.dim(` \u2022 ${p}`)).join("\n") : ""),
1111
+ { padding: 1, borderStyle: "round", borderColor: "yellow" }
1112
+ )
1113
+ );
1114
+ }
1115
+ console.log();
1116
+ });
1117
+ program.command("conflicts").description("Find and fix package conflicts").option("-p, --path <path>", "Project folder", process.cwd()).option("--fix", "Automatically fix conflicts").action(async (options) => {
1118
+ console.log();
1119
+ console.log(chalk.bold("\u{1F98E} Conflict Check"));
1120
+ console.log();
1121
+ const spinner = ora("Checking for conflicts...").start();
1122
+ const state = await loadState(options.path);
1123
+ let runtime;
1124
+ if (state.activeEnvironmentId) {
1125
+ const env = state.environments.find((e) => e.id === state.activeEnvironmentId);
1126
+ runtime = env?.runtime;
1127
+ }
1128
+ if (!runtime) {
1129
+ spinner.fail("No environment found");
1130
+ console.log();
1131
+ console.log(chalk.dim(" No active environment detected."));
1132
+ console.log();
1133
+ return;
1134
+ }
1135
+ const conflicts = await detectRealConflicts(options.path, runtime);
1136
+ spinner.stop();
1137
+ if (conflicts.length === 0) {
1138
+ console.log(chalk.green(" \u2713 No conflicts found!"));
1139
+ console.log();
1140
+ console.log(chalk.dim(" All packages are compatible."));
1141
+ console.log();
1142
+ return;
1143
+ }
1144
+ console.log(chalk.bold(` Found ${conflicts.length} conflict${conflicts.length > 1 ? "s" : ""}:`));
1145
+ console.log();
1146
+ conflicts.forEach((conflict) => {
1147
+ const icon = conflict.severity === "error" ? "\u2717" : "\u26A0";
1148
+ const color = conflict.severity === "error" ? chalk.red : chalk.yellow;
1149
+ console.log(color(` ${icon} ${conflict.package1} \u2194 ${conflict.package2}`));
1150
+ console.log(chalk.dim(` ${conflict.reason}`));
1151
+ if (conflict.suggestion) {
1152
+ console.log(chalk.dim(` \u{1F4A1} ${conflict.suggestion}`));
1153
+ }
1154
+ console.log();
1155
+ });
1156
+ if (!options.fix) {
1157
+ console.log(chalk.dim(" Run with --fix to automatically resolve conflicts."));
1158
+ console.log();
1159
+ return;
1160
+ }
1161
+ console.log(chalk.bold(" Attempting to resolve..."));
1162
+ console.log();
1163
+ const resolveSpinner = ora().start();
1164
+ const result = await resolveConflicts(
1165
+ options.path,
1166
+ runtime,
1167
+ conflicts,
1168
+ (message) => {
1169
+ resolveSpinner.text = message;
1170
+ }
1171
+ );
1172
+ if (resolveSpinner.isSpinning) {
1173
+ resolveSpinner.stop();
1174
+ }
1175
+ console.log();
1176
+ if (result.success) {
1177
+ console.log(
1178
+ boxen(
1179
+ chalk.green("All conflicts resolved!") + "\n\n" + result.resolved.map((r) => chalk.dim(` \u2713 ${r}`)).join("\n"),
1180
+ { padding: 1, borderStyle: "round", borderColor: "green" }
1181
+ )
1182
+ );
1183
+ } else {
1184
+ console.log(
1185
+ boxen(
1186
+ chalk.yellow("Some conflicts resolved") + "\n\n" + (result.resolved.length > 0 ? chalk.dim("Resolved:") + "\n" + result.resolved.map((r) => chalk.dim(` \u2713 ${r}`)).join("\n") + "\n\n" : "") + chalk.dim("Cannot auto-resolve:") + "\n" + result.remaining.map((c) => chalk.dim(` \u2022 ${c.package1} \u2194 ${c.package2}`)).join("\n") + "\n\n" + chalk.dim("These require manual intervention or separate environments."),
1187
+ { padding: 1, borderStyle: "round", borderColor: "yellow" }
1188
+ )
1189
+ );
1190
+ }
1191
+ console.log();
1192
+ });
867
1193
  program.command("ui").description("Open the visual dashboard").option("-p, --path <path>", "Project folder", process.cwd()).option("--port <port>", "Port number", "3333").action(async (options) => {
868
1194
  console.log();
869
1195
  console.log(chalk.bold("\u{1F98E} Komodo"));
@@ -872,7 +1198,7 @@ program.command("ui").description("Open the visual dashboard").option("-p, --pat
872
1198
  const url = `http://localhost:${port}`;
873
1199
  console.log(chalk.dim(" Starting dashboard..."));
874
1200
  try {
875
- const { startServer } = await import("./server-LCQG53IY.js");
1201
+ const { startServer } = await import("./server-YR5YMDJ7.js");
876
1202
  await startServer(options.path, port);
877
1203
  console.log();
878
1204
  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-AR6QW5FH.js";
10
+ } from "./chunk-G2KKBIAH.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,12 +1,19 @@
1
1
  {
2
2
  "name": "komodo-cli",
3
- "version": "2.2.0",
3
+ "version": "2.3.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
+ },
10
17
  "files": [
11
18
  "dist"
12
19
  ],
@@ -35,13 +42,7 @@
35
42
  "cross-spawn": "^7.0.6"
36
43
  },
37
44
  "devDependencies": {
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"
45
+ "@komodo/core": "workspace:*",
46
+ "@komodo/ui": "workspace:*"
46
47
  }
47
- }
48
+ }