@arkhera30/cli 0.2.2 → 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.
@@ -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: 600s
52
+ start_period: 60s
95
53
  retries: 3
96
54
 
97
55
  # ── Vault ──────────────────────────────────────────────────────────────────
98
- # Knowledge service. Semantic search over the knowledge-base repo.
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: 600s
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
@@ -48,18 +48,23 @@ var DEFAULT_PORTS = {
48
48
  vault_rest: 8e3,
49
49
  // keep for individual vault instances
50
50
  vault_mcp: 8300,
51
- vault_router: 8400,
52
- // new
53
- forge: 8200
51
+ vault_router: 8050,
52
+ // internal routing layer
53
+ ui: 8400,
54
+ // horus-ui — user-facing web interface
55
+ forge: 8200,
56
+ typesense: 8108
57
+ // Typesense search engine
54
58
  };
55
59
  var DEFAULT_DATA_DIR = join(homedir(), "Horus", "data");
56
60
  var SERVICES = [
57
- "qmd-daemon",
58
61
  "anvil",
59
62
  "vault-router",
60
63
  // replaces 'vault'
61
64
  "vault-mcp",
62
- "forge"
65
+ "forge",
66
+ "horus-ui",
67
+ "typesense"
63
68
  ];
64
69
  var CONFIG_VERSION = "1.0";
65
70
 
@@ -74,10 +79,14 @@ function defaultConfig() {
74
79
  anvil_notes: "",
75
80
  forge_registry: ""
76
81
  },
82
+ search: {
83
+ api_key: "horus-local-key"
84
+ },
77
85
  vaults: {},
78
86
  github_hosts: {},
79
87
  host_repos_path: "",
80
- host_repos_extra_scan_dirs: []
88
+ host_repos_extra_scan_dirs: [],
89
+ enable_ui: true
81
90
  };
82
91
  }
83
92
  function ensureHorusDir() {
@@ -124,16 +133,21 @@ function buildConfigFromParsed(parsed) {
124
133
  vault_rest: parsedPorts?.vault_rest ?? defaults.ports.vault_rest,
125
134
  vault_mcp: parsedPorts?.vault_mcp ?? defaults.ports.vault_mcp,
126
135
  vault_router: parsedPorts?.vault_router ?? defaults.ports.vault_router,
127
- forge: parsedPorts?.forge ?? defaults.ports.forge
136
+ forge: parsedPorts?.forge ?? defaults.ports.forge,
137
+ typesense: parsedPorts?.typesense ?? defaults.ports.typesense
128
138
  },
129
139
  repos: {
130
140
  anvil_notes: repos?.anvil_notes ?? defaults.repos.anvil_notes,
131
141
  forge_registry: repos?.forge_registry ?? defaults.repos.forge_registry
132
142
  },
143
+ search: {
144
+ api_key: parsed.search?.api_key ?? defaults.search.api_key
145
+ },
133
146
  vaults: parsed.vaults ?? defaults.vaults,
134
147
  github_hosts: parsed.github_hosts ?? defaults.github_hosts,
135
148
  host_repos_path: parsed.host_repos_path ?? defaults.host_repos_path,
136
- 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
137
151
  };
138
152
  }
