@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.
Files changed (2) hide show
  1. package/dist/index.js +84 -14
  2. 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
- 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").action(async (opts) => {
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 examplePrefix = `git@${git_host}:<owner>`;
553
- console.log("");
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: "Anvil notes repo URL (required):",
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: "Vault knowledge-base repo URL (required):",
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: "Forge registry repo URL (required):",
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
- execSync(`git clone "${repo.url}" "${repo.dest}"`, {
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
- console.log(chalk.dim(" Ensure you have git access (SSH key or credential helper)."));
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?",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkhera30/cli",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "CLI for managing the Horus AI development stack",
5
5
  "type": "module",
6
6
  "bin": {