komodo-cli 2.9.0 → 2.10.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
@@ -3,6 +3,7 @@ import {
3
3
  Komodo,
4
4
  KomodoChat,
5
5
  TEMPLATES,
6
+ analyzeCodebase,
6
7
  analyzeEnvironment,
7
8
  analyzeHealth,
8
9
  analyzeOptimizations,
@@ -14,6 +15,7 @@ import {
14
15
  diffPackages,
15
16
  executeRepair,
16
17
  explainPackage,
18
+ exportEnvironment,
17
19
  formatDiff,
18
20
  formatDoctorReport,
19
21
  formatExplanation,
@@ -21,17 +23,22 @@ import {
21
23
  formatOptimizationReport,
22
24
  formatRepoAnalysis,
23
25
  formatTemplateList,
26
+ generateHashSnapshot,
24
27
  generateOptimizationScript,
28
+ getCodebaseSummary,
25
29
  getInstallCommandsForTemplate,
26
30
  getInstalledPackages,
27
31
  getTemplateById,
32
+ importEnvironment,
33
+ loadAndVerifySnapshot,
28
34
  loadState,
29
35
  parseGitHubUrl,
30
36
  resolveConflicts,
31
37
  runDoctor,
38
+ saveSnapshot,
32
39
  searchTemplates,
33
40
  visualizeTree
34
- } from "./chunk-GGBZF72M.js";
41
+ } from "./chunk-EU4PZLPQ.js";
35
42
 
36
43
  // src/index.ts
37
44
  import { Command } from "commander";
@@ -40,6 +47,8 @@ import ora from "ora";
40
47
  import boxen from "boxen";
41
48
  import * as readline from "readline";
42
49
  import { createRequire } from "module";
50
+ import os from "os";
51
+ import { writeFile, readFile } from "fs/promises";
43
52
  var require2 = createRequire(import.meta.url);
44
53
  var packageJson = require2("../package.json");
45
54
  var CEREBRAS_API_KEY = "csk-m4vcnx94p854xmvnhxx38chwmxxwtffpnymk2ewexktk3962";
@@ -82,9 +91,9 @@ function printBanner() {
82
91
  console.log(chalk.hex("#78ff78").dim(" Just say what you want to build."));
83
92
  console.log();
84
93
  }
85
- function formatOs(os) {
94
+ function formatOs(os2) {
86
95
  const names = { darwin: "Mac", linux: "Linux", windows: "Windows" };
87
- return names[os] ?? os;
96
+ return names[os2] ?? os2;
88
97
  }
89
98
  function formatGpu(hardware) {
90
99
  if (hardware.gpu === "apple-silicon") {
@@ -96,6 +105,8 @@ function formatGpu(hardware) {
96
105
  }
97
106
  return "CPU";
98
107
  }
108
+ var cachedCodebaseSummary;
109
+ var codebaseAnalyzed = false;
99
110
  async function updateChatContext(projectPath) {
100
111
  const hardware = komodo.getHardware();
101
112
  const state = await loadState(projectPath);
@@ -115,6 +126,15 @@ async function updateChatContext(projectPath) {
115
126
  healthIssues = health.issues;
116
127
  }
117
128
  }
129
+ if (!codebaseAnalyzed) {
130
+ try {
131
+ const project = await analyzeCodebase(projectPath, { maxFiles: 300 });
132
+ cachedCodebaseSummary = getCodebaseSummary(project);
133
+ codebaseAnalyzed = true;
134
+ } catch {
135
+ codebaseAnalyzed = true;
136
+ }
137
+ }
118
138
  const context = {
119
139
  hardware,
120
140
  runtime,
@@ -122,7 +142,8 @@ async function updateChatContext(projectPath) {
122
142
  conflicts,
123
143
  healthIssues,
124
144
  projectPath,
125
- environmentName
145
+ environmentName,
146
+ codebaseSummary: cachedCodebaseSummary
126
147
  };
127
148
  chat.setContext(context);
128
149
  return { installedPackages, conflicts, healthIssues, runtime, environmentName };
@@ -635,7 +656,7 @@ async function handleUI(projectPath) {
635
656
  console.log();
636
657
  console.log(chalk.hex("#b4ffb4").dim(" Starting dashboard..."));
637
658
  try {
638
- const { startServer } = await import("./server-JOKWCY3W.js");
659
+ const { startServer } = await import("./server-G6XWHEZX.js");
639
660
  await startServer(projectPath, port);
640
661
  console.log(chalk.hex("#5aff5a")(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
641
662
  console.log();
@@ -964,7 +985,7 @@ program.command("ui").description("Open the visual dashboard").option("-p, --pat
964
985
  const url = `http://localhost:${port}`;
965
986
  console.log(chalk.dim(" Starting dashboard..."));
966
987
  try {
967
- const { startServer } = await import("./server-JOKWCY3W.js");
988
+ const { startServer } = await import("./server-G6XWHEZX.js");
968
989
  await startServer(options.path, port);
969
990
  console.log();
970
991
  console.log(chalk.green(` \u2713 Dashboard ready at ${chalk.bold(url)}`));
@@ -1272,4 +1293,181 @@ function formatTimeAgo(date) {
1272
1293
  if (seconds < 604800) return `${Math.floor(seconds / 86400)}d ago`;
1273
1294
  return date.toLocaleDateString();
1274
1295
  }
1296
+ program.command("export").description("Export environment to shareable file").option("-p, --path <path>", "Project folder", process.cwd()).option("-o, --output <file>", "Output file", ".komodo-env.json").option("--notes <notes>", "Description or notes about this environment").option("--tags <tags>", "Comma-separated tags for categorization").action(async (options) => {
1297
+ const spinner = ora(chalk.hex("#b4ffb4")("Exporting environment...")).start();
1298
+ try {
1299
+ const state = await loadState(options.path);
1300
+ if (!state.activeEnvironmentId) {
1301
+ spinner.fail(chalk.red("No environment to export"));
1302
+ console.log();
1303
+ console.log(chalk.dim(' Set up an environment first with: komodo "install <packages>"'));
1304
+ console.log();
1305
+ return;
1306
+ }
1307
+ const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
1308
+ if (!activeEnv) {
1309
+ spinner.fail(chalk.red("Environment not found"));
1310
+ return;
1311
+ }
1312
+ const exported = await exportEnvironment(options.path, activeEnv.runtime, {
1313
+ includeDevDeps: true,
1314
+ cleanVersions: false
1315
+ });
1316
+ exported.exportedBy = os.userInfo().username;
1317
+ if (options.notes) exported.notes = options.notes;
1318
+ if (options.tags) exported.tags = options.tags.split(",").map((t) => t.trim());
1319
+ exported.komodoVersion = packageJson.version;
1320
+ await writeFile(options.output, JSON.stringify(exported, null, 2));
1321
+ spinner.succeed(chalk.hex("#5aff5a")("Environment exported!"));
1322
+ console.log();
1323
+ console.log(chalk.hex("#b4ffb4")(" File: ") + chalk.white(options.output));
1324
+ console.log(chalk.hex("#b4ffb4")(" Runtime: ") + chalk.white(activeEnv.runtime));
1325
+ console.log(chalk.hex("#b4ffb4")(" Packages: ") + chalk.white(`${exported.packages.length}`));
1326
+ console.log(chalk.hex("#b4ffb4")(" Hardware: ") + chalk.white(`${exported.hardware?.gpu || "CPU"}`));
1327
+ console.log();
1328
+ console.log(chalk.dim(" Share this file with teammates: komodo import .komodo-env.json"));
1329
+ console.log();
1330
+ } catch (error) {
1331
+ spinner.fail();
1332
+ console.log();
1333
+ console.log(chalk.red(" Export failed"));
1334
+ console.log(chalk.dim(` ${error instanceof Error ? error.message : "Unknown error"}`));
1335
+ console.log();
1336
+ }
1337
+ });
1338
+ program.command("import").description("Import environment from file or URL").argument("<source>", "File path or URL to environment").option("-p, --path <path>", "Target project folder", process.cwd()).option("--force", "Skip hardware compatibility check").action(async (source, options) => {
1339
+ const spinner = ora(chalk.hex("#b4ffb4")("Importing environment...")).start();
1340
+ try {
1341
+ let data;
1342
+ if (source.startsWith("http://") || source.startsWith("https://")) {
1343
+ spinner.text = chalk.hex("#b4ffb4")("Fetching environment...");
1344
+ const response = await fetch(source);
1345
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
1346
+ data = await response.json();
1347
+ } else {
1348
+ const content = await readFile(source, "utf-8");
1349
+ data = JSON.parse(content);
1350
+ }
1351
+ if (!data.runtime || !data.packages || !Array.isArray(data.packages)) {
1352
+ throw new Error("Invalid environment file format");
1353
+ }
1354
+ spinner.stop();
1355
+ console.log();
1356
+ const hardware = komodo.getHardware();
1357
+ if (data.hardware && !options.force) {
1358
+ console.log(chalk.hex("#b4ffb4")(" Hardware check:"));
1359
+ console.log(chalk.dim(` Your machine: ${hardware.gpu || "CPU"}, ${hardware.totalMemoryGb}GB RAM`));
1360
+ console.log(chalk.dim(` Environment: ${data.hardware.gpu || "CPU"}, ${data.hardware.totalMemoryGb}GB RAM`));
1361
+ if (data.hardware.gpu !== hardware.gpu) {
1362
+ console.log(chalk.yellow(` \u26A0 GPU mismatch - packages will be adapted`));
1363
+ }
1364
+ if (data.hardware.totalMemoryGb > hardware.totalMemoryGb) {
1365
+ console.log(chalk.yellow(` \u26A0 Less memory than original - some packages may be slow`));
1366
+ }
1367
+ console.log();
1368
+ }
1369
+ console.log(chalk.hex("#a5ffa5")(" Installing:"));
1370
+ data.packages.slice(0, 10).forEach((pkg) => {
1371
+ const plus = chalk.hex("#5aff5a")("+");
1372
+ console.log(` ${plus} ${friendlyPackageName(pkg.name)}@${pkg.version}`);
1373
+ });
1374
+ if (data.packages.length > 10) {
1375
+ console.log(chalk.dim(` ...and ${data.packages.length - 10} more`));
1376
+ }
1377
+ console.log();
1378
+ const installSpinner = ora(chalk.hex("#b4ffb4")("Installing packages...")).start();
1379
+ const result = await importEnvironment(options.path, data);
1380
+ if (result.success) {
1381
+ installSpinner.succeed(chalk.hex("#5aff5a")("Environment imported!"));
1382
+ console.log();
1383
+ console.log(chalk.hex("#5aff5a")(` \u2713 ${result.installed?.length || 0} packages installed`));
1384
+ if (data.exportedBy) {
1385
+ console.log(chalk.dim(` From: ${data.exportedBy}`));
1386
+ }
1387
+ if (data.notes) {
1388
+ console.log(chalk.dim(` Notes: ${data.notes}`));
1389
+ }
1390
+ console.log();
1391
+ } else {
1392
+ installSpinner.fail(chalk.red("Import failed"));
1393
+ console.log();
1394
+ console.log(chalk.dim(` ${result.error || "Could not install packages"}`));
1395
+ console.log();
1396
+ }
1397
+ } catch (error) {
1398
+ spinner.fail();
1399
+ console.log();
1400
+ console.log(chalk.red(" Import failed"));
1401
+ console.log(chalk.dim(` ${error instanceof Error ? error.message : "Unknown error"}`));
1402
+ console.log();
1403
+ }
1404
+ });
1405
+ program.command("verify").description("Verify environment matches reproducible snapshot").option("-p, --path <path>", "Project folder", process.cwd()).option("--create", "Create a new reproducible snapshot").action(async (options) => {
1406
+ const spinner = ora(chalk.hex("#b4ffb4")("Verifying environment...")).start();
1407
+ try {
1408
+ const state = await loadState(options.path);
1409
+ if (!state.activeEnvironmentId) {
1410
+ spinner.fail(chalk.red("No environment to verify"));
1411
+ console.log();
1412
+ console.log(chalk.dim(' Set up an environment first with: komodo "install <packages>"'));
1413
+ console.log();
1414
+ return;
1415
+ }
1416
+ const activeEnv = state.environments.find((e) => e.id === state.activeEnvironmentId);
1417
+ if (!activeEnv) {
1418
+ spinner.fail(chalk.red("Environment not found"));
1419
+ return;
1420
+ }
1421
+ if (options.create) {
1422
+ spinner.text = chalk.hex("#b4ffb4")("Creating reproducible snapshot...");
1423
+ const snapshot2 = await generateHashSnapshot(
1424
+ options.path,
1425
+ activeEnv.runtime,
1426
+ `Created at ${(/* @__PURE__ */ new Date()).toISOString()}`
1427
+ );
1428
+ await saveSnapshot(options.path, snapshot2);
1429
+ spinner.succeed(chalk.hex("#5aff5a")("Snapshot created!"));
1430
+ console.log();
1431
+ console.log(chalk.hex("#b4ffb4")(" Snapshot: .komodo-snapshot.json"));
1432
+ console.log(chalk.hex("#b4ffb4")(" Packages: ") + chalk.white(snapshot2.hashes.length.toString()));
1433
+ console.log(chalk.dim(" Use 'komodo verify' to check reproducibility"));
1434
+ console.log();
1435
+ return;
1436
+ }
1437
+ const { snapshot, verification } = await loadAndVerifySnapshot(options.path);
1438
+ spinner.stop();
1439
+ console.log();
1440
+ if (verification.valid) {
1441
+ console.log(chalk.hex("#5aff5a")(" \u2713 Environment is reproducible!"));
1442
+ console.log(chalk.hex("#b4ffb4")(" Packages verified: ") + chalk.white(snapshot.hashes.length.toString()));
1443
+ console.log(chalk.dim(` Snapshot from: ${snapshot.timestamp.split("T")[0]}`));
1444
+ console.log();
1445
+ } else {
1446
+ console.log(chalk.red(` \u2717 Hash mismatches (${verification.mismatches.length}):`));
1447
+ verification.mismatches.slice(0, 5).forEach((m) => {
1448
+ console.log(chalk.dim(` \u2022 ${m}`));
1449
+ });
1450
+ if (verification.mismatches.length > 5) {
1451
+ console.log(chalk.dim(` ...and ${verification.mismatches.length - 5} more`));
1452
+ }
1453
+ console.log();
1454
+ console.log(chalk.dim(" Packages may have been upgraded or changed."));
1455
+ console.log(chalk.dim(" Run 'komodo verify --create' to create a new snapshot."));
1456
+ console.log();
1457
+ }
1458
+ } catch (error) {
1459
+ spinner.fail();
1460
+ console.log();
1461
+ if (error instanceof Error && error.message.includes("Snapshot not found")) {
1462
+ console.log(chalk.yellow(" No snapshot found"));
1463
+ console.log();
1464
+ console.log(chalk.dim(" Create one with: komodo verify --create"));
1465
+ console.log();
1466
+ } else {
1467
+ console.log(chalk.red(" Verification failed"));
1468
+ console.log(chalk.dim(` ${error instanceof Error ? error.message : "Unknown error"}`));
1469
+ console.log();
1470
+ }
1471
+ }
1472
+ });
1275
1473
  program.parse();