@arkhera30/cli 0.3.6 → 0.3.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 +43 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -601,6 +601,12 @@ var ANVIL_SERVICE = ` # \u2500\u2500 Anvil \u2500\u2500\u2500\u2500\u2500\u2500
601
601
  - ANVIL_SYNC_INTERVAL=\${ANVIL_SYNC_INTERVAL:-300}
602
602
  - ANVIL_DEBOUNCE_SECONDS=\${ANVIL_DEBOUNCE_SECONDS:-5}
603
603
  - GITHUB_TOKEN=\${GITHUB_TOKEN:-}
604
+ - TYPESENSE_HOST=typesense
605
+ - TYPESENSE_PORT=8108
606
+ - TYPESENSE_API_KEY=\${TYPESENSE_API_KEY:-horus-local-key}
607
+ depends_on:
608
+ typesense:
609
+ condition: service_healthy
604
610
  networks:
605
611
  - horus-net
606
612
  restart: unless-stopped
@@ -649,9 +655,14 @@ var FORGE_SERVICE = ` # \u2500\u2500 Forge \u2500\u2500\u2500\u2500\u2500\u2500
649
655
  - FORGE_HOST_FORGE_URL=http://localhost:\${FORGE_PORT:-8200}
650
656
  - FORGE_SCAN_PATHS=\${FORGE_SCAN_PATHS:-/data/repos}
651
657
  - GITHUB_TOKEN=\${GITHUB_TOKEN:-}
658
+ - TYPESENSE_HOST=typesense
659
+ - TYPESENSE_PORT=8108
660
+ - TYPESENSE_API_KEY=\${TYPESENSE_API_KEY:-horus-local-key}
652
661
  depends_on:
653
662
  anvil:
654
663
  condition: service_healthy
664
+ typesense:
665
+ condition: service_healthy
655
666
  vault-router:
656
667
  condition: service_healthy
657
668
  networks:
@@ -731,7 +742,11 @@ var HORUS_UI_SERVICE = ` # \u2500\u2500 Horus UI \u2500\u2500\u2500\u2500\u2500
731
742
  timeout: 5s
732
743
  start_period: 30s
733
744
  retries: 3`;
734
- var TEST_COMPOSE_CONTENT = `# \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\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\u2500
745
+ function generateTestComposeFile(config) {
746
+ const vaultEntries = Object.entries(config.vaults).sort(([a], [b]) => a.localeCompare(b));
747
+ const defaultVaultEntry = vaultEntries.find(([, v]) => v.default);
748
+ const vaultName = defaultVaultEntry ? defaultVaultEntry[0] : vaultEntries[0]?.[0] ?? "default";
749
+ return `# \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\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\u2500
735
750
  # Horus \u2014 Shadow Stack Overlay for Integration Testing
736
751
  # \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\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\u2500
737
752
  # Usage (managed by \`horus test-env acquire\`):
@@ -744,9 +759,6 @@ var TEST_COMPOSE_CONTENT = `# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u
744
759
  #
745
760
  # All TEST_PORT_* and TEST_DATA_PATH are set by \`horus test-env acquire\`.
746
761
  # Slot 0 defaults: ports 9100-9399, data at ~/Horus/data/test-env/slot-0/
747
- #
748
- # NOTE: vault-personal is assumed as the primary vault name. If your config
749
- # uses a different vault name, set TEST_VAULT_NAME accordingly.
750
762
  # \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\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\u2500
751
763
 
752
764
  services:
@@ -756,11 +768,11 @@ services:
756
768
  volumes:
757
769
  - "\${TEST_DATA_PATH:-/tmp/horus-test}/notes:/data/notes:rw"
758
770
 
759
- vault-personal:
771
+ vault-${vaultName}:
760
772
  ports:
761
773
  - "\${TEST_PORT_VAULT_SVC:-9101}:8000"
762
774
  volumes:
763
- - "\${TEST_DATA_PATH:-/tmp/horus-test}/vaults/personal:/data/knowledge-repo:rw"
775
+ - "\${TEST_DATA_PATH:-/tmp/horus-test}/vaults/${vaultName}:/data/knowledge-repo:rw"
764
776
 
765
777
  vault-router:
766
778
  ports:
@@ -790,6 +802,7 @@ services:
790
802
  ports:
791
803
  - "\${TEST_PORT_UI:-9260}:8400"
792
804
  `;
