@arkhera30/cli 0.1.6 → 0.1.8
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 +84 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import ora from "ora";
|
|
|
12
12
|
import { execSync } from "child_process";
|
|
13
13
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
14
14
|
import { join as join3 } from "path";
|
|
15
|
-
import { input, confirm, number, select } from "@inquirer/prompts";
|
|
15
|
+
import { input, confirm, number, select, password } from "@inquirer/prompts";
|
|
16
16
|
|
|
17
17
|
// src/lib/config.ts
|
|
18
18
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
@@ -123,10 +123,13 @@ function generateEnv(config) {
|
|
|
123
123
|
`VAULT_MCP_PORT=${config.ports.vault_mcp}`,
|
|
124
124
|
`FORGE_PORT=${config.ports.forge}`,
|
|
125
125
|
"",
|
|
126
|
-
"# Repository URLs",
|
|
126
|
+
"# Repository URLs (must be HTTPS \u2014 container services do not have SSH keys)",
|
|
127
127
|
`ANVIL_REPO_URL=${config.repos.anvil_notes}`,
|
|
128
128
|
`VAULT_KNOWLEDGE_REPO_URL=${config.repos.vault_knowledge}`,
|
|
129
129
|
`FORGE_REGISTRY_REPO_URL=${config.repos.forge_registry}`,
|
|
130
|
+
"",
|
|
131
|
+
"# Authentication",
|
|
132
|
+
`GITHUB_TOKEN=${config.github_token}`,
|
|
130
133
|
""
|
|
131
134
|
];
|
|
132
135
|
return lines.join("\n");
|
|
@@ -428,7 +431,18 @@ function installComposeFile() {
|
|
|
428
431
|
}
|
|
429
432
|
|
|
430
433
|
// src/commands/setup.ts
|
|
431
|
-
|
|
434
|
+
function injectToken(url, token) {
|
|
435
|
+
if (!token) return url;
|
|
436
|
+
try {
|
|
437
|
+
const parsed = new URL(url);
|
|
438
|
+
parsed.username = "oauth2";
|
|
439
|
+
parsed.password = token;
|
|
440
|
+
return parsed.toString();
|
|
441
|
+
} catch {
|
|
442
|
+
return url;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
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").option("--git-host <host>", "Git server hostname (e.g., github.com, gitlab.corp.com)").option("--anvil-repo <url>", "Anvil notes repository URL").option("--vault-repo <url>", "Vault knowledge-base repository URL").option("--forge-repo <url>", "Forge registry repository URL").option("--github-token <token>", "GitHub personal access token for private repos").action(async (opts) => {
|
|
432
446
|
console.log("");
|
|
433
447
|
console.log(chalk.bold("Horus Setup"));
|
|
434
448
|
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"));
|
|
@@ -500,7 +514,8 @@ var setupCommand = new Command("setup").description("Interactive first-run setup
|
|
|
500
514
|
anvil_notes: opts.anvilRepo || process.env.ANVIL_REPO_URL || defaults.repos.anvil_notes,
|
|
501
515
|
vault_knowledge: opts.vaultRepo || process.env.VAULT_KNOWLEDGE_REPO_URL || defaults.repos.vault_knowledge,
|
|
502
516
|
forge_registry: opts.forgeRepo || process.env.FORGE_REGISTRY_REPO_URL || defaults.repos.forge_registry
|
|
503
|
-
}
|
|
517
|
+
},
|
|
518
|
+
github_token: opts.githubToken || process.env.GITHUB_TOKEN || ""
|
|
504
519
|
};
|
|
505
520
|
} else {
|
|
506
521
|
const data_dir = await input({
|
|
@@ -545,26 +560,42 @@ var setupCommand = new Command("setup").description("Interactive first-run setup
|
|
|
545
560
|
console.log(chalk.dim("Horus stores notes and knowledge in Git repos you own."));
|
|
546
561
|
console.log(chalk.dim("Create empty repos on your Git server, then paste the URLs below."));
|
|
547
562
|
console.log("");
|
|
563
|
+
console.log(chalk.yellow(" Use HTTPS URLs \u2014 container services do not have SSH keys."));
|
|
564
|
+
console.log(chalk.dim(" SSH URLs (git@github.com:...) will fail at runtime inside Docker/Podman."));
|
|
565
|
+
console.log("");
|
|
548
566
|
const git_host = await input({
|
|
549
567
|
message: "Git server hostname:",
|
|
550
568
|
default: "github.com"
|
|
551
569
|
});
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
console.log(chalk.dim(` Example: ${examplePrefix}/my-repo.git`));
|
|
570
|
+
const host = git_host.trim();
|
|
571
|
+
const example = (repo) => chalk.dim(` e.g., https://${host}/<owner>/${repo}`);
|
|
555
572
|
console.log("");
|
|
556
573
|
const anvil_notes = await input({
|
|
557
|
-
message:
|
|
574
|
+
message: `Anvil notes repo URL:
|
|
575
|
+
${example("horus-notes")}
|
|
576
|
+
`,
|
|
558
577
|
validate: (v) => v.trim().length > 0 || "Anvil needs a notes repo to store your data."
|
|
559
578
|
});
|
|
560
579
|
const vault_knowledge = await input({
|
|
561
|
-
message:
|
|
580
|
+
message: `Vault knowledge-base repo URL:
|
|
581
|
+
${example("knowledge-base")}
|
|
582
|
+
`,
|
|
562
583
|
validate: (v) => v.trim().length > 0 || "Vault needs a knowledge-base repo."
|
|
563
584
|
});
|
|
564
585
|
const forge_registry = await input({
|
|
565
|
-
message:
|
|
586
|
+
message: `Forge registry repo URL:
|
|
587
|
+
${example("forge-registry")}
|
|
588
|
+
`,
|
|
566
589
|
validate: (v) => v.trim().length > 0 || "Forge needs a registry repo."
|
|
567
590
|
});
|
|
591
|
+
console.log("");
|
|
592
|
+
console.log(chalk.bold("Authentication"));
|
|
593
|
+
console.log(chalk.dim("A personal access token is required for private repositories."));
|
|
594
|
+
console.log("");
|
|
595
|
+
const github_token = await password({
|
|
596
|
+
message: "GitHub personal access token (leave empty to skip):",
|
|
597
|
+
mask: "*"
|
|
598
|
+
});
|
|
568
599
|
config = {
|
|
569
600
|
...defaultConfig(),
|
|
570
601
|
data_dir,
|
|
@@ -576,7 +607,8 @@ var setupCommand = new Command("setup").description("Interactive first-run setup
|
|
|
576
607
|
anvil_notes: anvil_notes.trim(),
|
|
577
608
|
vault_knowledge: vault_knowledge.trim(),
|
|
578
609
|
forge_registry: forge_registry.trim()
|
|
579
|
-
}
|
|
610
|
+
},
|
|
611
|
+
github_token: github_token.trim()
|
|
580
612
|
};
|
|
581
613
|
}
|
|
582
614
|
const configSpinner = ora("Saving configuration...").start();
|
|
@@ -624,7 +656,8 @@ var setupCommand = new Command("setup").description("Interactive first-run setup
|
|
|
624
656
|
}
|
|
625
657
|
try {
|
|
626
658
|
mkdirSync2(repo.dest, { recursive: true });
|
|
627
|
-
|
|
659
|
+
const cloneUrl = injectToken(repo.url, config.github_token);
|
|
660
|
+
execSync(`git clone "${cloneUrl}" "${repo.dest}"`, {
|
|
628
661
|
stdio: "pipe",
|
|
629
662
|
timeout: 6e4
|
|
630
663
|
});
|
|
@@ -638,7 +671,9 @@ var setupCommand = new Command("setup").description("Interactive first-run setup
|
|
|
638
671
|
console.log(chalk.dim(` ${msg.split("\n")[0]}`));
|
|
639
672
|
}
|
|
640
673
|
console.log(chalk.dim(` URL: ${repo.url}`));
|
|
641
|
-
|
|
674
|
+
if (!config.github_token) {
|
|
675
|
+
console.log(chalk.dim(" Tip: Re-run setup and provide a GitHub token if the repo is private."));
|
|
676
|
+
}
|
|
642
677
|
process.exit(1);
|
|
643
678
|
}
|
|
644
679
|
}
|
|
@@ -1051,6 +1086,27 @@ async function syncSkills(runtime) {
|
|
|
1051
1086
|
}
|
|
1052
1087
|
}
|
|
1053
1088
|
}
|
|
1089
|
+
async function syncSkillsForCursor(runtime) {
|
|
1090
|
+
const home = homedir3();
|
|
1091
|
+
const rulesDir = join4(home, ".cursor", "rules");
|
|
1092
|
+
const skills = ["horus-anvil", "horus-vault", "horus-forge"];
|
|
1093
|
+
const forgeContainer = "horus-forge-1";
|
|
1094
|
+
mkdirSync3(rulesDir, { recursive: true });
|
|
1095
|
+
for (const skill of skills) {
|
|
1096
|
+
const src = `/home/forge/.claude/skills/${skill}/SKILL.md`;
|
|
1097
|
+
const dest = join4(rulesDir, `${skill}.mdc`);
|
|
1098
|
+
const result = await runtime.exec(forgeContainer, "cat", src);
|
|
1099
|
+
if (result.exitCode === 0 && result.stdout.trim()) {
|
|
1100
|
+
const frontmatter = `---
|
|
1101
|
+
description: Horus ${skill} reference
|
|
1102
|
+
alwaysApply: true
|
|
1103
|
+
---
|
|
1104
|
+
|
|
1105
|
+
`;
|
|
1106
|
+
writeFileSync3(dest, frontmatter + result.stdout, "utf-8");
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1054
1110
|
function printNextSteps(targets) {
|
|
1055
1111
|
console.log("");
|
|
1056
1112
|
console.log(chalk6.bold("Next steps:"));
|
|
@@ -1063,7 +1119,7 @@ function printNextSteps(targets) {
|
|
|
1063
1119
|
console.log(` ${chalk6.cyan("Claude Code")} Start a new Claude Code session`);
|
|
1064
1120
|
break;
|
|
1065
1121
|
case "cursor":
|
|
1066
|
-
console.log(` ${chalk6.cyan("Cursor")} Restart Cursor`);
|
|
1122
|
+
console.log(` ${chalk6.cyan("Cursor")} Restart Cursor to pick up the new MCP configuration and rules`);
|
|
1067
1123
|
break;
|
|
1068
1124
|
}
|
|
1069
1125
|
}
|
|
@@ -1154,6 +1210,16 @@ var connectCommand = new Command6("connect").description("Configure Claude/Curso
|
|
|
1154
1210
|
console.log(chalk6.dim(error.message));
|
|
1155
1211
|
}
|
|
1156
1212
|
}
|
|
1213
|
+
if (targets.includes("cursor")) {
|
|
1214
|
+
const cursorRulesSpinner = ora5("Syncing horus-core rules for Cursor...").start();
|
|
1215
|
+
try {
|
|
1216
|
+
await syncSkillsForCursor(runtime);
|
|
1217
|
+
cursorRulesSpinner.succeed("horus-core rules synced to ~/.cursor/rules/");
|
|
1218
|
+
} catch (error) {
|
|
1219
|
+
cursorRulesSpinner.warn("Could not sync Cursor rules (Forge container may not be running)");
|
|
1220
|
+
console.log(chalk6.dim(error.message));
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1157
1223
|
printNextSteps(targets);
|
|
1158
1224
|
});
|
|
1159
1225
|
|
|
@@ -1330,6 +1396,10 @@ var updateCommand = new Command7("update").description("Update Horus to the late
|
|
|
1330
1396
|
console.log(chalk7.dim(" Could not reach GitHub to check latest version."));
|
|
1331
1397
|
}
|
|
1332
1398
|
console.log("");
|
|
1399
|
+
console.log(chalk7.dim(" Note: this updates the Horus container services only."));
|
|
1400
|
+
console.log(chalk7.dim(" To update the Horus CLI itself, run:"));
|
|
1401
|
+
console.log(` ${chalk7.cyan("npm install -g @arkhera30/cli@latest")}`);
|
|
1402
|
+
console.log("");
|
|
1333
1403
|
if (!opts.yes) {
|
|
1334
1404
|
const confirmed = await confirm3({
|
|
1335
1405
|
message: "Pull latest images and restart services?",
|