139
153
  function saveConfig(config) {
@@ -220,6 +234,10 @@ function generateEnv(config) {
220
234
  `VAULT_MCP_PORT=${config.ports.vault_mcp}`,
221
235
  `VAULT_ROUTER_PORT=${config.ports.vault_router}`,
222
236
  `FORGE_PORT=${config.ports.forge}`,
237
+ `TYPESENSE_PORT=${config.ports.typesense}`,
238
+ "",
239
+ "# Search",
240
+ `TYPESENSE_API_KEY=${config.search.api_key}`,
223
241
  "",
224
242
  "# Repository URLs (must be HTTPS \u2014 container services do not have SSH keys)",
225
243
  `ANVIL_REPO_URL=${config.repos.anvil_notes}`,
@@ -243,8 +261,11 @@ var CONFIG_KEYS = [
243
261
  "port.vault-mcp",
244
262
  "port.vault-router",
245
263
  "port.forge",
264
+ "port.typesense",
246
265
  "repo.anvil-notes",
247
- "repo.forge-registry"
266
+ "repo.forge-registry",
267
+ "search.api-key",
268
+ "enable-ui"
248
269
  ];
249
270
  function getConfigValue(config, key) {
250
271
  switch (key) {
@@ -266,10 +287,16 @@ function getConfigValue(config, key) {
266
287
  return String(config.ports.vault_router);
267
288
  case "port.forge":
268
289
  return String(config.ports.forge);
290
+ case "port.typesense":
291
+ return String(config.ports.typesense);
269
292
  case "repo.anvil-notes":
270
293
  return config.repos.anvil_notes;
271
294
  case "repo.forge-registry":
272
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);
273
300
  }
274
301
  }
275
302
  function setConfigValue(config, key, value) {
@@ -305,12 +332,24 @@ function setConfigValue(config, key, value) {
305
332
  case "port.forge":
306
333
  updated.ports = { ...updated.ports, forge: parseInt(value, 10) };
307
334
  break;
335
+ case "port.typesense":
336
+ updated.ports = { ...updated.ports, typesense: parseInt(value, 10) };
337
+ break;
308
338
  case "repo.anvil-notes":
309
339
  updated.repos = { ...updated.repos, anvil_notes: value };
310
340
  break;
311
341
  case "repo.forge-registry":
312
342
  updated.repos = { ...updated.repos, forge_registry: value };
313
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;
314
353
  }
315
354
  return updated;
316
355
  }
@@ -543,32 +582,6 @@ function applyPodmanUserOverride(compose) {
543
582
  '$1\n user: "0:0"'
544
583
  );
545
584
  }
546
- 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
547
- # Shared QMD MCP HTTP server. Keeps GGUF models warm in memory so Anvil and
548
- # Vault pay the model-load cost only once.
549
- qmd-daemon:
550
- image: ghcr.io/arjunkhera/horus/qmd-daemon:latest
551
- environment:
552
- - QMD_DAEMON_PORT=8181
553
- - HORUS_RUNTIME=\${HORUS_RUNTIME:-docker}
554
- volumes:
555
- - qmd-daemon-data:/home/qmd/.cache/qmd
556
- networks:
557
- - horus-net
558
- restart: unless-stopped
559
- stop_grace_period: 15s
560
- deploy:
561
- resources:
562
- limits:
563
- memory: 4g
564
- reservations:
565
- memory: 512m
566
- healthcheck:
567
- test: ["CMD", "curl", "-f", "http://localhost:8181/health"]
568
- interval: 30s
569
- timeout: 10s
570
- start_period: 600s
571
- retries: 3`;
572
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
573
586
  # Notes system and MCP server. Indexes markdown files from the Notes repo.
574
587
  anvil:
@@ -577,7 +590,6 @@ var ANVIL_SERVICE = ` # \u2500\u2500 Anvil \u2500\u2500\u2500\u2500\u2500\u2500
577
590
  - "\${ANVIL_PORT:-8100}:8100"
578
591
  volumes:
579
592
  - \${HORUS_DATA_PATH}/notes:/data/notes:rw
580
- - qmd-daemon-data:/home/anvil/.cache/qmd
581
593
  environment:
582
594
  - HORUS_RUNTIME=\${HORUS_RUNTIME:-docker}
583
595
  - ANVIL_TRANSPORT=http
@@ -585,14 +597,9 @@ var ANVIL_SERVICE = ` # \u2500\u2500 Anvil \u2500\u2500\u2500\u2500\u2500\u2500
585
597
  - ANVIL_HOST=0.0.0.0
586
598
  - ANVIL_NOTES_PATH=/data/notes
587
599
  - ANVIL_REPO_URL=\${ANVIL_REPO_URL:-}
588
- - ANVIL_QMD_COLLECTION=\${ANVIL_QMD_COLLECTION:-anvil}
589
600
  - ANVIL_SYNC_INTERVAL=\${ANVIL_SYNC_INTERVAL:-300}
590
601
  - ANVIL_DEBOUNCE_SECONDS=\${ANVIL_DEBOUNCE_SECONDS:-5}
591
602
  - GITHUB_TOKEN=\${GITHUB_TOKEN:-}
592
- - QMD_DAEMON_URL=http://qmd-daemon:8181
593
- depends_on:
594
- qmd-daemon:
595
- condition: service_healthy
596
603
  networks:
597
604
  - horus-net
598
605
  restart: unless-stopped
@@ -607,7 +614,7 @@ var ANVIL_SERVICE = ` # \u2500\u2500 Anvil \u2500\u2500\u2500\u2500\u2500\u2500
607
614
  test: ["CMD", "curl", "-f", "http://localhost:8100/health"]
608
615
  interval: 30s
609
616
  timeout: 5s
610
- start_period: 600s
617
+ start_period: 60s
611
618
  retries: 3`;
612
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
613
620
  # Workspace manager and package registry MCP server.
@@ -657,6 +664,67 @@ var FORGE_SERVICE = ` # \u2500\u2500 Forge \u2500\u2500\u2500\u2500\u2500\u2500
657
664
  timeout: 5s
658
665
  start_period: 60s
659
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`;
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
689
+ # Web interface \u2014 React SPA served by Express proxy on port 8400.
690
+ # Proxies /api/anvil, /api/vault, /api/forge to the respective services.
691
+ # Stores dashboard configs and preferences in _system/ui/ (not indexed by Anvil).
692
+ horus-ui:
693
+ image: ghcr.io/arjunkhera/horus/horus-ui:latest
694
+ ports:
695
+ - "\${UI_PORT:-8400}:8400"
696
+ volumes:
697
+ - \${HORUS_DATA_PATH}/notes:/data/notes:rw
698
+ environment:
699
+ - PORT=8400
700
+ - HORUS_DATA_PATH=/data/notes
701
+ - ANVIL_URL=http://anvil:8100
702
+ - VAULT_URL=http://vault-mcp:8300
703
+ - FORGE_URL=http://forge:8200
704
+ - NODE_ENV=production
705
+ depends_on:
706
+ anvil:
707
+ condition: service_healthy
708
+ vault-mcp:
709
+ condition: service_healthy
710
+ forge:
711
+ condition: service_healthy
712
+ networks:
713
+ - horus-net
714
+ restart: unless-stopped
715
+ stop_grace_period: 10s
716
+ deploy:
717
+ resources:
718
+ limits:
719
+ memory: 256m
720
+ reservations:
721
+ memory: 64m
722
+ healthcheck:
723
+ test: ["CMD", "wget", "--spider", "-q", "http://localhost:8400/api/health"]
724
+ interval: 30s
725
+ timeout: 5s
726
+ start_period: 30s
727
+ retries: 3`;
660
728
  function generateComposeFile(config, runtime) {
661
729
  const vaultEntries = Object.entries(config.vaults).sort(([a], [b]) => a.localeCompare(b));
662
730
  const vaultServices = vaultEntries.map(([name, vault], index) => {
@@ -673,13 +741,11 @@ function generateComposeFile(config, runtime) {
673
741
  volumes:
674
742
  - \${HORUS_DATA_PATH}/vaults/${name}:/data/knowledge-repo:rw
675
743
  - vault-${name}-workspace:/data/workspace
676
- - qmd-daemon-data:/home/appuser/.cache/qmd
677
744
  environment:
678
745
  - HORUS_RUNTIME=\${HORUS_RUNTIME:-docker}
679
746
  - KNOWLEDGE_REPO_PATH=/data/knowledge-repo
680
747
  - WORKSPACE_PATH=/data/workspace
681
748
  - VAULT_KNOWLEDGE_REPO_URL=${vault.repo}
682
- - QMD_INDEX_NAME=vault-${name}
683
749
  - SYNC_INTERVAL=\${VAULT_SYNC_INTERVAL:-300}
684
750
  - VAULT_SYNC_INTERVAL=\${VAULT_SYNC_INTERVAL:-300}
685
751
  - LOG_LEVEL=\${LOG_LEVEL:-info}
@@ -687,10 +753,6 @@ function generateComposeFile(config, runtime) {
687
753
  - PORT=8000
688
754
  - GITHUB_TOKEN=${token}
689
755
  - GITHUB_API_HOST=${apiHost}
690
- - QMD_DAEMON_URL=http://qmd-daemon:8181
691
- depends_on:
692
- qmd-daemon:
693
- condition: service_healthy
694
756
  networks:
695
757
  - horus-net
696
758
  restart: unless-stopped
@@ -704,7 +766,7 @@ function generateComposeFile(config, runtime) {
704
766
  test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
705
767
  interval: 30s
706
768
  timeout: 10s
707
- start_period: 600s
769
+ start_period: 60s
708
770
  retries: 3`;
709
771
  });
710
772
  const defaultVaultEntry = vaultEntries.find(([, v]) => v.default);
@@ -717,7 +779,7 @@ function generateComposeFile(config, runtime) {
717
779
  vault-router:
718
780
  image: ghcr.io/arjunkhera/horus/vault-router:latest
719
781
  ports:
720
- - "\${VAULT_ROUTER_PORT:-8400}:8400"
782
+ - "\${VAULT_ROUTER_PORT:-8050}:8400"
721
783
  environment:
722
784
  - VAULT_ENDPOINTS=${vaultEndpoints}
723
785
  - VAULT_DEFAULT=${defaultVaultName}
@@ -778,8 +840,6 @@ ${vaultRouterDependsOn}
778
840
  "",
779
841
  "services:",
780
842
  "",
781
- QMD_DAEMON_SERVICE,
782
- "",
783
843
  ANVIL_SERVICE,
784
844
  "",
785
845
  ...vaultServices.map((s) => s + "\n"),
@@ -789,6 +849,9 @@ ${vaultRouterDependsOn}
789
849
  "",
790
850
  FORGE_SERVICE,
791
851
  "",
852
+ TYPESENSE_SERVICE,
853
+ "",
854
+ ...config.enable_ui !== false ? [HORUS_UI_SERVICE, ""] : [],
792
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",
793
856
  "networks:",
794
857
  " horus-net:",
@@ -796,7 +859,6 @@ ${vaultRouterDependsOn}
796
859
  "",
797
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",
798
861
  "volumes:",
799
- " qmd-daemon-data:",
800
862
  vaultVolumeEntries
801
863
  ];
802
864
  let content = sections.join("\n");
@@ -1282,7 +1344,8 @@ var setupCommand = new Command2("setup").description("Interactive first-run setu
1282
1344
  vault_rest: vault_rest ?? DEFAULT_PORTS.vault_rest,
1283
1345
  vault_mcp: vault_mcp ?? DEFAULT_PORTS.vault_mcp,
1284
1346
  vault_router: vault_router ?? DEFAULT_PORTS.vault_router,
1285
- forge: forge ?? DEFAULT_PORTS.forge
1347
+ forge: forge ?? DEFAULT_PORTS.forge,
1348
+ typesense: DEFAULT_PORTS.typesense
1286
1349
  };
1287
1350
  }
1288
1351
  console.log("");
@@ -2271,7 +2334,7 @@ function checkDiskSpace(dataDir) {
2271
2334
  return {
2272
2335
  status: "warn",
2273
2336
  label: "Disk space",
2274
- message: `Disk space low: only ${freeGBStr}GB available (5GB recommended; QMD models take ~2GB)`,
2337
+ message: `Disk space low: only ${freeGBStr}GB available (5GB recommended)`,
2275
2338
  hint: "Free up disk space before running Horus"
2276
2339
  };
2277
2340
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkhera30/cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "CLI for managing the Horus AI development stack",
5
5
  "type": "module",
6
6
  "bin": {
@@ -24,6 +24,7 @@
24
24
  "@types/node": "^20.0.0",
25
25
  "tsup": "^8.0.0",
26
26
  "typescript": "^5.4.0",
27
+ "vite": "^6.0.0",
27
28
  "vitest": "^4.0.18"
28
29
  },
29
30
  "engines": {
@@ -36,7 +37,7 @@
36
37
  "repository": {
37
38
  "type": "git",
38
39
  "url": "git+https://github.com/Arjunkhera/Horus.git",
39
- "directory": "cli"
40
+ "directory": "packages/cli"
40
41
  },
41
42
  "homepage": "https://github.com/Arjunkhera/Horus#readme",
42
43
  "bugs": {