805
+ }
793
806
  function generateComposeFile(config, runtime) {
794
807
  const vaultEntries = Object.entries(config.vaults).sort(([a], [b]) => a.localeCompare(b));
795
808
  const vaultServices = vaultEntries.map(([name, vault], index) => {
@@ -939,7 +952,7 @@ function installComposeFile(config, runtime) {
939
952
  ensureHorusDir();
940
953
  const content = generateComposeFile(config, runtime);
941
954
  writeFileSync2(COMPOSE_PATH, content, "utf-8");
942
- writeFileSync2(COMPOSE_TEST_PATH, TEST_COMPOSE_CONTENT, "utf-8");
955
+ writeFileSync2(COMPOSE_TEST_PATH, generateTestComposeFile(config), "utf-8");
943
956
  }
944
957
 
945
958
  // src/commands/connect.ts
@@ -1625,7 +1638,7 @@ ${example(`${vaultName.trim()}-knowledge`)}
1625
1638
  console.log("");
1626
1639
  console.log(chalk2.bold("Starting Horus services..."));
1627
1640
  try {
1628
- await composeStreaming(runtime, ["up", "-d"]);
1641
+ await composeStreaming(runtime, ["up", "-d", "--remove-orphans"]);
1629
1642
  } catch (error) {
1630
1643
  console.log(chalk2.red("Failed to start services."));
1631
1644
  console.log(chalk2.dim(error.message));
@@ -1731,7 +1744,7 @@ var upCommand = new Command3("up").description("Start the Horus stack").option("
1731
1744
  console.log("");
1732
1745
  console.log(chalk3.bold("Starting Horus services..."));
1733
1746
  try {
1734
- const upArgs = opts.pull ? ["up", "-d", "--force-recreate"] : ["up", "-d"];
1747
+ const upArgs = opts.pull ? ["up", "-d", "--force-recreate", "--remove-orphans"] : ["up", "-d", "--remove-orphans"];
1735
1748
  await composeStreaming(runtime, upArgs);
1736
1749
  } catch (error) {
1737
1750
  console.log(chalk3.red("Failed to start services."));
@@ -2131,7 +2144,7 @@ var updateCommand = new Command7("update").description("Update Horus to the late
2131
2144
  console.log("");
2132
2145
  console.log(chalk7.bold("Restarting from snapshot (using cached images)..."));
2133
2146
  try {
2134
- await composeStreaming(runtime, ["up", "-d"]);
2147
+ await composeStreaming(runtime, ["up", "-d", "--remove-orphans"]);
2135
2148
  } catch (error) {
2136
2149
  console.log(chalk7.red("Failed to restart services."));
2137
2150
  console.log(chalk7.dim(error.message));
@@ -2209,7 +2222,7 @@ var updateCommand = new Command7("update").description("Update Horus to the late
2209
2222
  console.log("");
2210
2223
  console.log(chalk7.bold("Restarting services..."));
2211
2224
  try {
2212
- await composeStreaming(runtime, ["up", "-d", "--force-recreate"]);
2225
+ await composeStreaming(runtime, ["up", "-d", "--force-recreate", "--remove-orphans"]);
2213
2226
  } catch (error) {
2214
2227
  console.log(chalk7.red("Failed to restart services."));
2215
2228
  console.log(chalk7.dim(error.message));
@@ -2843,10 +2856,10 @@ function findFreeSlot(dataDir, cfg) {
2843
2856
  }
2844
2857
  return null;
2845
2858
  }
2846
- function createSlotDirs(slotDataPath) {
2859
+ function createSlotDirs(slotDataPath, vaultNames = ["default"]) {
2847
2860
  const dirs = [
2848
2861
  "notes",
2849
- join7("vaults", "personal"),
2862
+ ...vaultNames.map((name) => join7("vaults", name)),
2850
2863
  "registry",
2851
2864
  "workspaces",
2852
2865
  "sessions",
@@ -2885,7 +2898,8 @@ async function preSeedNotesDir(dataDir, slotDataPath) {
2885
2898
  ]);
2886
2899
  }
2887
2900
  }
2888
- function buildComposeEnv(runtime, ports, slotDataPath) {
2901
+ function buildComposeEnv(runtime, ports, slotDataPath, defaultVaultName = "default") {
2902
+ const vaultPortEnvVar = `VAULT_REST_PORT_${defaultVaultName.toUpperCase().replace(/-/g, "_")}`;
2889
2903
  return {
2890
2904
  ...process.env,
2891
2905
  HORUS_RUNTIME: runtime.name,
@@ -2898,7 +2912,7 @@ function buildComposeEnv(runtime, ports, slotDataPath) {
2898
2912
  FORGE_PORT: String(ports.forge),
2899
2913
  VAULT_MCP_PORT: String(ports.vault_mcp),
2900
2914
  VAULT_ROUTER_PORT: String(ports.vault_router),
2901
- VAULT_REST_PORT_PERSONAL: String(ports.vault_svc),
2915
+ [vaultPortEnvVar]: String(ports.vault_svc),
2902
2916
  TYPESENSE_PORT: String(ports.typesense),
2903
2917
  UI_PORT: String(ports.ui),
2904
2918
  // TEST_PORT_* vars for overlay reference (harmless duplicates after above fix)
@@ -2911,8 +2925,8 @@ function buildComposeEnv(runtime, ports, slotDataPath) {
2911
2925
  TEST_PORT_UI: String(ports.ui)
2912
2926
  };
2913
2927
  }
2914
- async function composeUp(runtime, projectName2, ports, slotDataPath) {
2915
- const env = buildComposeEnv(runtime, ports, slotDataPath);
2928
+ async function composeUp(runtime, projectName2, ports, slotDataPath, defaultVaultName = "default") {
2929
+ const env = buildComposeEnv(runtime, ports, slotDataPath, defaultVaultName);
2916
2930
  const result = await execa3(
2917
2931
  runtime.name,
2918
2932
  [
@@ -2935,8 +2949,8 @@ ${result.stderr}`
2935
2949
  );
2936
2950
  }
2937
2951
  }
2938
- async function composeDown(runtime, projectName2, ports, slotDataPath) {
2939
- const env = buildComposeEnv(runtime, ports, slotDataPath);
2952
+ async function composeDown(runtime, projectName2, ports, slotDataPath, defaultVaultName = "default") {
2953
+ const env = buildComposeEnv(runtime, ports, slotDataPath, defaultVaultName);
2940
2954
  await execa3(
2941
2955
  runtime.name,
2942
2956
  ["compose", "-p", projectName2, "down", "--volumes", "--remove-orphans"],
@@ -3023,6 +3037,9 @@ testEnvCommand.command("acquire").description("Start a shadow stack on alternate
3023
3037
  const config = loadConfig();
3024
3038
  const dataDir = config.data_dir;
3025
3039
  const testCfg = loadTestEnvConfig(dataDir);
3040
+ const vaultNames = Object.keys(config.vaults).sort();
3041
+ const defaultVaultEntry = Object.entries(config.vaults).find(([, v]) => v.default);
3042
+ const defaultVaultName = defaultVaultEntry?.[0] ?? vaultNames[0] ?? "default";
3026
3043
  const spinner = ora8("Detecting runtime...").start();
3027
3044
  let runtime;
3028
3045
  try {
@@ -3044,7 +3061,7 @@ testEnvCommand.command("acquire").description("Start a shadow stack on alternate
3044
3061
  const slotDataPath = getSlotDataPath(dataDir, slot);
3045
3062
  const project = projectName(slot);
3046
3063
  const dirSpinner = ora8(`Creating slot-${slot} data directories...`).start();
3047
- createSlotDirs(slotDataPath);
3064
+ createSlotDirs(slotDataPath, vaultNames);
3048
3065
  dirSpinner.succeed(`Data directory: ${chalk10.dim(slotDataPath)}`);
3049
3066
  const seedSpinner = ora8("Pre-seeding notes directory...").start();
3050
3067
  try {
@@ -3065,7 +3082,7 @@ testEnvCommand.command("acquire").description("Start a shadow stack on alternate
3065
3082
  });
3066
3083
  const upSpinner = ora8(`Starting shadow stack (project ${chalk10.cyan(project)})...`).start();
3067
3084
  try {
3068
- await composeUp(runtime, project, ports, slotDataPath);
3085
+ await composeUp(runtime, project, ports, slotDataPath, defaultVaultName);
3069
3086
  upSpinner.succeed(`Shadow stack started`);
3070
3087
  } catch (error) {
3071
3088
  upSpinner.fail("Failed to start shadow stack");
@@ -3084,7 +3101,7 @@ testEnvCommand.command("acquire").description("Start a shadow stack on alternate
3084
3101
  healthSpinner.succeed("All services healthy");
3085
3102
  } catch (error) {
3086
3103
  healthSpinner.fail("Health check failed");
3087
- await composeDown(runtime, project, ports, slotDataPath);
3104
+ await composeDown(runtime, project, ports, slotDataPath, defaultVaultName);
3088
3105
  removeLock(dataDir, slot);
3089
3106
  removeSlotDirs(slotDataPath);
3090
3107
  console.error(error.message);
@@ -3120,6 +3137,9 @@ testEnvCommand.command("release").description("Tear down a shadow stack and remo
3120
3137
  const config = loadConfig();
3121
3138
  const dataDir = config.data_dir;
3122
3139
  const testCfg = loadTestEnvConfig(dataDir);
3140
+ const vaultNames = Object.keys(config.vaults).sort();
3141
+ const defaultVaultEntry = Object.entries(config.vaults).find(([, v]) => v.default);
3142
+ const defaultVaultName = defaultVaultEntry?.[0] ?? vaultNames[0] ?? "default";
3123
3143
  let slot;
3124
3144
  if (opts.slot !== void 0) {
3125
3145
  slot = parseInt(opts.slot, 10);
@@ -3148,7 +3168,7 @@ testEnvCommand.command("release").description("Tear down a shadow stack and remo
3148
3168
  }
3149
3169
  const downSpinner = ora8(`Stopping ${chalk10.cyan(project)}...`).start();
3150
3170
  try {
3151
- await composeDown(runtime, project, ports, slotDataPath);
3171
+ await composeDown(runtime, project, ports, slotDataPath, defaultVaultName);
3152
3172
  downSpinner.succeed("Shadow stack stopped");
3153
3173
  } catch {
3154
3174
  downSpinner.warn("Failed to stop cleanly (continuing cleanup)");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkhera30/cli",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "CLI for managing the Horus AI development stack",
5
5
  "type": "module",
6
6
  "bin": {