@arkhera30/cli 0.3.5 → 0.3.7
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 +46 -19
- 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
|
|
@@ -624,8 +630,11 @@ var FORGE_SERVICE = ` # \u2500\u2500 Forge \u2500\u2500\u2500\u2500\u2500\u2500
|
|
|
624
630
|
ports:
|
|
625
631
|
- "\${FORGE_PORT:-8200}:8200"
|
|
626
632
|
volumes:
|
|
633
|
+
- \${HORUS_DATA_PATH}/config:/data/config:rw
|
|
627
634
|
- \${HORUS_DATA_PATH}/registry:/data/registry:rw
|
|
628
635
|
- \${HORUS_DATA_PATH}/workspaces:/data/workspaces:rw
|
|
636
|
+
- \${HORUS_DATA_PATH}/repos:/data/horus-repos:rw
|
|
637
|
+
- \${HORUS_DATA_PATH}/sessions:/data/sessions:rw
|
|
629
638
|
- \${HOST_REPOS_PATH}:/data/repos:ro
|
|
630
639
|
environment:
|
|
631
640
|
- HORUS_RUNTIME=\${HORUS_RUNTIME:-docker}
|
|
@@ -633,6 +642,8 @@ var FORGE_SERVICE = ` # \u2500\u2500 Forge \u2500\u2500\u2500\u2500\u2500\u2500
|
|
|
633
642
|
- FORGE_HOST=0.0.0.0
|
|
634
643
|
- FORGE_REGISTRY_PATH=/data/registry
|
|
635
644
|
- FORGE_WORKSPACES_PATH=/data/workspaces
|
|
645
|
+
- FORGE_CONFIG_PATH=/data/config
|
|
646
|
+
- FORGE_MANAGED_REPOS_PATH=/data/horus-repos
|
|
636
647
|
- FORGE_REGISTRY_REPO_URL=\${FORGE_REGISTRY_REPO_URL:-}
|
|
637
648
|
- FORGE_SYNC_INTERVAL=\${FORGE_SYNC_INTERVAL:-300}
|
|
638
649
|
- FORGE_ANVIL_URL=http://anvil:8100
|
|
@@ -644,9 +655,14 @@ var FORGE_SERVICE = ` # \u2500\u2500 Forge \u2500\u2500\u2500\u2500\u2500\u2500
|
|
|
644
655
|
- FORGE_HOST_FORGE_URL=http://localhost:\${FORGE_PORT:-8200}
|
|
645
656
|
- FORGE_SCAN_PATHS=\${FORGE_SCAN_PATHS:-/data/repos}
|
|
646
657
|
- GITHUB_TOKEN=\${GITHUB_TOKEN:-}
|
|
658
|
+
- TYPESENSE_HOST=typesense
|
|
659
|
+
- TYPESENSE_PORT=8108
|
|
660
|
+
- TYPESENSE_API_KEY=\${TYPESENSE_API_KEY:-horus-local-key}
|
|
647
661
|
depends_on:
|
|
648
662
|
anvil:
|
|
649
663
|
condition: service_healthy
|
|
664
|
+
typesense:
|
|
665
|
+
condition: service_healthy
|
|
650
666
|
vault-router:
|
|
651
667
|
condition: service_healthy
|
|
652
668
|
networks:
|
|
@@ -726,7 +742,11 @@ var HORUS_UI_SERVICE = ` # \u2500\u2500 Horus UI \u2500\u2500\u2500\u2500\u2500
|
|
|
726
742
|
timeout: 5s
|
|
727
743
|
start_period: 30s
|
|
728
744
|
retries: 3`;
|
|
729
|
-
|
|
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
|
|
730
750
|
# Horus \u2014 Shadow Stack Overlay for Integration Testing
|
|
731
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
|
|
732
752
|
# Usage (managed by \`horus test-env acquire\`):
|
|
@@ -739,9 +759,6 @@ var TEST_COMPOSE_CONTENT = `# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u
|
|
|
739
759
|
#
|
|
740
760
|
# All TEST_PORT_* and TEST_DATA_PATH are set by \`horus test-env acquire\`.
|
|
741
761
|
# Slot 0 defaults: ports 9100-9399, data at ~/Horus/data/test-env/slot-0/
|
|
742
|
-
#
|
|
743
|
-
# NOTE: vault-personal is assumed as the primary vault name. If your config
|
|
744
|
-
# uses a different vault name, set TEST_VAULT_NAME accordingly.
|
|
745
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
|
|
746
763
|
|
|
747
764
|
services:
|
|
@@ -751,11 +768,11 @@ services:
|
|
|
751
768
|
volumes:
|
|
752
769
|
- "\${TEST_DATA_PATH:-/tmp/horus-test}/notes:/data/notes:rw"
|
|
753
770
|
|
|
754
|
-
vault
|
|
771
|
+
vault-${vaultName}:
|
|
755
772
|
ports:
|
|
756
773
|
- "\${TEST_PORT_VAULT_SVC:-9101}:8000"
|
|
757
774
|
volumes:
|
|
758
|
-
- "\${TEST_DATA_PATH:-/tmp/horus-test}/vaults
|
|
775
|
+
- "\${TEST_DATA_PATH:-/tmp/horus-test}/vaults/${vaultName}:/data/knowledge-repo:rw"
|
|
759
776
|
|
|
760
777
|
vault-router:
|
|
761
778
|
ports:
|
|
@@ -769,8 +786,10 @@ services:
|
|
|
769
786
|
ports:
|
|
770
787
|
- "\${TEST_PORT_FORGE:-9250}:8200"
|
|
771
788
|
volumes:
|
|
789
|
+
- "\${TEST_DATA_PATH:-/tmp/horus-test}/config:/data/config:rw"
|
|
772
790
|
- "\${TEST_DATA_PATH:-/tmp/horus-test}/registry:/data/registry:rw"
|
|
773
791
|
- "\${TEST_DATA_PATH:-/tmp/horus-test}/workspaces:/data/workspaces:rw"
|
|
792
|
+
- "\${TEST_DATA_PATH:-/tmp/horus-test}/repos:/data/horus-repos:rw"
|
|
774
793
|
- "\${TEST_DATA_PATH:-/tmp/horus-test}/sessions:/data/sessions:rw"
|
|
775
794
|
|
|
776
795
|
typesense:
|
|
@@ -783,6 +802,7 @@ services:
|
|
|
783
802
|
ports:
|
|
784
803
|
- "\${TEST_PORT_UI:-9260}:8400"
|
|
785
804
|
`;
|
|
805
|
+
}
|
|
786
806
|
function generateComposeFile(config, runtime) {
|
|
787
807
|
const vaultEntries = Object.entries(config.vaults).sort(([a], [b]) => a.localeCompare(b));
|
|
788
808
|
const vaultServices = vaultEntries.map(([name, vault], index) => {
|
|
@@ -932,7 +952,7 @@ function installComposeFile(config, runtime) {
|
|
|
932
952
|
ensureHorusDir();
|
|
933
953
|
const content = generateComposeFile(config, runtime);
|
|
934
954
|
writeFileSync2(COMPOSE_PATH, content, "utf-8");
|
|
935
|
-
writeFileSync2(COMPOSE_TEST_PATH,
|
|
955
|
+
writeFileSync2(COMPOSE_TEST_PATH, generateTestComposeFile(config), "utf-8");
|
|
936
956
|
}
|
|
937
957
|
|
|
938
958
|
// src/commands/connect.ts
|
|
@@ -2836,10 +2856,10 @@ function findFreeSlot(dataDir, cfg) {
|
|
|
2836
2856
|
}
|
|
2837
2857
|
return null;
|
|
2838
2858
|
}
|
|
2839
|
-
function createSlotDirs(slotDataPath) {
|
|
2859
|
+
function createSlotDirs(slotDataPath, vaultNames = ["default"]) {
|
|
2840
2860
|
const dirs = [
|
|
2841
2861
|
"notes",
|
|
2842
|
-
join7("vaults",
|
|
2862
|
+
...vaultNames.map((name) => join7("vaults", name)),
|
|
2843
2863
|
"registry",
|
|
2844
2864
|
"workspaces",
|
|
2845
2865
|
"sessions",
|
|
@@ -2878,7 +2898,8 @@ async function preSeedNotesDir(dataDir, slotDataPath) {
|
|
|
2878
2898
|
]);
|
|
2879
2899
|
}
|
|
2880
2900
|
}
|
|
2881
|
-
function buildComposeEnv(runtime, ports, slotDataPath) {
|
|
2901
|
+
function buildComposeEnv(runtime, ports, slotDataPath, defaultVaultName = "default") {
|
|
2902
|
+
const vaultPortEnvVar = `VAULT_REST_PORT_${defaultVaultName.toUpperCase().replace(/-/g, "_")}`;
|
|
2882
2903
|
return {
|
|
2883
2904
|
...process.env,
|
|
2884
2905
|
HORUS_RUNTIME: runtime.name,
|
|
@@ -2891,7 +2912,7 @@ function buildComposeEnv(runtime, ports, slotDataPath) {
|
|
|
2891
2912
|
FORGE_PORT: String(ports.forge),
|
|
2892
2913
|
VAULT_MCP_PORT: String(ports.vault_mcp),
|
|
2893
2914
|
VAULT_ROUTER_PORT: String(ports.vault_router),
|
|
2894
|
-
|
|
2915
|
+
[vaultPortEnvVar]: String(ports.vault_svc),
|
|
2895
2916
|
TYPESENSE_PORT: String(ports.typesense),
|
|
2896
2917
|
UI_PORT: String(ports.ui),
|
|
2897
2918
|
// TEST_PORT_* vars for overlay reference (harmless duplicates after above fix)
|
|
@@ -2904,8 +2925,8 @@ function buildComposeEnv(runtime, ports, slotDataPath) {
|
|
|
2904
2925
|
TEST_PORT_UI: String(ports.ui)
|
|
2905
2926
|
};
|
|
2906
2927
|
}
|
|
2907
|
-
async function composeUp(runtime, projectName2, ports, slotDataPath) {
|
|
2908
|
-
const env = buildComposeEnv(runtime, ports, slotDataPath);
|
|
2928
|
+
async function composeUp(runtime, projectName2, ports, slotDataPath, defaultVaultName = "default") {
|
|
2929
|
+
const env = buildComposeEnv(runtime, ports, slotDataPath, defaultVaultName);
|
|
2909
2930
|
const result = await execa3(
|
|
2910
2931
|
runtime.name,
|
|
2911
2932
|
[
|
|
@@ -2928,8 +2949,8 @@ ${result.stderr}`
|
|
|
2928
2949
|
);
|
|
2929
2950
|
}
|
|
2930
2951
|
}
|
|
2931
|
-
async function composeDown(runtime, projectName2, ports, slotDataPath) {
|
|
2932
|
-
const env = buildComposeEnv(runtime, ports, slotDataPath);
|
|
2952
|
+
async function composeDown(runtime, projectName2, ports, slotDataPath, defaultVaultName = "default") {
|
|
2953
|
+
const env = buildComposeEnv(runtime, ports, slotDataPath, defaultVaultName);
|
|
2933
2954
|
await execa3(
|
|
2934
2955
|
runtime.name,
|
|
2935
2956
|
["compose", "-p", projectName2, "down", "--volumes", "--remove-orphans"],
|
|
@@ -3016,6 +3037,9 @@ testEnvCommand.command("acquire").description("Start a shadow stack on alternate
|
|
|
3016
3037
|
const config = loadConfig();
|
|
3017
3038
|
const dataDir = config.data_dir;
|
|
3018
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";
|
|
3019
3043
|
const spinner = ora8("Detecting runtime...").start();
|
|
3020
3044
|
let runtime;
|
|
3021
3045
|
try {
|
|
@@ -3037,7 +3061,7 @@ testEnvCommand.command("acquire").description("Start a shadow stack on alternate
|
|
|
3037
3061
|
const slotDataPath = getSlotDataPath(dataDir, slot);
|
|
3038
3062
|
const project = projectName(slot);
|
|
3039
3063
|
const dirSpinner = ora8(`Creating slot-${slot} data directories...`).start();
|
|
3040
|
-
createSlotDirs(slotDataPath);
|
|
3064
|
+
createSlotDirs(slotDataPath, vaultNames);
|
|
3041
3065
|
dirSpinner.succeed(`Data directory: ${chalk10.dim(slotDataPath)}`);
|
|
3042
3066
|
const seedSpinner = ora8("Pre-seeding notes directory...").start();
|
|
3043
3067
|
try {
|
|
@@ -3058,7 +3082,7 @@ testEnvCommand.command("acquire").description("Start a shadow stack on alternate
|
|
|
3058
3082
|
});
|
|
3059
3083
|
const upSpinner = ora8(`Starting shadow stack (project ${chalk10.cyan(project)})...`).start();
|
|
3060
3084
|
try {
|
|
3061
|
-
await composeUp(runtime, project, ports, slotDataPath);
|
|
3085
|
+
await composeUp(runtime, project, ports, slotDataPath, defaultVaultName);
|
|
3062
3086
|
upSpinner.succeed(`Shadow stack started`);
|
|
3063
3087
|
} catch (error) {
|
|
3064
3088
|
upSpinner.fail("Failed to start shadow stack");
|
|
@@ -3077,7 +3101,7 @@ testEnvCommand.command("acquire").description("Start a shadow stack on alternate
|
|
|
3077
3101
|
healthSpinner.succeed("All services healthy");
|
|
3078
3102
|
} catch (error) {
|
|
3079
3103
|
healthSpinner.fail("Health check failed");
|
|
3080
|
-
await composeDown(runtime, project, ports, slotDataPath);
|
|
3104
|
+
await composeDown(runtime, project, ports, slotDataPath, defaultVaultName);
|
|
3081
3105
|
removeLock(dataDir, slot);
|
|
3082
3106
|
removeSlotDirs(slotDataPath);
|
|
3083
3107
|
console.error(error.message);
|
|
@@ -3113,6 +3137,9 @@ testEnvCommand.command("release").description("Tear down a shadow stack and remo
|
|
|
3113
3137
|
const config = loadConfig();
|
|
3114
3138
|
const dataDir = config.data_dir;
|
|
3115
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";
|
|
3116
3143
|
let slot;
|
|
3117
3144
|
if (opts.slot !== void 0) {
|
|
3118
3145
|
slot = parseInt(opts.slot, 10);
|
|
@@ -3141,7 +3168,7 @@ testEnvCommand.command("release").description("Tear down a shadow stack and remo
|
|
|
3141
3168
|
}
|
|
3142
3169
|
const downSpinner = ora8(`Stopping ${chalk10.cyan(project)}...`).start();
|
|
3143
3170
|
try {
|
|
3144
|
-
await composeDown(runtime, project, ports, slotDataPath);
|
|
3171
|
+
await composeDown(runtime, project, ports, slotDataPath, defaultVaultName);
|
|
3145
3172
|
downSpinner.succeed("Shadow stack stopped");
|
|
3146
3173
|
} catch {
|
|
3147
3174
|
downSpinner.warn("Failed to stop cleanly (continuing cleanup)");
|