@arkhera30/cli 0.2.3 → 0.2.4
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/compose/docker-compose.yml +3 -57
- package/dist/index.js +72 -54
- package/package.json +2 -2
|
@@ -16,40 +16,6 @@
|
|
|
16
16
|
|
|
17
17
|
services:
|
|
18
18
|
|
|
19
|
-
# ── QMD Daemon ─────────────────────────────────────────────────────────────
|
|
20
|
-
# Shared QMD MCP HTTP server. Keeps GGUF models warm in memory so Anvil and
|
|
21
|
-
# Vault pay the model-load cost only once.
|
|
22
|
-
#
|
|
23
|
-
# The qmd-daemon-data volume is also mounted into the Anvil and Vault
|
|
24
|
-
# containers at their respective ~/.cache/qmd paths. This lets both services
|
|
25
|
-
# run `qmd collection add` / `qmd update` subprocess calls that write to the
|
|
26
|
-
# same SQLite database the daemon reads from — keeping the index current.
|
|
27
|
-
#
|
|
28
|
-
# start_period covers first-boot GGUF model download (~1-2 GB) + initial embed.
|
|
29
|
-
qmd-daemon:
|
|
30
|
-
image: ghcr.io/arjunkhera/horus/qmd-daemon:latest
|
|
31
|
-
environment:
|
|
32
|
-
- QMD_DAEMON_PORT=8181
|
|
33
|
-
- HORUS_RUNTIME=${HORUS_RUNTIME:-docker}
|
|
34
|
-
volumes:
|
|
35
|
-
- qmd-daemon-data:/home/qmd/.cache/qmd
|
|
36
|
-
networks:
|
|
37
|
-
- horus-net
|
|
38
|
-
restart: unless-stopped
|
|
39
|
-
stop_grace_period: 15s
|
|
40
|
-
deploy:
|
|
41
|
-
resources:
|
|
42
|
-
limits:
|
|
43
|
-
memory: 4g
|
|
44
|
-
reservations:
|
|
45
|
-
memory: 512m
|
|
46
|
-
healthcheck:
|
|
47
|
-
test: ["CMD", "curl", "-f", "http://localhost:8181/health"]
|
|
48
|
-
interval: 30s
|
|
49
|
-
timeout: 10s
|
|
50
|
-
start_period: 600s
|
|
51
|
-
retries: 3
|
|
52
|
-
|
|
53
19
|
# ── Anvil ──────────────────────────────────────────────────────────────────
|
|
54
20
|
# Notes system and MCP server. Indexes markdown files from the Notes repo.
|
|
55
21
|
anvil:
|
|
@@ -59,8 +25,6 @@ services:
|
|
|
59
25
|
volumes:
|
|
60
26
|
# Notes repo — read/write so Anvil can git-sync or clone on first boot
|
|
61
27
|
- ${HORUS_DATA_PATH}/notes:/data/notes:rw
|
|
62
|
-
# Shared QMD database + model cache (same volume as qmd-daemon).
|
|
63
|
-
- qmd-daemon-data:/home/anvil/.cache/qmd
|
|
64
28
|
environment:
|
|
65
29
|
- HORUS_RUNTIME=${HORUS_RUNTIME:-docker}
|
|
66
30
|
- ANVIL_TRANSPORT=http
|
|
@@ -68,15 +32,9 @@ services:
|
|
|
68
32
|
- ANVIL_HOST=0.0.0.0
|
|
69
33
|
- ANVIL_NOTES_PATH=/data/notes
|
|
70
34
|
- ANVIL_REPO_URL=${ANVIL_REPO_URL:-}
|
|
71
|
-
- ANVIL_QMD_COLLECTION=${ANVIL_QMD_COLLECTION:-anvil}
|
|
72
35
|
- ANVIL_SYNC_INTERVAL=${ANVIL_SYNC_INTERVAL:-300}
|
|
73
36
|
- ANVIL_DEBOUNCE_SECONDS=${ANVIL_DEBOUNCE_SECONDS:-5}
|
|
74
37
|
- GITHUB_TOKEN=${GITHUB_TOKEN:-}
|
|
75
|
-
# Route search calls to the shared daemon; fall back to subprocess if unset.
|
|
76
|
-
- QMD_DAEMON_URL=http://qmd-daemon:8181
|
|
77
|
-
depends_on:
|
|
78
|
-
qmd-daemon:
|
|
79
|
-
condition: service_healthy
|
|
80
38
|
networks:
|
|
81
39
|
- horus-net
|
|
82
40
|
restart: unless-stopped
|
|
@@ -91,11 +49,11 @@ services:
|
|
|
91
49
|
test: ["CMD", "curl", "-f", "http://localhost:8100/health"]
|
|
92
50
|
interval: 30s
|
|
93
51
|
timeout: 5s
|
|
94
|
-
start_period:
|
|
52
|
+
start_period: 60s
|
|
95
53
|
retries: 3
|
|
96
54
|
|
|
97
55
|
# ── Vault ──────────────────────────────────────────────────────────────────
|
|
98
|
-
# Knowledge service.
|
|
56
|
+
# Knowledge service. Search over the knowledge-base repo.
|
|
99
57
|
vault:
|
|
100
58
|
image: ghcr.io/arjunkhera/horus/vault:latest
|
|
101
59
|
ports:
|
|
@@ -105,25 +63,17 @@ services:
|
|
|
105
63
|
- ${HORUS_DATA_PATH}/knowledge-base:/data/knowledge-repo:rw
|
|
106
64
|
# Write-path workspace: staging area for draft pages before PR
|
|
107
65
|
- vault-workspace:/data/workspace
|
|
108
|
-
# Shared QMD database + model cache (same volume as qmd-daemon).
|
|
109
|
-
- qmd-daemon-data:/home/appuser/.cache/qmd
|
|
110
66
|
environment:
|
|
111
67
|
- HORUS_RUNTIME=${HORUS_RUNTIME:-docker}
|
|
112
68
|
- KNOWLEDGE_REPO_PATH=/data/knowledge-repo
|
|
113
69
|
- WORKSPACE_PATH=/data/workspace
|
|
114
70
|
- VAULT_KNOWLEDGE_REPO_URL=${VAULT_KNOWLEDGE_REPO_URL:-}
|
|
115
|
-
- QMD_INDEX_NAME=${QMD_INDEX_NAME:-knowledge}
|
|
116
71
|
- SYNC_INTERVAL=${VAULT_SYNC_INTERVAL:-300}
|
|
117
72
|
- VAULT_SYNC_INTERVAL=${VAULT_SYNC_INTERVAL:-300}
|
|
118
73
|
- LOG_LEVEL=${LOG_LEVEL:-info}
|
|
119
74
|
- HOST=0.0.0.0
|
|
120
75
|
- PORT=8000
|
|
121
76
|
- GITHUB_TOKEN=${GITHUB_TOKEN:-}
|
|
122
|
-
# Route search calls to the shared daemon; fall back to subprocess if unset.
|
|
123
|
-
- QMD_DAEMON_URL=http://qmd-daemon:8181
|
|
124
|
-
depends_on:
|
|
125
|
-
qmd-daemon:
|
|
126
|
-
condition: service_healthy
|
|
127
77
|
networks:
|
|
128
78
|
- horus-net
|
|
129
79
|
restart: unless-stopped
|
|
@@ -138,7 +88,7 @@ services:
|
|
|
138
88
|
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
|
139
89
|
interval: 30s
|
|
140
90
|
timeout: 10s
|
|
141
|
-
start_period:
|
|
91
|
+
start_period: 60s
|
|
142
92
|
retries: 3
|
|
143
93
|
|
|
144
94
|
# ── Vault MCP ──────────────────────────────────────────────────────────────
|
|
@@ -236,9 +186,5 @@ networks:
|
|
|
236
186
|
|
|
237
187
|
# ── Volumes ───────────────────────────────────────────────────────────────────
|
|
238
188
|
volumes:
|
|
239
|
-
# Shared QMD daemon database + GGUF model cache.
|
|
240
|
-
# Mounted into qmd-daemon, Anvil, and Vault so all three share one SQLite index.
|
|
241
|
-
# Persists model downloads (~1-2 GB) and index across container rebuilds.
|
|
242
|
-
qmd-daemon-data:
|
|
243
189
|
# Vault write-path staging workspace
|
|
244
190
|
vault-workspace:
|
package/dist/index.js
CHANGED
|
@@ -52,17 +52,19 @@ var DEFAULT_PORTS = {
|
|
|
52
52
|
// internal routing layer
|
|
53
53
|
ui: 8400,
|
|
54
54
|
// horus-ui — user-facing web interface
|
|
55
|
-
forge: 8200
|
|
55
|
+
forge: 8200,
|
|
56
|
+
typesense: 8108
|
|
57
|
+
// Typesense search engine
|
|
56
58
|
};
|
|
57
59
|
var DEFAULT_DATA_DIR = join(homedir(), "Horus", "data");
|
|
58
60
|
var SERVICES = [
|
|
59
|
-
"qmd-daemon",
|
|
60
61
|
"anvil",
|
|
61
62
|
"vault-router",
|
|
62
63
|
// replaces 'vault'
|
|
63
64
|
"vault-mcp",
|
|
64
65
|
"forge",
|
|
65
|
-
"horus-ui"
|
|
66
|
+
"horus-ui",
|
|
67
|
+
"typesense"
|
|
66
68
|
];
|
|
67
69
|
var CONFIG_VERSION = "1.0";
|
|
68
70
|
|
|
@@ -77,10 +79,14 @@ function defaultConfig() {
|
|
|
77
79
|
anvil_notes: "",
|
|
78
80
|
forge_registry: ""
|
|
79
81
|
},
|
|
82
|
+
search: {
|
|
83
|
+
api_key: "horus-local-key"
|
|
84
|
+
},
|
|
80
85
|
vaults: {},
|
|
81
86
|
github_hosts: {},
|
|
82
87
|
host_repos_path: "",
|
|
83
|
-
host_repos_extra_scan_dirs: []
|
|
88
|
+
host_repos_extra_scan_dirs: [],
|
|
89
|
+
enable_ui: true
|
|
84
90
|
};
|
|
85
91
|
}
|
|
86
92
|
function ensureHorusDir() {
|
|
@@ -127,16 +133,21 @@ function buildConfigFromParsed(parsed) {
|
|
|
127
133
|
vault_rest: parsedPorts?.vault_rest ?? defaults.ports.vault_rest,
|
|
128
134
|
vault_mcp: parsedPorts?.vault_mcp ?? defaults.ports.vault_mcp,
|
|
129
135
|
vault_router: parsedPorts?.vault_router ?? defaults.ports.vault_router,
|
|
130
|
-
forge: parsedPorts?.forge ?? defaults.ports.forge
|
|
136
|
+
forge: parsedPorts?.forge ?? defaults.ports.forge,
|
|
137
|
+
typesense: parsedPorts?.typesense ?? defaults.ports.typesense
|
|
131
138
|
},
|
|
132
139
|
repos: {
|
|
133
140
|
anvil_notes: repos?.anvil_notes ?? defaults.repos.anvil_notes,
|
|
134
141
|
forge_registry: repos?.forge_registry ?? defaults.repos.forge_registry
|
|
135
142
|
},
|
|
143
|
+
search: {
|
|
144
|
+
api_key: parsed.search?.api_key ?? defaults.search.api_key
|
|
145
|
+
},
|
|
136
146
|
vaults: parsed.vaults ?? defaults.vaults,
|
|
137
147
|
github_hosts: parsed.github_hosts ?? defaults.github_hosts,
|
|
138
148
|
host_repos_path: parsed.host_repos_path ?? defaults.host_repos_path,
|
|
139
|
-
host_repos_extra_scan_dirs: parsed.host_repos_extra_scan_dirs ?? defaults.host_repos_extra_scan_dirs
|
|
149
|
+
host_repos_extra_scan_dirs: parsed.host_repos_extra_scan_dirs ?? defaults.host_repos_extra_scan_dirs,
|
|
150
|
+
enable_ui: parsed.enable_ui ?? defaults.enable_ui
|
|
140
151
|
};
|
|
141
152
|
}
|
|
142
153
|
function saveConfig(config) {
|
|
@@ -223,6 +234,10 @@ function generateEnv(config) {
|
|
|
223
234
|
`VAULT_MCP_PORT=${config.ports.vault_mcp}`,
|
|
224
235
|
`VAULT_ROUTER_PORT=${config.ports.vault_router}`,
|
|
225
236
|
`FORGE_PORT=${config.ports.forge}`,
|
|
237
|
+
`TYPESENSE_PORT=${config.ports.typesense}`,
|
|
238
|
+
"",
|
|
239
|
+
"# Search",
|
|
240
|
+
`TYPESENSE_API_KEY=${config.search.api_key}`,
|
|
226
241
|
"",
|
|
227
242
|
"# Repository URLs (must be HTTPS \u2014 container services do not have SSH keys)",
|
|
228
243
|
`ANVIL_REPO_URL=${config.repos.anvil_notes}`,
|
|
@@ -246,8 +261,11 @@ var CONFIG_KEYS = [
|
|
|
246
261
|
"port.vault-mcp",
|
|
247
262
|
"port.vault-router",
|
|
248
263
|
"port.forge",
|
|
264
|
+
"port.typesense",
|
|
249
265
|
"repo.anvil-notes",
|
|
250
|
-
"repo.forge-registry"
|
|
266
|
+
"repo.forge-registry",
|
|
267
|
+
"search.api-key",
|
|
268
|
+
"enable-ui"
|
|
251
269
|
];
|
|
252
270
|
function getConfigValue(config, key) {
|
|
253
271
|
switch (key) {
|
|
@@ -269,10 +287,16 @@ function getConfigValue(config, key) {
|
|
|
269
287
|
return String(config.ports.vault_router);
|
|
270
288
|
case "port.forge":
|
|
271
289
|
return String(config.ports.forge);
|
|
290
|
+
case "port.typesense":
|
|
291
|
+
return String(config.ports.typesense);
|
|
272
292
|
case "repo.anvil-notes":
|
|
273
293
|
return config.repos.anvil_notes;
|
|
274
294
|
case "repo.forge-registry":
|
|
275
295
|
return config.repos.forge_registry;
|
|
296
|
+
case "search.api-key":
|
|
297
|
+
return config.search.api_key;
|
|
298
|
+
case "enable-ui":
|
|
299
|
+
return String(config.enable_ui);
|
|
276
300
|
}
|
|
277
301
|
}
|
|
278
302
|
function setConfigValue(config, key, value) {
|
|
@@ -308,12 +332,24 @@ function setConfigValue(config, key, value) {
|
|
|
308
332
|
case "port.forge":
|
|
309
333
|
updated.ports = { ...updated.ports, forge: parseInt(value, 10) };
|
|
310
334
|
break;
|
|
335
|
+
case "port.typesense":
|
|
336
|
+
updated.ports = { ...updated.ports, typesense: parseInt(value, 10) };
|
|
337
|
+
break;
|
|
311
338
|
case "repo.anvil-notes":
|
|
312
339
|
updated.repos = { ...updated.repos, anvil_notes: value };
|
|
313
340
|
break;
|
|
314
341
|
case "repo.forge-registry":
|
|
315
342
|
updated.repos = { ...updated.repos, forge_registry: value };
|
|
316
343
|
break;
|
|
344
|
+
case "search.api-key":
|
|
345
|
+
updated.search = { ...updated.search, api_key: value };
|
|
346
|
+
break;
|
|
347
|
+
case "enable-ui":
|
|
348
|
+
if (value !== "true" && value !== "false") {
|
|
349
|
+
throw new Error(`Invalid value for enable-ui: ${value}. Must be "true" or "false".`);
|
|
350
|
+
}
|
|
351
|
+
updated.enable_ui = value === "true";
|
|
352
|
+
break;
|
|
317
353
|
}
|
|
318
354
|
return updated;
|
|
319
355
|
}
|
|
@@ -546,32 +582,6 @@ function applyPodmanUserOverride(compose) {
|
|
|
546
582
|
'$1\n user: "0:0"'
|
|
547
583
|
);
|
|
548
584
|
}
|
|
549
|
-
var QMD_DAEMON_SERVICE = ` # \u2500\u2500 QMD Daemon \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
550
|
-
# Shared QMD MCP HTTP server. Keeps GGUF models warm in memory so Anvil and
|
|
551
|
-
# Vault pay the model-load cost only once.
|
|
552
|
-
qmd-daemon:
|
|
553
|
-
image: ghcr.io/arjunkhera/horus/qmd-daemon:latest
|
|
554
|
-
environment:
|
|
555
|
-
- QMD_DAEMON_PORT=8181
|
|
556
|
-
- HORUS_RUNTIME=\${HORUS_RUNTIME:-docker}
|
|
557
|
-
volumes:
|
|
558
|
-
- qmd-daemon-data:/home/qmd/.cache/qmd
|
|
559
|
-
networks:
|
|
560
|
-
- horus-net
|
|
561
|
-
restart: unless-stopped
|
|
562
|
-
stop_grace_period: 15s
|
|
563
|
-
deploy:
|
|
564
|
-
resources:
|
|
565
|
-
limits:
|
|
566
|
-
memory: 4g
|
|
567
|
-
reservations:
|
|
568
|
-
memory: 512m
|
|
569
|
-
healthcheck:
|
|
570
|
-
test: ["CMD", "curl", "-f", "http://localhost:8181/health"]
|
|
571
|
-
interval: 30s
|
|
572
|
-
timeout: 10s
|
|
573
|
-
start_period: 600s
|
|
574
|
-
retries: 3`;
|
|
575
585
|
var ANVIL_SERVICE = ` # \u2500\u2500 Anvil \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
576
586
|
# Notes system and MCP server. Indexes markdown files from the Notes repo.
|
|
577
587
|
anvil:
|
|
@@ -580,7 +590,6 @@ var ANVIL_SERVICE = ` # \u2500\u2500 Anvil \u2500\u2500\u2500\u2500\u2500\u2500
|
|
|
580
590
|
- "\${ANVIL_PORT:-8100}:8100"
|
|
581
591
|
volumes:
|
|
582
592
|
- \${HORUS_DATA_PATH}/notes:/data/notes:rw
|
|
583
|
-
- qmd-daemon-data:/home/anvil/.cache/qmd
|
|
584
593
|
environment:
|
|
585
594
|
- HORUS_RUNTIME=\${HORUS_RUNTIME:-docker}
|
|
586
595
|
- ANVIL_TRANSPORT=http
|
|
@@ -588,14 +597,9 @@ var ANVIL_SERVICE = ` # \u2500\u2500 Anvil \u2500\u2500\u2500\u2500\u2500\u2500
|
|
|
588
597
|
- ANVIL_HOST=0.0.0.0
|
|
589
598
|
- ANVIL_NOTES_PATH=/data/notes
|
|
590
599
|
- ANVIL_REPO_URL=\${ANVIL_REPO_URL:-}
|
|
591
|
-
- ANVIL_QMD_COLLECTION=\${ANVIL_QMD_COLLECTION:-anvil}
|
|
592
600
|
- ANVIL_SYNC_INTERVAL=\${ANVIL_SYNC_INTERVAL:-300}
|
|
593
601
|
- ANVIL_DEBOUNCE_SECONDS=\${ANVIL_DEBOUNCE_SECONDS:-5}
|
|
594
602
|
- GITHUB_TOKEN=\${GITHUB_TOKEN:-}
|
|
595
|
-
- QMD_DAEMON_URL=http://qmd-daemon:8181
|
|
596
|
-
depends_on:
|
|
597
|
-
qmd-daemon:
|
|
598
|
-
condition: service_healthy
|
|
599
603
|
networks:
|
|
600
604
|
- horus-net
|
|
601
605
|
restart: unless-stopped
|
|
@@ -610,7 +614,7 @@ var ANVIL_SERVICE = ` # \u2500\u2500 Anvil \u2500\u2500\u2500\u2500\u2500\u2500
|
|
|
610
614
|
test: ["CMD", "curl", "-f", "http://localhost:8100/health"]
|
|
611
615
|
interval: 30s
|
|
612
616
|
timeout: 5s
|
|
613
|
-
start_period:
|
|
617
|
+
start_period: 60s
|
|
614
618
|
retries: 3`;
|
|
615
619
|
var FORGE_SERVICE = ` # \u2500\u2500 Forge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
616
620
|
# Workspace manager and package registry MCP server.
|
|
@@ -660,6 +664,27 @@ var FORGE_SERVICE = ` # \u2500\u2500 Forge \u2500\u2500\u2500\u2500\u2500\u2500
|
|
|
660
664
|
timeout: 5s
|
|
661
665
|
start_period: 60s
|
|
662
666
|
retries: 3`;
|
|
667
|
+
var TYPESENSE_SERVICE = ` # \u2500\u2500 Typesense \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
668
|
+
# Full-text and vector search engine for unified Horus Search.
|
|
669
|
+
typesense:
|
|
670
|
+
image: typesense/typesense:27.1
|
|
671
|
+
ports:
|
|
672
|
+
- "\${TYPESENSE_PORT:-8108}:8108"
|
|
673
|
+
volumes:
|
|
674
|
+
- \${HORUS_DATA_PATH}/typesense-data:/data
|
|
675
|
+
command: >
|
|
676
|
+
--data-dir=/data
|
|
677
|
+
--api-key=\${TYPESENSE_API_KEY:-horus-local-key}
|
|
678
|
+
--enable-cors
|
|
679
|
+
networks:
|
|
680
|
+
- horus-net
|
|
681
|
+
healthcheck:
|
|
682
|
+
test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/localhost/8108'"]
|
|
683
|
+
interval: 10s
|
|
684
|
+
timeout: 5s
|
|
685
|
+
retries: 3
|
|
686
|
+
start_period: 5s
|
|
687
|
+
restart: unless-stopped`;
|
|
663
688
|
var HORUS_UI_SERVICE = ` # \u2500\u2500 Horus UI \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
664
689
|
# Web interface \u2014 React SPA served by Express proxy on port 8400.
|
|
665
690
|
# Proxies /api/anvil, /api/vault, /api/forge to the respective services.
|
|
@@ -695,7 +720,7 @@ var HORUS_UI_SERVICE = ` # \u2500\u2500 Horus UI \u2500\u2500\u2500\u2500\u2500
|
|
|
695
720
|
reservations:
|
|
696
721
|
memory: 64m
|
|
697
722
|
healthcheck:
|
|
698
|
-
test: ["CMD", "
|
|
723
|
+
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8400/api/health"]
|
|
699
724
|
interval: 30s
|
|
700
725
|
timeout: 5s
|
|
701
726
|
start_period: 30s
|
|
@@ -716,13 +741,11 @@ function generateComposeFile(config, runtime) {
|
|
|
716
741
|
volumes:
|
|
717
742
|
- \${HORUS_DATA_PATH}/vaults/${name}:/data/knowledge-repo:rw
|
|
718
743
|
- vault-${name}-workspace:/data/workspace
|
|
719
|
-
- qmd-daemon-data:/home/appuser/.cache/qmd
|
|
720
744
|
environment:
|
|
721
745
|
- HORUS_RUNTIME=\${HORUS_RUNTIME:-docker}
|
|
722
746
|
- KNOWLEDGE_REPO_PATH=/data/knowledge-repo
|
|
723
747
|
- WORKSPACE_PATH=/data/workspace
|
|
724
748
|
- VAULT_KNOWLEDGE_REPO_URL=${vault.repo}
|
|
725
|
-
- QMD_INDEX_NAME=vault-${name}
|
|
726
749
|
- SYNC_INTERVAL=\${VAULT_SYNC_INTERVAL:-300}
|
|
727
750
|
- VAULT_SYNC_INTERVAL=\${VAULT_SYNC_INTERVAL:-300}
|
|
728
751
|
- LOG_LEVEL=\${LOG_LEVEL:-info}
|
|
@@ -730,10 +753,6 @@ function generateComposeFile(config, runtime) {
|
|
|
730
753
|
- PORT=8000
|
|
731
754
|
- GITHUB_TOKEN=${token}
|
|
732
755
|
- GITHUB_API_HOST=${apiHost}
|
|
733
|
-
- QMD_DAEMON_URL=http://qmd-daemon:8181
|
|
734
|
-
depends_on:
|
|
735
|
-
qmd-daemon:
|
|
736
|
-
condition: service_healthy
|
|
737
756
|
networks:
|
|
738
757
|
- horus-net
|
|
739
758
|
restart: unless-stopped
|
|
@@ -747,7 +766,7 @@ function generateComposeFile(config, runtime) {
|
|
|
747
766
|
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
|
748
767
|
interval: 30s
|
|
749
768
|
timeout: 10s
|
|
750
|
-
start_period:
|
|
769
|
+
start_period: 60s
|
|
751
770
|
retries: 3`;
|
|
752
771
|
});
|
|
753
772
|
const defaultVaultEntry = vaultEntries.find(([, v]) => v.default);
|
|
@@ -821,8 +840,6 @@ ${vaultRouterDependsOn}
|
|
|
821
840
|
"",
|
|
822
841
|
"services:",
|
|
823
842
|
"",
|
|
824
|
-
QMD_DAEMON_SERVICE,
|
|
825
|
-
"",
|
|
826
843
|
ANVIL_SERVICE,
|
|
827
844
|
"",
|
|
828
845
|
...vaultServices.map((s) => s + "\n"),
|
|
@@ -832,8 +849,9 @@ ${vaultRouterDependsOn}
|
|
|
832
849
|
"",
|
|
833
850
|
FORGE_SERVICE,
|
|
834
851
|
"",
|
|
835
|
-
|
|
852
|
+
TYPESENSE_SERVICE,
|
|
836
853
|
"",
|
|
854
|
+
...config.enable_ui !== false ? [HORUS_UI_SERVICE, ""] : [],
|
|
837
855
|
"# \u2500\u2500 Networks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
838
856
|
"networks:",
|
|
839
857
|
" horus-net:",
|
|
@@ -841,7 +859,6 @@ ${vaultRouterDependsOn}
|
|
|
841
859
|
"",
|
|
842
860
|
"# \u2500\u2500 Volumes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
843
861
|
"volumes:",
|
|
844
|
-
" qmd-daemon-data:",
|
|
845
862
|
vaultVolumeEntries
|
|
846
863
|
];
|
|
847
864
|
let content = sections.join("\n");
|
|
@@ -1327,7 +1344,8 @@ var setupCommand = new Command2("setup").description("Interactive first-run setu
|
|
|
1327
1344
|
vault_rest: vault_rest ?? DEFAULT_PORTS.vault_rest,
|
|
1328
1345
|
vault_mcp: vault_mcp ?? DEFAULT_PORTS.vault_mcp,
|
|
1329
1346
|
vault_router: vault_router ?? DEFAULT_PORTS.vault_router,
|
|
1330
|
-
forge: forge ?? DEFAULT_PORTS.forge
|
|
1347
|
+
forge: forge ?? DEFAULT_PORTS.forge,
|
|
1348
|
+
typesense: DEFAULT_PORTS.typesense
|
|
1331
1349
|
};
|
|
1332
1350
|
}
|
|
1333
1351
|
console.log("");
|
|
@@ -2316,7 +2334,7 @@ function checkDiskSpace(dataDir) {
|
|
|
2316
2334
|
return {
|
|
2317
2335
|
status: "warn",
|
|
2318
2336
|
label: "Disk space",
|
|
2319
|
-
message: `Disk space low: only ${freeGBStr}GB available (5GB recommended
|
|
2337
|
+
message: `Disk space low: only ${freeGBStr}GB available (5GB recommended)`,
|
|
2320
2338
|
hint: "Free up disk space before running Horus"
|
|
2321
2339
|
};
|
|
2322
2340
|
} catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arkhera30/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "CLI for managing the Horus AI development stack",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"repository": {
|
|
38
38
|
"type": "git",
|
|
39
39
|
"url": "git+https://github.com/Arjunkhera/Horus.git",
|
|
40
|
-
"directory": "cli"
|
|
40
|
+
"directory": "packages/cli"
|
|
41
41
|
},
|
|
42
42
|
"homepage": "https://github.com/Arjunkhera/Horus#readme",
|
|
43
43
|
"bugs": {
|