@arkhera30/cli 0.1.1 → 0.1.3
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 +61 -15
- package/package.json +9 -7
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import chalk10 from "chalk";
|
|
|
8
8
|
import { Command } from "commander";
|
|
9
9
|
import chalk from "chalk";
|
|
10
10
|
import ora from "ora";
|
|
11
|
-
import { input, confirm, number } from "@inquirer/prompts";
|
|
11
|
+
import { input, confirm, number, select } from "@inquirer/prompts";
|
|
12
12
|
|
|
13
13
|
// src/lib/config.ts
|
|
14
14
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
@@ -212,7 +212,15 @@ function toResult(result) {
|
|
|
212
212
|
}
|
|
213
213
|
async function tryCommand(command, args) {
|
|
214
214
|
try {
|
|
215
|
-
await execa(command, args, { reject: false });
|
|
215
|
+
const result = await execa(command, args, { reject: false });
|
|
216
|
+
return result.exitCode === 0;
|
|
217
|
+
} catch {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async function commandExists(command) {
|
|
222
|
+
try {
|
|
223
|
+
await execa(command, ["--version"], { reject: false });
|
|
216
224
|
return true;
|
|
217
225
|
} catch {
|
|
218
226
|
return false;
|
|
@@ -261,6 +269,9 @@ function createRuntime(name) {
|
|
|
261
269
|
}
|
|
262
270
|
};
|
|
263
271
|
}
|
|
272
|
+
async function checkRuntime(name) {
|
|
273
|
+
return tryCommand(name, ["compose", "version"]);
|
|
274
|
+
}
|
|
264
275
|
async function detectRuntime(preferred) {
|
|
265
276
|
if (preferred) {
|
|
266
277
|
const hasPreferred = await tryCommand(preferred, ["compose", "version"]);
|
|
@@ -276,6 +287,12 @@ async function detectRuntime(preferred) {
|
|
|
276
287
|
if (hasPodman) {
|
|
277
288
|
return createRuntime("podman");
|
|
278
289
|
}
|
|
290
|
+
const podmanInstalled = await commandExists("podman");
|
|
291
|
+
if (podmanInstalled) {
|
|
292
|
+
throw new Error(
|
|
293
|
+
"Podman is installed but `podman compose` is not working.\n\nFix options:\n 1. Ensure your Podman machine is running: podman machine start\n 2. Install podman-compose: pip3 install podman-compose\n 3. Upgrade Podman to v5+: brew upgrade podman\n"
|
|
294
|
+
);
|
|
295
|
+
}
|
|
279
296
|
throw new Error(
|
|
280
297
|
"No container runtime found.\n\nHorus requires Docker or Podman with the Compose plugin.\n\nInstall one of:\n - Docker Desktop: https://www.docker.com/products/docker-desktop/\n - Podman Desktop: https://podman-desktop.io/\n"
|
|
281
298
|
);
|
|
@@ -384,7 +401,7 @@ function installComposeFile() {
|
|
|
384
401
|
}
|
|
385
402
|
|
|
386
403
|
// src/commands/setup.ts
|
|
387
|
-
var setupCommand = new Command("setup").description("Interactive first-run setup for Horus").option("-y, --yes", "Non-interactive mode (use defaults + env vars)").option("--data-dir <path>", "Data directory path").option("--repos-path <path>", "Host repos path for Forge scanning").action(async (opts) => {
|
|
404
|
+
var setupCommand = new Command("setup").description("Interactive first-run setup for Horus").option("-y, --yes", "Non-interactive mode (use defaults + env vars)").option("--runtime <runtime>", "Container runtime to use: docker or podman (non-interactive only)").option("--data-dir <path>", "Data directory path").option("--repos-path <path>", "Host repos path for Forge scanning").action(async (opts) => {
|
|
388
405
|
console.log("");
|
|
389
406
|
console.log(chalk.bold("Horus Setup"));
|
|
390
407
|
console.log(chalk.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
@@ -403,17 +420,46 @@ var setupCommand = new Command("setup").description("Interactive first-run setup
|
|
|
403
420
|
}
|
|
404
421
|
}
|
|
405
422
|
}
|
|
406
|
-
const
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
423
|
+
const checkSpinner = ora("Checking for container runtimes...").start();
|
|
424
|
+
const [hasDocker, hasPodman] = await Promise.all([
|
|
425
|
+
checkRuntime("docker"),
|
|
426
|
+
checkRuntime("podman")
|
|
427
|
+
]);
|
|
428
|
+
checkSpinner.stop();
|
|
429
|
+
const available = [
|
|
430
|
+
...hasDocker ? ["docker"] : [],
|
|
431
|
+
...hasPodman ? ["podman"] : []
|
|
432
|
+
];
|
|
433
|
+
if (available.length === 0) {
|
|
434
|
+
console.log(chalk.red("No container runtime found."));
|
|
413
435
|
console.log("");
|
|
414
|
-
console.log(
|
|
436
|
+
console.log("Horus requires Docker or Podman with the Compose plugin.");
|
|
437
|
+
console.log("");
|
|
438
|
+
console.log("Install one of:");
|
|
439
|
+
console.log(" Docker Desktop: https://www.docker.com/products/docker-desktop/");
|
|
440
|
+
console.log(" Podman Desktop: https://podman-desktop.io/");
|
|
415
441
|
process.exit(1);
|
|
416
442
|
}
|
|
443
|
+
let selectedRuntime;
|
|
444
|
+
if (opts.yes) {
|
|
445
|
+
const requested = opts.runtime;
|
|
446
|
+
if (requested && !available.includes(requested)) {
|
|
447
|
+
console.log(chalk.red(`Requested runtime "${requested}" is not installed.`));
|
|
448
|
+
console.log(chalk.dim(`Available: ${available.join(", ")}`));
|
|
449
|
+
process.exit(1);
|
|
450
|
+
}
|
|
451
|
+
selectedRuntime = requested ?? available[0];
|
|
452
|
+
console.log(`Using ${chalk.cyan(selectedRuntime)}`);
|
|
453
|
+
} else {
|
|
454
|
+
selectedRuntime = await select({
|
|
455
|
+
message: "Which container runtime would you like to use?",
|
|
456
|
+
choices: available.map((r) => ({
|
|
457
|
+
value: r,
|
|
458
|
+
name: r === "docker" ? "Docker" : "Podman"
|
|
459
|
+
}))
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
const runtime = await detectRuntime(selectedRuntime);
|
|
417
463
|
let config;
|
|
418
464
|
if (opts.yes) {
|
|
419
465
|
config = {
|
|
@@ -1013,7 +1059,7 @@ var connectCommand = new Command6("connect").description("Configure Claude/Curso
|
|
|
1013
1059
|
import { Command as Command7 } from "commander";
|
|
1014
1060
|
import chalk7 from "chalk";
|
|
1015
1061
|
import ora6 from "ora";
|
|
1016
|
-
import { select, confirm as confirm3 } from "@inquirer/prompts";
|
|
1062
|
+
import { select as select2, confirm as confirm3 } from "@inquirer/prompts";
|
|
1017
1063
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, readdirSync, existsSync as existsSync4 } from "fs";
|
|
1018
1064
|
import { join as join4 } from "path";
|
|
1019
1065
|
import { createHash } from "crypto";
|
|
@@ -1110,7 +1156,7 @@ var updateCommand = new Command7("update").description("Update Horus to the late
|
|
|
1110
1156
|
name: `${snapshot.timestamp} (images: ${Object.keys(snapshot.images).length})`,
|
|
1111
1157
|
value: i
|
|
1112
1158
|
}));
|
|
1113
|
-
const idx = await
|
|
1159
|
+
const idx = await select2({
|
|
1114
1160
|
message: "Select snapshot to restore:",
|
|
1115
1161
|
choices
|
|
1116
1162
|
});
|
|
@@ -1289,7 +1335,7 @@ function colorMessage(status, msg) {
|
|
|
1289
1335
|
return chalk8.red(msg);
|
|
1290
1336
|
}
|
|
1291
1337
|
}
|
|
1292
|
-
async function
|
|
1338
|
+
async function checkRuntime2() {
|
|
1293
1339
|
try {
|
|
1294
1340
|
execSync("docker info", { stdio: "ignore" });
|
|
1295
1341
|
return { status: "pass", label: "Runtime", message: "Docker is running" };
|
|
@@ -1477,7 +1523,7 @@ var doctorCommand = new Command8("doctor").description("Diagnose common Horus is
|
|
|
1477
1523
|
console.log(chalk8.bold("Horus Doctor"));
|
|
1478
1524
|
console.log(chalk8.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1479
1525
|
const allResults = [];
|
|
1480
|
-
allResults.push(await
|
|
1526
|
+
allResults.push(await checkRuntime2());
|
|
1481
1527
|
allResults.push(await checkCompose());
|
|
1482
1528
|
allResults.push(checkConfig());
|
|
1483
1529
|
allResults.push(checkComposeFile());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arkhera30/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "CLI for managing the Horus AI development stack",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,20 +9,22 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsup src/index.ts --format esm --dts",
|
|
11
11
|
"dev": "tsup src/index.ts --format esm --watch",
|
|
12
|
-
"typecheck": "tsc --noEmit"
|
|
12
|
+
"typecheck": "tsc --noEmit",
|
|
13
|
+
"test": "vitest run"
|
|
13
14
|
},
|
|
14
15
|
"dependencies": {
|
|
15
16
|
"@inquirer/prompts": "^7.0.0",
|
|
17
|
+
"chalk": "^5.0.0",
|
|
16
18
|
"commander": "^12.0.0",
|
|
17
19
|
"execa": "^8.0.0",
|
|
18
|
-
"
|
|
19
|
-
"yaml": "^2.0.0"
|
|
20
|
-
"ora": "^8.0.0"
|
|
20
|
+
"ora": "^8.0.0",
|
|
21
|
+
"yaml": "^2.0.0"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
|
-
"
|
|
24
|
+
"@types/node": "^20.0.0",
|
|
24
25
|
"tsup": "^8.0.0",
|
|
25
|
-
"
|
|
26
|
+
"typescript": "^5.4.0",
|
|
27
|
+
"vitest": "^4.0.18"
|
|
26
28
|
},
|
|
27
29
|
"engines": {
|
|
28
30
|
"node": ">=18"
|