@duckmind/deepquark-darwin-arm64 0.9.83 → 0.9.88
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/.deepquark/skills/bundled/knowledge-graph/SKILL.md +385 -0
- package/.deepquark/skills/bundled/knowledge-graph/STANDARDS.md +461 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/cli.ts +588 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/config.ts +630 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/connection-profile.ts +629 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/container.ts +756 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/mcp-client.ts +1310 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/output-formatter.ts +997 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/token-metrics.ts +335 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/transformation-log.ts +137 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/wrapper-config.ts +113 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/.env.example +129 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/compare-embeddings.ts +175 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/config-falkordb.yaml +108 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/config-neo4j.yaml +111 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/diagnose.ts +483 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-falkordb-dev.yml +146 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-falkordb.yml +151 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-neo4j-dev-local.yml +161 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-neo4j-dev.yml +161 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-neo4j.yml +169 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-production.yml +128 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-test.yml +10 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose.yml +84 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/entrypoint.sh +40 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/install.ts +2054 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/podman-compose-falkordb.yml +78 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/podman-compose-neo4j.yml +88 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/podman-compose.yml +83 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-all-llms-mcp.ts +387 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-embedding-models.ts +201 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-embedding-providers.ts +641 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-graphiti-model.ts +217 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-grok-correct.ts +141 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-grok-llms-mcp.ts +386 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-grok-models.ts +173 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-llama-extraction.ts +188 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-mcp-final.ts +240 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-mcp-live.ts +187 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-mcp-session.ts +127 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-model-combinations.ts +316 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-ollama-models.ts +228 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-openrouter-models.ts +460 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-real-life-mcp.ts +311 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-search-debug.ts +199 -0
- package/.deepquark/skills/bundled/knowledge-graph/tools/Install.md +104 -0
- package/.deepquark/skills/bundled/knowledge-graph/tools/README.md +120 -0
- package/.deepquark/skills/bundled/knowledge-graph/tools/knowledge-cli.ts +996 -0
- package/.deepquark/skills/bundled/knowledge-graph/tools/server-cli.ts +531 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/BulkImport.md +514 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/CaptureEpisode.md +242 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/ClearGraph.md +392 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/GetRecent.md +352 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/GetStatus.md +373 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/HealthReport.md +212 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/InvestigateEntity.md +142 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/OntologyManagement.md +201 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/RunMaintenance.md +302 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/SearchByDate.md +255 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/SearchFacts.md +382 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/SearchKnowledge.md +374 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/StixImport.md +212 -0
- package/bin/deepquark +0 -0
- package/package.json +1 -1
- package/.deepquark/skills/bundled/ge-payroll/SKILL.md +0 -153
- package/.deepquark/skills/bundled/ge-payroll/evals/evals.json +0 -23
- package/.deepquark/skills/bundled/ge-payroll/references/pain-points-improvements.md +0 -106
- package/.deepquark/skills/bundled/ge-payroll/references/process-detail.md +0 -217
- package/.deepquark/skills/bundled/ge-payroll/references/raci-stakeholders.md +0 -85
- package/.deepquark/skills/bundled/ge-payroll/references/timeline-mandays.md +0 -64
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Loader Library
|
|
3
|
+
*
|
|
4
|
+
* Handles loading and mapping environment variables for the Madeinoz Knowledge System.
|
|
5
|
+
* Supports MADEINOZ_KNOWLEDGE_* prefixed variables and maps them to standard container env vars.
|
|
6
|
+
*
|
|
7
|
+
* PAI .env is the ONLY source of truth for all configuration:
|
|
8
|
+
* - Uses ${PAI_DIR}/.env if PAI_DIR environment variable is set
|
|
9
|
+
* - Falls back to ~/.claude/.env if PAI_DIR is not set
|
|
10
|
+
*
|
|
11
|
+
* Docker containers read directly from PAI .env via the env_file directive.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Configuration interface
|
|
18
|
+
*/
|
|
19
|
+
export interface KnowledgeConfig {
|
|
20
|
+
// API Keys
|
|
21
|
+
OPENAI_API_KEY?: string;
|
|
22
|
+
ANTHROPIC_API_KEY?: string;
|
|
23
|
+
GOOGLE_API_KEY?: string;
|
|
24
|
+
GROQ_API_KEY?: string;
|
|
25
|
+
VOYAGE_API_KEY?: string;
|
|
26
|
+
|
|
27
|
+
// LLM Provider Configuration
|
|
28
|
+
LLM_PROVIDER: string;
|
|
29
|
+
EMBEDDER_PROVIDER: string;
|
|
30
|
+
MODEL_NAME: string;
|
|
31
|
+
|
|
32
|
+
// Custom Endpoint Configuration
|
|
33
|
+
OPENAI_BASE_URL?: string; // For Ollama LLM: http://host.docker.internal:11434/v1
|
|
34
|
+
EMBEDDER_PROVIDER_URL?: string; // For custom embedder endpoint (Ollama, etc.)
|
|
35
|
+
EMBEDDER_MODEL?: string; // For Ollama: nomic-embed-text
|
|
36
|
+
EMBEDDER_DIMENSIONS?: string; // For embedder: 1024 for mxbai, 1536 for OpenAI
|
|
37
|
+
|
|
38
|
+
// Performance Configuration
|
|
39
|
+
SEMAPHORE_LIMIT: string;
|
|
40
|
+
|
|
41
|
+
// Knowledge Graph Configuration
|
|
42
|
+
GROUP_ID: string;
|
|
43
|
+
|
|
44
|
+
// Database Configuration
|
|
45
|
+
DATABASE_TYPE: string;
|
|
46
|
+
FALKORDB_HOST?: string;
|
|
47
|
+
FALKORDB_PORT?: string;
|
|
48
|
+
FALKORDB_PASSWORD?: string;
|
|
49
|
+
|
|
50
|
+
// Neo4j Configuration (alternative)
|
|
51
|
+
NEO4J_URI?: string;
|
|
52
|
+
NEO4J_USER?: string;
|
|
53
|
+
NEO4J_PASSWORD?: string;
|
|
54
|
+
|
|
55
|
+
// Telemetry
|
|
56
|
+
GRAPHITI_TELEMETRY_ENABLED: string;
|
|
57
|
+
|
|
58
|
+
// Prompt Caching (Gemini)
|
|
59
|
+
PROMPT_CACHE_ENABLED?: string;
|
|
60
|
+
PROMPT_CACHE_METRICS_ENABLED?: string;
|
|
61
|
+
PROMPT_CACHE_LOG_REQUESTS?: string;
|
|
62
|
+
PROMPT_CACHE_TTL?: string;
|
|
63
|
+
METRICS_PORT?: string;
|
|
64
|
+
|
|
65
|
+
// Container Configuration
|
|
66
|
+
NETWORK_NAME: string;
|
|
67
|
+
FALKORDB_CONTAINER: string;
|
|
68
|
+
MCP_CONTAINER: string;
|
|
69
|
+
VOLUME_NAME: string;
|
|
70
|
+
|
|
71
|
+
// Port Configuration
|
|
72
|
+
MCP_SERVER_PORT: string;
|
|
73
|
+
FALKORDB_UI_PORT: string;
|
|
74
|
+
|
|
75
|
+
// Original MADEINOZ_KNOWLEDGE_* prefixed values (for reference)
|
|
76
|
+
PAI_PREFIXES?: Record<string, string | undefined>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Default configuration values
|
|
81
|
+
*/
|
|
82
|
+
const DEFAULTS: Record<string, string> = {
|
|
83
|
+
LLM_PROVIDER: 'ollama',
|
|
84
|
+
EMBEDDER_PROVIDER: 'ollama',
|
|
85
|
+
MODEL_NAME: 'llama3.2',
|
|
86
|
+
OPENAI_BASE_URL: 'http://host.docker.internal:11434/v1', // Ollama LLM default (Docker)
|
|
87
|
+
EMBEDDER_PROVIDER_URL: 'http://host.containers.internal:11434', // Embedder endpoint (Ollama, etc.)
|
|
88
|
+
EMBEDDER_MODEL: 'nomic-embed-text', // Ollama embedding model
|
|
89
|
+
EMBEDDER_DIMENSIONS: '512', // nomic-embed-text dimensions
|
|
90
|
+
SEMAPHORE_LIMIT: '10',
|
|
91
|
+
GROUP_ID: 'main',
|
|
92
|
+
DATABASE_TYPE: 'neo4j',
|
|
93
|
+
GRAPHITI_TELEMETRY_ENABLED: 'false',
|
|
94
|
+
NETWORK_NAME: 'madeinoz-knowledge-net',
|
|
95
|
+
FALKORDB_CONTAINER: 'madeinoz-knowledge-falkordb',
|
|
96
|
+
MCP_CONTAINER: 'madeinoz-knowledge-graph-mcp',
|
|
97
|
+
VOLUME_NAME: 'madeinoz-knowledge-falkordb-data',
|
|
98
|
+
MCP_SERVER_PORT: '8000',
|
|
99
|
+
FALKORDB_UI_PORT: '3000',
|
|
100
|
+
FALKORDB_HOST: 'madeinoz-knowledge-falkordb',
|
|
101
|
+
FALKORDB_PORT: '6379',
|
|
102
|
+
NEO4J_URI: 'bolt://localhost:7687',
|
|
103
|
+
NEO4J_USER: 'neo4j',
|
|
104
|
+
NEO4J_PASSWORD: 'demodemo',
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Configuration Loader class
|
|
109
|
+
*
|
|
110
|
+
* PAI .env is the ONLY source of truth for all configuration.
|
|
111
|
+
* Uses ${PAI_DIR}/.env if PAI_DIR is set, otherwise ~/.claude/.env
|
|
112
|
+
*/
|
|
113
|
+
export class ConfigLoader {
|
|
114
|
+
private packRoot: string;
|
|
115
|
+
private envFile: string;
|
|
116
|
+
|
|
117
|
+
constructor(packRoot?: string) {
|
|
118
|
+
// If packRoot not provided, navigate up from src/server/lib to pack root
|
|
119
|
+
this.packRoot = packRoot || join(import.meta.dir, '../../../');
|
|
120
|
+
|
|
121
|
+
// PAI .env is the ONLY source of truth
|
|
122
|
+
// Priority: PAI_DIR/.env > ~/.claude/.env
|
|
123
|
+
const homeDir = process.env.HOME || '';
|
|
124
|
+
this.envFile = process.env.PAI_DIR
|
|
125
|
+
? join(process.env.PAI_DIR, '.env')
|
|
126
|
+
: join(homeDir, '.claude', '.env');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get the pack root directory
|
|
131
|
+
*/
|
|
132
|
+
getPackRoot(): string {
|
|
133
|
+
return this.packRoot;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get the PAI .env file path
|
|
138
|
+
*/
|
|
139
|
+
getEnvFile(): string {
|
|
140
|
+
return this.envFile;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Check if .env file exists
|
|
145
|
+
*/
|
|
146
|
+
async envExists(): Promise<boolean> {
|
|
147
|
+
const file = Bun.file(this.envFile);
|
|
148
|
+
return file.exists();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Load environment variables from PAI .env file using Bun
|
|
153
|
+
* PAI .env (${PAI_DIR}/.env or ~/.claude/.env) is the ONLY source of truth
|
|
154
|
+
*/
|
|
155
|
+
async loadEnv(): Promise<Record<string, string>> {
|
|
156
|
+
const env: Record<string, string> = {};
|
|
157
|
+
|
|
158
|
+
// Copy process.env (filtering out undefined values)
|
|
159
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
160
|
+
if (value !== undefined) {
|
|
161
|
+
env[key] = value;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Load from PAI .env (the ONLY source of truth)
|
|
166
|
+
if (await this.envExists()) {
|
|
167
|
+
const file = Bun.file(this.envFile);
|
|
168
|
+
const content = await file.text();
|
|
169
|
+
this.parseEnvFile(content, env);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return env;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Parse .env file content
|
|
177
|
+
*/
|
|
178
|
+
private parseEnvFile(content: string, env: Record<string, string>): void {
|
|
179
|
+
const lines = content.split('\n');
|
|
180
|
+
|
|
181
|
+
for (const line of lines) {
|
|
182
|
+
const trimmed = line.trim();
|
|
183
|
+
|
|
184
|
+
// Skip empty lines and comments
|
|
185
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Parse KEY=VALUE
|
|
190
|
+
const eqIndex = trimmed.indexOf('=');
|
|
191
|
+
if (eqIndex > 0) {
|
|
192
|
+
const key = trimmed.substring(0, eqIndex).trim();
|
|
193
|
+
const value = trimmed.substring(eqIndex + 1).trim();
|
|
194
|
+
|
|
195
|
+
// Remove quotes if present
|
|
196
|
+
const unquoted =
|
|
197
|
+
(value.startsWith('"') && value.endsWith('"')) ||
|
|
198
|
+
(value.startsWith("'") && value.endsWith("'"))
|
|
199
|
+
? value.slice(1, -1)
|
|
200
|
+
: value;
|
|
201
|
+
|
|
202
|
+
env[key] = unquoted;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Map MADEINOZ_KNOWLEDGE_* prefixed variables to standard names
|
|
209
|
+
* MADEINOZ_KNOWLEDGE_* variables take PRECEDENCE over unprefixed variables
|
|
210
|
+
*/
|
|
211
|
+
private mapPrefixes(env: Record<string, string>): {
|
|
212
|
+
mapped: Record<string, string>;
|
|
213
|
+
originals: Record<string, string | undefined>;
|
|
214
|
+
} {
|
|
215
|
+
const mapped: Record<string, string> = { ...env };
|
|
216
|
+
const originals: Record<string, string | undefined> = {};
|
|
217
|
+
|
|
218
|
+
// Mapping of MADEINOZ_KNOWLEDGE_* -> standard variable
|
|
219
|
+
const mappings: Record<string, string> = {
|
|
220
|
+
// API Keys
|
|
221
|
+
MADEINOZ_KNOWLEDGE_OPENAI_API_KEY: 'OPENAI_API_KEY',
|
|
222
|
+
MADEINOZ_KNOWLEDGE_ANTHROPIC_API_KEY: 'ANTHROPIC_API_KEY',
|
|
223
|
+
MADEINOZ_KNOWLEDGE_GOOGLE_API_KEY: 'GOOGLE_API_KEY',
|
|
224
|
+
MADEINOZ_KNOWLEDGE_GROQ_API_KEY: 'GROQ_API_KEY',
|
|
225
|
+
MADEINOZ_KNOWLEDGE_VOYAGE_API_KEY: 'VOYAGE_API_KEY',
|
|
226
|
+
// LLM Configuration
|
|
227
|
+
MADEINOZ_KNOWLEDGE_LLM_PROVIDER: 'LLM_PROVIDER',
|
|
228
|
+
MADEINOZ_KNOWLEDGE_EMBEDDER_PROVIDER: 'EMBEDDER_PROVIDER',
|
|
229
|
+
MADEINOZ_KNOWLEDGE_MODEL_NAME: 'MODEL_NAME',
|
|
230
|
+
// Custom Endpoint Configuration
|
|
231
|
+
MADEINOZ_KNOWLEDGE_OPENAI_BASE_URL: 'OPENAI_BASE_URL',
|
|
232
|
+
MADEINOZ_KNOWLEDGE_EMBEDDER_PROVIDER_URL: 'EMBEDDER_PROVIDER_URL',
|
|
233
|
+
MADEINOZ_KNOWLEDGE_EMBEDDER_MODEL: 'EMBEDDER_MODEL',
|
|
234
|
+
MADEINOZ_KNOWLEDGE_EMBEDDER_DIMENSIONS: 'EMBEDDER_DIMENSIONS',
|
|
235
|
+
// Performance
|
|
236
|
+
MADEINOZ_KNOWLEDGE_SEMAPHORE_LIMIT: 'SEMAPHORE_LIMIT',
|
|
237
|
+
// Knowledge Graph
|
|
238
|
+
MADEINOZ_KNOWLEDGE_GROUP_ID: 'GROUP_ID',
|
|
239
|
+
MADEINOZ_KNOWLEDGE_DATABASE_TYPE: 'DATABASE_TYPE',
|
|
240
|
+
MADEINOZ_KNOWLEDGE_GRAPHITI_TELEMETRY_ENABLED: 'GRAPHITI_TELEMETRY_ENABLED',
|
|
241
|
+
// FalkorDB
|
|
242
|
+
MADEINOZ_KNOWLEDGE_FALKORDB_HOST: 'FALKORDB_HOST',
|
|
243
|
+
MADEINOZ_KNOWLEDGE_FALKORDB_PORT: 'FALKORDB_PORT',
|
|
244
|
+
MADEINOZ_KNOWLEDGE_FALKORDB_PASSWORD: 'FALKORDB_PASSWORD',
|
|
245
|
+
// Neo4j
|
|
246
|
+
MADEINOZ_KNOWLEDGE_NEO4J_URI: 'NEO4J_URI',
|
|
247
|
+
MADEINOZ_KNOWLEDGE_NEO4J_USER: 'NEO4J_USER',
|
|
248
|
+
MADEINOZ_KNOWLEDGE_NEO4J_PASSWORD: 'NEO4J_PASSWORD',
|
|
249
|
+
MADEINOZ_KNOWLEDGE_NEO4J_DATABASE: 'NEO4J_DATABASE',
|
|
250
|
+
// Prompt Caching
|
|
251
|
+
MADEINOZ_KNOWLEDGE_PROMPT_CACHE_ENABLED: 'PROMPT_CACHE_ENABLED',
|
|
252
|
+
MADEINOZ_KNOWLEDGE_PROMPT_CACHE_METRICS_ENABLED: 'PROMPT_CACHE_METRICS_ENABLED',
|
|
253
|
+
MADEINOZ_KNOWLEDGE_PROMPT_CACHE_LOG_REQUESTS: 'PROMPT_CACHE_LOG_REQUESTS',
|
|
254
|
+
MADEINOZ_KNOWLEDGE_PROMPT_CACHE_TTL: 'PROMPT_CACHE_TTL',
|
|
255
|
+
MADEINOZ_KNOWLEDGE_METRICS_PORT: 'METRICS_PORT',
|
|
256
|
+
// Remote MCP Access (Feature 010)
|
|
257
|
+
MADEINOZ_KNOWLEDGE_PROFILE: 'KNOWLEDGE_PROFILE',
|
|
258
|
+
MADEINOZ_KNOWLEDGE_HOST: 'KNOWLEDGE_HOST',
|
|
259
|
+
MADEINOZ_KNOWLEDGE_PORT: 'KNOWLEDGE_PORT',
|
|
260
|
+
MADEINOZ_KNOWLEDGE_PROTOCOL: 'KNOWLEDGE_PROTOCOL',
|
|
261
|
+
MADEINOZ_KNOWLEDGE_BASE_PATH: 'KNOWLEDGE_BASE_PATH',
|
|
262
|
+
MADEINOZ_KNOWLEDGE_TLS_VERIFY: 'KNOWLEDGE_TLS_VERIFY',
|
|
263
|
+
MADEINOZ_KNOWLEDGE_TLS_CA: 'KNOWLEDGE_TLS_CA',
|
|
264
|
+
MADEINOZ_KNOWLEDGE_TLS_CERT: 'KNOWLEDGE_TLS_CERT',
|
|
265
|
+
MADEINOZ_KNOWLEDGE_TLS_KEY: 'KNOWLEDGE_TLS_KEY',
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// Apply mappings - MADEINOZ_KNOWLEDGE_* takes PRECEDENCE over unprefixed variables
|
|
269
|
+
for (const [paiVar, standardVar] of Object.entries(mappings)) {
|
|
270
|
+
const paiValue = env[paiVar];
|
|
271
|
+
if (paiValue) {
|
|
272
|
+
// Store original for reference
|
|
273
|
+
originals[paiVar] = paiValue;
|
|
274
|
+
|
|
275
|
+
// ALWAYS use MADEINOZ_KNOWLEDGE_* value, overriding any unprefixed variable
|
|
276
|
+
// This ensures prefixed vars take precedence as the primary configuration
|
|
277
|
+
mapped[standardVar] = paiValue;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return { mapped, originals };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Get configuration value with fallback to default
|
|
286
|
+
*/
|
|
287
|
+
private getEnvValue(env: Record<string, string>, key: string, defaultValue?: string): string {
|
|
288
|
+
const value = env[key];
|
|
289
|
+
if (value) {
|
|
290
|
+
return value;
|
|
291
|
+
}
|
|
292
|
+
if (defaultValue !== undefined) {
|
|
293
|
+
return defaultValue;
|
|
294
|
+
}
|
|
295
|
+
// Return from defaults
|
|
296
|
+
return DEFAULTS[key] || '';
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Load and validate configuration
|
|
301
|
+
*/
|
|
302
|
+
async load(): Promise<KnowledgeConfig> {
|
|
303
|
+
// Load .env file
|
|
304
|
+
const env = await this.loadEnv();
|
|
305
|
+
|
|
306
|
+
// Map MADEINOZ_KNOWLEDGE_* prefixes
|
|
307
|
+
const { mapped, originals } = this.mapPrefixes(env);
|
|
308
|
+
|
|
309
|
+
// Build configuration object
|
|
310
|
+
const config: KnowledgeConfig = {
|
|
311
|
+
// API Keys
|
|
312
|
+
OPENAI_API_KEY: this.getEnvValue(mapped, 'OPENAI_API_KEY'),
|
|
313
|
+
ANTHROPIC_API_KEY: this.getEnvValue(mapped, 'ANTHROPIC_API_KEY'),
|
|
314
|
+
GOOGLE_API_KEY: this.getEnvValue(mapped, 'GOOGLE_API_KEY'),
|
|
315
|
+
GROQ_API_KEY: this.getEnvValue(mapped, 'GROQ_API_KEY'),
|
|
316
|
+
VOYAGE_API_KEY: this.getEnvValue(mapped, 'VOYAGE_API_KEY'),
|
|
317
|
+
|
|
318
|
+
// LLM Provider Configuration
|
|
319
|
+
LLM_PROVIDER: this.getEnvValue(mapped, 'LLM_PROVIDER', DEFAULTS.LLM_PROVIDER),
|
|
320
|
+
EMBEDDER_PROVIDER: this.getEnvValue(mapped, 'EMBEDDER_PROVIDER', DEFAULTS.EMBEDDER_PROVIDER),
|
|
321
|
+
MODEL_NAME: this.getEnvValue(mapped, 'MODEL_NAME', DEFAULTS.MODEL_NAME),
|
|
322
|
+
|
|
323
|
+
// Custom Endpoint Configuration
|
|
324
|
+
OPENAI_BASE_URL: this.getEnvValue(mapped, 'OPENAI_BASE_URL', ''),
|
|
325
|
+
EMBEDDER_PROVIDER_URL: this.getEnvValue(mapped, 'EMBEDDER_PROVIDER_URL', ''),
|
|
326
|
+
EMBEDDER_MODEL: this.getEnvValue(mapped, 'EMBEDDER_MODEL', ''),
|
|
327
|
+
EMBEDDER_DIMENSIONS: this.getEnvValue(mapped, 'EMBEDDER_DIMENSIONS', ''),
|
|
328
|
+
|
|
329
|
+
// Performance Configuration
|
|
330
|
+
SEMAPHORE_LIMIT: this.getEnvValue(mapped, 'SEMAPHORE_LIMIT', DEFAULTS.SEMAPHORE_LIMIT),
|
|
331
|
+
|
|
332
|
+
// Knowledge Graph Configuration
|
|
333
|
+
GROUP_ID: this.getEnvValue(mapped, 'GROUP_ID', DEFAULTS.GROUP_ID),
|
|
334
|
+
|
|
335
|
+
// Database Configuration
|
|
336
|
+
DATABASE_TYPE: this.getEnvValue(mapped, 'DATABASE_TYPE', DEFAULTS.DATABASE_TYPE),
|
|
337
|
+
FALKORDB_HOST: this.getEnvValue(mapped, 'FALKORDB_HOST', DEFAULTS.FALKORDB_HOST),
|
|
338
|
+
FALKORDB_PORT: this.getEnvValue(mapped, 'FALKORDB_PORT', DEFAULTS.FALKORDB_PORT),
|
|
339
|
+
FALKORDB_PASSWORD: this.getEnvValue(mapped, 'FALKORDB_PASSWORD', ''),
|
|
340
|
+
|
|
341
|
+
// Neo4j Configuration
|
|
342
|
+
NEO4J_URI: this.getEnvValue(mapped, 'NEO4J_URI', DEFAULTS.NEO4J_URI),
|
|
343
|
+
NEO4J_USER: this.getEnvValue(mapped, 'NEO4J_USER', DEFAULTS.NEO4J_USER),
|
|
344
|
+
NEO4J_PASSWORD: this.getEnvValue(mapped, 'NEO4J_PASSWORD', DEFAULTS.NEO4J_PASSWORD),
|
|
345
|
+
|
|
346
|
+
// Telemetry
|
|
347
|
+
GRAPHITI_TELEMETRY_ENABLED: this.getEnvValue(
|
|
348
|
+
mapped,
|
|
349
|
+
'GRAPHITI_TELEMETRY_ENABLED',
|
|
350
|
+
DEFAULTS.GRAPHITI_TELEMETRY_ENABLED
|
|
351
|
+
),
|
|
352
|
+
|
|
353
|
+
// Prompt Caching (Gemini)
|
|
354
|
+
PROMPT_CACHE_ENABLED: this.getEnvValue(mapped, 'PROMPT_CACHE_ENABLED', ''),
|
|
355
|
+
PROMPT_CACHE_METRICS_ENABLED: this.getEnvValue(mapped, 'PROMPT_CACHE_METRICS_ENABLED', ''),
|
|
356
|
+
PROMPT_CACHE_LOG_REQUESTS: this.getEnvValue(mapped, 'PROMPT_CACHE_LOG_REQUESTS', ''),
|
|
357
|
+
PROMPT_CACHE_TTL: this.getEnvValue(mapped, 'PROMPT_CACHE_TTL', ''),
|
|
358
|
+
METRICS_PORT: this.getEnvValue(mapped, 'METRICS_PORT', ''),
|
|
359
|
+
|
|
360
|
+
// Container Configuration
|
|
361
|
+
NETWORK_NAME: this.getEnvValue(mapped, 'NETWORK_NAME', DEFAULTS.NETWORK_NAME),
|
|
362
|
+
FALKORDB_CONTAINER: this.getEnvValue(
|
|
363
|
+
mapped,
|
|
364
|
+
'FALKORDB_CONTAINER',
|
|
365
|
+
DEFAULTS.FALKORDB_CONTAINER
|
|
366
|
+
),
|
|
367
|
+
MCP_CONTAINER: this.getEnvValue(mapped, 'MCP_CONTAINER', DEFAULTS.MCP_CONTAINER),
|
|
368
|
+
VOLUME_NAME: this.getEnvValue(mapped, 'VOLUME_NAME', DEFAULTS.VOLUME_NAME),
|
|
369
|
+
|
|
370
|
+
// Port Configuration
|
|
371
|
+
MCP_SERVER_PORT: this.getEnvValue(mapped, 'MCP_SERVER_PORT', DEFAULTS.MCP_SERVER_PORT),
|
|
372
|
+
FALKORDB_UI_PORT: this.getEnvValue(mapped, 'FALKORDB_UI_PORT', DEFAULTS.FALKORDB_UI_PORT),
|
|
373
|
+
|
|
374
|
+
// Store original MADEINOZ_KNOWLEDGE_* values
|
|
375
|
+
PAI_PREFIXES: originals,
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
return config;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Validate that required configuration is present
|
|
383
|
+
*/
|
|
384
|
+
validate(config: KnowledgeConfig): { valid: boolean; errors: string[] } {
|
|
385
|
+
const errors: string[] = [];
|
|
386
|
+
|
|
387
|
+
// Check that at least one API key is configured (not required for Ollama)
|
|
388
|
+
const isOllama = config.LLM_PROVIDER === 'ollama';
|
|
389
|
+
const hasAnyKey =
|
|
390
|
+
!!config.OPENAI_API_KEY ||
|
|
391
|
+
!!config.ANTHROPIC_API_KEY ||
|
|
392
|
+
!!config.GOOGLE_API_KEY ||
|
|
393
|
+
!!config.GROQ_API_KEY;
|
|
394
|
+
|
|
395
|
+
if (!hasAnyKey && !isOllama) {
|
|
396
|
+
errors.push('No LLM API key configured (need OPENAI_API_KEY or alternative, or use Ollama)');
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Validate LLM provider
|
|
400
|
+
const validProviders = ['openai', 'anthropic', 'gemini', 'groq', 'ollama'];
|
|
401
|
+
if (!validProviders.includes(config.LLM_PROVIDER)) {
|
|
402
|
+
errors.push(`Invalid LLM_PROVIDER: ${config.LLM_PROVIDER}`);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Validate Ollama configuration
|
|
406
|
+
if (isOllama && !config.OPENAI_BASE_URL) {
|
|
407
|
+
errors.push(
|
|
408
|
+
'OPENAI_BASE_URL required for Ollama (e.g., http://host.docker.internal:11434/v1)'
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Validate database type
|
|
413
|
+
const validDatabases = ['falkordb', 'neo4j'];
|
|
414
|
+
if (!validDatabases.includes(config.DATABASE_TYPE)) {
|
|
415
|
+
errors.push(`Invalid DATABASE_TYPE: ${config.DATABASE_TYPE}`);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Validate semaphore limit is a number
|
|
419
|
+
const semaphoreLimit = Number.parseInt(config.SEMAPHORE_LIMIT, 10);
|
|
420
|
+
if (Number.isNaN(semaphoreLimit) || semaphoreLimit < 1) {
|
|
421
|
+
errors.push(`Invalid SEMAPHORE_LIMIT: ${config.SEMAPHORE_LIMIT}`);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return {
|
|
425
|
+
valid: errors.length === 0,
|
|
426
|
+
errors,
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Get configuration for container environment variables
|
|
432
|
+
* Maps config to container-friendly env var names
|
|
433
|
+
*/
|
|
434
|
+
getContainerEnv(config: KnowledgeConfig): Record<string, string> {
|
|
435
|
+
const env: Record<string, string> = {
|
|
436
|
+
OPENAI_API_KEY: config.OPENAI_API_KEY || '',
|
|
437
|
+
ANTHROPIC_API_KEY: config.ANTHROPIC_API_KEY || '',
|
|
438
|
+
GOOGLE_API_KEY: config.GOOGLE_API_KEY || '',
|
|
439
|
+
GROQ_API_KEY: config.GROQ_API_KEY || '',
|
|
440
|
+
VOYAGE_API_KEY: config.VOYAGE_API_KEY || '',
|
|
441
|
+
DATABASE_TYPE: config.DATABASE_TYPE,
|
|
442
|
+
FALKORDB_HOST: config.FALKORDB_HOST || config.FALKORDB_CONTAINER,
|
|
443
|
+
FALKORDB_PORT: config.FALKORDB_PORT || '6379',
|
|
444
|
+
FALKORDB_PASSWORD: config.FALKORDB_PASSWORD || '',
|
|
445
|
+
// For containers, always use container hostname 'neo4j' not 'localhost'
|
|
446
|
+
NEO4J_URI: 'bolt://neo4j:7687',
|
|
447
|
+
NEO4J_USER: config.NEO4J_USER || 'neo4j',
|
|
448
|
+
NEO4J_PASSWORD: config.NEO4J_PASSWORD || 'demodemo',
|
|
449
|
+
SEMAPHORE_LIMIT: config.SEMAPHORE_LIMIT,
|
|
450
|
+
GRAPHITI_TELEMETRY_ENABLED: config.GRAPHITI_TELEMETRY_ENABLED,
|
|
451
|
+
MODEL_NAME: config.MODEL_NAME,
|
|
452
|
+
LLM_PROVIDER: config.LLM_PROVIDER,
|
|
453
|
+
EMBEDDER_PROVIDER: config.EMBEDDER_PROVIDER,
|
|
454
|
+
EMBEDDER_MODEL: config.EMBEDDER_MODEL || '',
|
|
455
|
+
EMBEDDER_DIMENSIONS: config.EMBEDDER_DIMENSIONS || '',
|
|
456
|
+
EMBEDDER_PROVIDER_URL: config.EMBEDDER_PROVIDER_URL || '',
|
|
457
|
+
GROUP_ID: config.GROUP_ID,
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// LLM provider configuration
|
|
461
|
+
// For Ollama LLM: Use "openai" as provider with custom base URL (OpenAI-compatible API)
|
|
462
|
+
const isOllamaLLM = config.LLM_PROVIDER === 'ollama';
|
|
463
|
+
if (isOllamaLLM) {
|
|
464
|
+
env.LLM_PROVIDER = 'openai';
|
|
465
|
+
env.OPENAI_API_KEY = config.OPENAI_API_KEY || 'ollama'; // Ollama doesn't need a real key
|
|
466
|
+
env.OPENAI_BASE_URL = config.OPENAI_BASE_URL || DEFAULTS.OPENAI_BASE_URL;
|
|
467
|
+
} else if (config.OPENAI_BASE_URL) {
|
|
468
|
+
// Custom OpenAI endpoint (e.g., Azure, local proxy)
|
|
469
|
+
env.OPENAI_BASE_URL = config.OPENAI_BASE_URL;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Embedder provider configuration (independent from LLM provider)
|
|
473
|
+
const isOllamaEmbedder = config.EMBEDDER_PROVIDER === 'ollama';
|
|
474
|
+
if (isOllamaEmbedder) {
|
|
475
|
+
// Ollama embedder uses native 'ollama' provider in Graphiti
|
|
476
|
+
env.EMBEDDER_PROVIDER = 'ollama';
|
|
477
|
+
env.EMBEDDER_PROVIDER_URL = config.EMBEDDER_PROVIDER_URL || DEFAULTS.EMBEDDER_PROVIDER_URL;
|
|
478
|
+
env.EMBEDDER_MODEL = config.EMBEDDER_MODEL || DEFAULTS.EMBEDDER_MODEL;
|
|
479
|
+
env.EMBEDDER_DIMENSIONS = config.EMBEDDER_DIMENSIONS || DEFAULTS.EMBEDDER_DIMENSIONS;
|
|
480
|
+
} else if (config.EMBEDDER_MODEL) {
|
|
481
|
+
env.EMBEDDER_MODEL = config.EMBEDDER_MODEL;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Prompt Caching (Gemini)
|
|
485
|
+
if (config.PROMPT_CACHE_ENABLED) {
|
|
486
|
+
env.PROMPT_CACHE_ENABLED = config.PROMPT_CACHE_ENABLED;
|
|
487
|
+
}
|
|
488
|
+
if (config.PROMPT_CACHE_METRICS_ENABLED) {
|
|
489
|
+
env.PROMPT_CACHE_METRICS_ENABLED = config.PROMPT_CACHE_METRICS_ENABLED;
|
|
490
|
+
}
|
|
491
|
+
if (config.PROMPT_CACHE_LOG_REQUESTS) {
|
|
492
|
+
env.PROMPT_CACHE_LOG_REQUESTS = config.PROMPT_CACHE_LOG_REQUESTS;
|
|
493
|
+
}
|
|
494
|
+
if (config.PROMPT_CACHE_TTL) {
|
|
495
|
+
env.PROMPT_CACHE_TTL = config.PROMPT_CACHE_TTL;
|
|
496
|
+
}
|
|
497
|
+
if (config.METRICS_PORT) {
|
|
498
|
+
env.METRICS_PORT = config.METRICS_PORT;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
return env;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Save configuration to PAI .env file
|
|
506
|
+
* Writes to ${PAI_DIR}/.env or ~/.claude/.env (the ONLY source of truth)
|
|
507
|
+
*/
|
|
508
|
+
async save(config: Partial<KnowledgeConfig>): Promise<void> {
|
|
509
|
+
// Build new content for PAI .env
|
|
510
|
+
let newContent = '# Madeinoz Knowledge System Configuration\n';
|
|
511
|
+
newContent += `# Location: ${this.envFile}\n`;
|
|
512
|
+
newContent += `# Generated: ${new Date().toISOString()}\n`;
|
|
513
|
+
newContent += '\n';
|
|
514
|
+
|
|
515
|
+
// Add API Keys (all use MADEINOZ_KNOWLEDGE_* prefix)
|
|
516
|
+
if (config.OPENAI_API_KEY) {
|
|
517
|
+
newContent += `MADEINOZ_KNOWLEDGE_OPENAI_API_KEY=${config.OPENAI_API_KEY}\n`;
|
|
518
|
+
}
|
|
519
|
+
if (config.ANTHROPIC_API_KEY) {
|
|
520
|
+
newContent += `MADEINOZ_KNOWLEDGE_ANTHROPIC_API_KEY=${config.ANTHROPIC_API_KEY}\n`;
|
|
521
|
+
}
|
|
522
|
+
if (config.GOOGLE_API_KEY) {
|
|
523
|
+
newContent += `MADEINOZ_KNOWLEDGE_GOOGLE_API_KEY=${config.GOOGLE_API_KEY}\n`;
|
|
524
|
+
}
|
|
525
|
+
if (config.GROQ_API_KEY) {
|
|
526
|
+
newContent += `MADEINOZ_KNOWLEDGE_GROQ_API_KEY=${config.GROQ_API_KEY}\n`;
|
|
527
|
+
}
|
|
528
|
+
if (config.VOYAGE_API_KEY) {
|
|
529
|
+
newContent += `MADEINOZ_KNOWLEDGE_VOYAGE_API_KEY=${config.VOYAGE_API_KEY}\n`;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
newContent += '\n';
|
|
533
|
+
|
|
534
|
+
// Add LLM Configuration
|
|
535
|
+
if (config.LLM_PROVIDER) {
|
|
536
|
+
newContent += `MADEINOZ_KNOWLEDGE_LLM_PROVIDER=${config.LLM_PROVIDER}\n`;
|
|
537
|
+
}
|
|
538
|
+
if (config.EMBEDDER_PROVIDER) {
|
|
539
|
+
newContent += `MADEINOZ_KNOWLEDGE_EMBEDDER_PROVIDER=${config.EMBEDDER_PROVIDER}\n`;
|
|
540
|
+
}
|
|
541
|
+
if (config.MODEL_NAME) {
|
|
542
|
+
newContent += `MADEINOZ_KNOWLEDGE_MODEL_NAME=${config.MODEL_NAME}\n`;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
newContent += '\n';
|
|
546
|
+
|
|
547
|
+
// Add Ollama/Custom Endpoint Configuration
|
|
548
|
+
if (config.OPENAI_BASE_URL) {
|
|
549
|
+
newContent += '# Ollama/Custom Endpoint (for OpenAI-compatible APIs)\n';
|
|
550
|
+
newContent += `MADEINOZ_KNOWLEDGE_OPENAI_BASE_URL=${config.OPENAI_BASE_URL}\n`;
|
|
551
|
+
}
|
|
552
|
+
if (config.EMBEDDER_MODEL) {
|
|
553
|
+
newContent += `MADEINOZ_KNOWLEDGE_EMBEDDER_MODEL=${config.EMBEDDER_MODEL}\n`;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
newContent += '\n';
|
|
557
|
+
|
|
558
|
+
// Add Performance Configuration
|
|
559
|
+
if (config.SEMAPHORE_LIMIT) {
|
|
560
|
+
newContent += `MADEINOZ_KNOWLEDGE_SEMAPHORE_LIMIT=${config.SEMAPHORE_LIMIT}\n`;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
newContent += '\n';
|
|
564
|
+
|
|
565
|
+
// Add Knowledge Graph Configuration
|
|
566
|
+
if (config.GROUP_ID) {
|
|
567
|
+
newContent += `MADEINOZ_KNOWLEDGE_GROUP_ID=${config.GROUP_ID}\n`;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (config.DATABASE_TYPE) {
|
|
571
|
+
newContent += `MADEINOZ_KNOWLEDGE_DATABASE_TYPE=${config.DATABASE_TYPE}\n`;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (config.GRAPHITI_TELEMETRY_ENABLED) {
|
|
575
|
+
newContent += `MADEINOZ_KNOWLEDGE_GRAPHITI_TELEMETRY_ENABLED=${config.GRAPHITI_TELEMETRY_ENABLED}\n`;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
newContent += '\n';
|
|
579
|
+
|
|
580
|
+
// Add Database Configuration (FalkorDB)
|
|
581
|
+
if (config.FALKORDB_HOST) {
|
|
582
|
+
newContent += `MADEINOZ_KNOWLEDGE_FALKORDB_HOST=${config.FALKORDB_HOST}\n`;
|
|
583
|
+
}
|
|
584
|
+
if (config.FALKORDB_PORT) {
|
|
585
|
+
newContent += `MADEINOZ_KNOWLEDGE_FALKORDB_PORT=${config.FALKORDB_PORT}\n`;
|
|
586
|
+
}
|
|
587
|
+
if (config.FALKORDB_PASSWORD) {
|
|
588
|
+
newContent += `MADEINOZ_KNOWLEDGE_FALKORDB_PASSWORD=${config.FALKORDB_PASSWORD}\n`;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
newContent += '\n';
|
|
592
|
+
|
|
593
|
+
// Add Database Configuration (Neo4j)
|
|
594
|
+
if (config.NEO4J_URI) {
|
|
595
|
+
newContent += `MADEINOZ_KNOWLEDGE_NEO4J_URI=${config.NEO4J_URI}\n`;
|
|
596
|
+
}
|
|
597
|
+
if (config.NEO4J_USER) {
|
|
598
|
+
newContent += `MADEINOZ_KNOWLEDGE_NEO4J_USER=${config.NEO4J_USER}\n`;
|
|
599
|
+
}
|
|
600
|
+
if (config.NEO4J_PASSWORD) {
|
|
601
|
+
newContent += `MADEINOZ_KNOWLEDGE_NEO4J_PASSWORD=${config.NEO4J_PASSWORD}\n`;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Write to file
|
|
605
|
+
await Bun.write(this.envFile, newContent);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Create a config loader instance
|
|
611
|
+
*/
|
|
612
|
+
export function createConfigLoader(packRoot?: string): ConfigLoader {
|
|
613
|
+
return new ConfigLoader(packRoot);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Load configuration (convenience function)
|
|
618
|
+
*/
|
|
619
|
+
export async function loadConfig(): Promise<KnowledgeConfig> {
|
|
620
|
+
const loader = new ConfigLoader();
|
|
621
|
+
return await loader.load();
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Validate configuration (convenience function)
|
|
626
|
+
*/
|
|
627
|
+
export function validateConfig(config: KnowledgeConfig): { valid: boolean; errors: string[] } {
|
|
628
|
+
const loader = new ConfigLoader();
|
|
629
|
+
return loader.validate(config);
|
|
630
|
+
}
|