amalfa 1.0.1 â 1.0.2
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/README.md +226 -263
- package/docs/AGENT-METADATA-PATTERNS.md +1021 -0
- package/docs/CONFIG_E2E_VALIDATION.md +147 -0
- package/docs/CONFIG_UNIFICATION.md +187 -0
- package/docs/CONFIG_VALIDATION.md +103 -0
- package/docs/LEGACY_DEPRECATION.md +174 -0
- package/docs/MCP_SETUP.md +317 -0
- package/docs/QUICK_START_MCP.md +168 -0
- package/docs/SESSION-2026-01-06-METADATA-PATTERNS.md +346 -0
- package/docs/SETUP.md +464 -0
- package/docs/SETUP_COMPLETE.md +464 -0
- package/docs/VISION-AGENT-LEARNING.md +1242 -0
- package/docs/_current-config-status.md +93 -0
- package/package.json +6 -3
- package/polyvis.settings.json.bak +38 -0
- package/src/cli.ts +103 -21
- package/src/config/defaults.ts +52 -12
- package/src/core/VectorEngine.ts +18 -9
- package/src/mcp/index.ts +62 -7
- package/src/resonance/DatabaseFactory.ts +3 -4
- package/src/resonance/db.ts +4 -4
- package/src/resonance/services/vector-daemon.ts +151 -0
- package/src/utils/DaemonManager.ts +147 -0
- package/src/utils/ZombieDefense.ts +5 -1
- package/:memory: +0 -0
- package/:memory:-shm +0 -0
- package/:memory:-wal +0 -0
- package/CHANGELOG.md.old +0 -43
- package/README.old.md +0 -112
- package/ROADMAP.md +0 -316
- package/TEST_PLAN.md +0 -561
- package/agents.config.json +0 -11
- package/drizzle/0000_minor_iron_fist.sql +0 -19
- package/drizzle/meta/0000_snapshot.json +0 -139
- package/drizzle/meta/_journal.json +0 -13
- package/example_usage.ts +0 -39
- package/experiment.sh +0 -35
- package/hello +0 -2
- package/index.html +0 -52
- package/knowledge/excalibur.md +0 -12
- package/plans/experience-graph-integration.md +0 -60
- package/prompts/gemini-king-mode-prompt.md +0 -46
- package/public/docs/MCP_TOOLS.md +0 -372
- package/schemas/README.md +0 -20
- package/schemas/cda.schema.json +0 -84
- package/schemas/conceptual-lexicon.schema.json +0 -75
- package/scratchpads/dummy-debrief-boxed.md +0 -39
- package/scratchpads/dummy-debrief.md +0 -27
- package/scratchpads/scratchpad-design.md +0 -50
- package/scratchpads/scratchpad-scrolling.md +0 -20
- package/scratchpads/scratchpad-toc-disappearance.md +0 -23
- package/scratchpads/scratchpad-toc.md +0 -28
- package/scratchpads/test_gardener.md +0 -7
- package/src/core/LLMClient.ts +0 -93
- package/src/core/TagEngine.ts +0 -56
- package/src/db/schema.ts +0 -46
- package/src/gardeners/AutoTagger.ts +0 -116
- package/src/pipeline/HarvesterPipeline.ts +0 -101
- package/src/pipeline/Ingestor.ts +0 -555
- package/src/resonance/cli/ingest.ts +0 -41
- package/src/resonance/cli/migrate.ts +0 -54
- package/src/resonance/config.ts +0 -40
- package/src/resonance/daemon.ts +0 -236
- package/src/resonance/pipeline/extract.ts +0 -89
- package/src/resonance/pipeline/transform_docs.ts +0 -60
- package/src/resonance/services/tokenizer.ts +0 -159
- package/src/resonance/transform/cda.ts +0 -393
- package/src/utils/EnvironmentVerifier.ts +0 -67
- package/substack/substack-playbook-1.md +0 -95
- package/substack/substack-playbook-2.md +0 -78
- package/tasks/ui-investigation.md +0 -26
- package/test-db +0 -0
- package/test-db-shm +0 -0
- package/test-db-wal +0 -0
- package/tests/canary/verify_pinch_check.ts +0 -44
- package/tests/fixtures/ingest_test.md +0 -12
- package/tests/fixtures/ingest_test_boxed.md +0 -13
- package/tests/fixtures/safety_test.md +0 -45
- package/tests/fixtures/safety_test_boxed.md +0 -49
- package/tests/fixtures/tagged_output.md +0 -49
- package/tests/fixtures/tagged_test.md +0 -49
- package/tests/mcp-server-settings.json +0 -8
- package/verify-embedder.ts +0 -54
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Current Configuration Status
|
|
2
|
+
|
|
3
|
+
**Last Updated:** 2026-01-06
|
|
4
|
+
|
|
5
|
+
## Configuration Files (Single Source of Truth)
|
|
6
|
+
|
|
7
|
+
### 1. AMALFA Core Configuration
|
|
8
|
+
**File:** `amalfa.config.json` (root)
|
|
9
|
+
**Purpose:** Main AMALFA system settings
|
|
10
|
+
**Loaded by:** `src/config/defaults.ts`
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"sources": ["../polyvis/docs", "../polyvis/playbooks"],
|
|
15
|
+
"database": ".amalfa/multi-source-test.db",
|
|
16
|
+
"embeddings": {
|
|
17
|
+
"model": "BAAI/bge-small-en-v1.5",
|
|
18
|
+
"dimensions": 384
|
|
19
|
+
},
|
|
20
|
+
"watch": {
|
|
21
|
+
"enabled": true,
|
|
22
|
+
"debounce": 1000
|
|
23
|
+
},
|
|
24
|
+
"excludePatterns": ["node_modules", ".git", ".amalfa"]
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Status:** â
Active, primary config for AMALFA operations
|
|
29
|
+
|
|
30
|
+
### 2. Resonance Configuration (Legacy)
|
|
31
|
+
**File:** `polyvis.settings.json` (root)
|
|
32
|
+
**Purpose:** Resonance database and pipeline settings
|
|
33
|
+
**Loaded by:** `src/resonance/config.ts`
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"paths": {
|
|
38
|
+
"database": { "resonance": "public/resonance.db" },
|
|
39
|
+
"docs": { ... },
|
|
40
|
+
"sources": {
|
|
41
|
+
"experience": [...],
|
|
42
|
+
"persona": { ... }
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"graph": { "tuning": { ... } },
|
|
46
|
+
"schema": { "version": "1.0.0" }
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Status:** đ Legacy, used by resonance pipeline only
|
|
51
|
+
|
|
52
|
+
### 3. Beads Issue Tracking
|
|
53
|
+
**File:** `.beads/config.yaml`
|
|
54
|
+
**Purpose:** Beads issue tracking system configuration
|
|
55
|
+
**Loaded by:** Beads CLI (`bd` commands)
|
|
56
|
+
|
|
57
|
+
**Status:** â
Active, separate system
|
|
58
|
+
|
|
59
|
+
## Configuration Strategy
|
|
60
|
+
|
|
61
|
+
### Current Approach (2026-01-06)
|
|
62
|
+
- **AMALFA** and **Resonance** have separate configs
|
|
63
|
+
- This is **intentional** - they serve different purposes:
|
|
64
|
+
- AMALFA: User-facing MCP server and CLI
|
|
65
|
+
- Resonance: Internal database/pipeline layer
|
|
66
|
+
|
|
67
|
+
### Future Unification (v1.0+)
|
|
68
|
+
- Consider consolidating if Resonance becomes AMALFA-exclusive
|
|
69
|
+
- Keep separate if Resonance remains standalone library
|
|
70
|
+
|
|
71
|
+
## Configuration Hierarchy
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Project Root
|
|
75
|
+
âââ amalfa.config.json â AMALFA core (MCP, CLI, daemon)
|
|
76
|
+
âââ polyvis.settings.json â Resonance (database, pipeline)
|
|
77
|
+
âââ .beads/
|
|
78
|
+
âââ config.yaml â Beads (issue tracking)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Action Items
|
|
82
|
+
|
|
83
|
+
- [x] Decide: Keep separate, deprecate polyvis.settings.json gradually (See CONFIG_UNIFICATION.md)
|
|
84
|
+
- [x] Document: Which config controls what (See CONFIG_UNIFICATION.md)
|
|
85
|
+
- [ ] Add deprecation warning when polyvis.settings.json is loaded
|
|
86
|
+
- [ ] Migrate graph tuning to amalfa.config.json (optional)
|
|
87
|
+
- [ ] Remove polyvis.settings.json in v2.0
|
|
88
|
+
|
|
89
|
+
## Notes
|
|
90
|
+
|
|
91
|
+
- No `_current-*` files existed prior to 2026-01-06
|
|
92
|
+
- Configuration is stable but not unified
|
|
93
|
+
- Each system has clear ownership of its config file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amalfa",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Local-first knowledge graph engine for AI agents. Transforms markdown into searchable memory with MCP protocol.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/pjsvis/amalfa#readme",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"author": "Peter John Smith <729613+pjsvis@users.noreply.github.com>",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
|
-
"url": "https://github.com/pjsvis/amalfa"
|
|
13
|
+
"url": "git+https://github.com/pjsvis/amalfa.git"
|
|
14
14
|
},
|
|
15
15
|
"keywords": [
|
|
16
16
|
"mcp",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"pkm"
|
|
30
30
|
],
|
|
31
31
|
"bin": {
|
|
32
|
-
"amalfa": "
|
|
32
|
+
"amalfa": "src/cli.ts"
|
|
33
33
|
},
|
|
34
34
|
"engines": {
|
|
35
35
|
"bun": "1.3.x",
|
|
@@ -48,6 +48,9 @@
|
|
|
48
48
|
"start": "bun run src/mcp/index.ts start",
|
|
49
49
|
"stop": "bun run src/mcp/index.ts stop",
|
|
50
50
|
"status": "bun run src/mcp/index.ts status",
|
|
51
|
+
"servers": "bun run scripts/cli/servers.ts",
|
|
52
|
+
"validate-config": "bun run scripts/validate-config.ts",
|
|
53
|
+
"release": "bun run scripts/release.ts",
|
|
51
54
|
"check": "biome check .",
|
|
52
55
|
"format": "biome format --write ."
|
|
53
56
|
},
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "â ī¸ DEPRECATED: This file will be removed in v2.0. Use amalfa.config.json for user-facing settings. See docs/CONFIG_UNIFICATION.md",
|
|
3
|
+
"paths": {
|
|
4
|
+
"database": {
|
|
5
|
+
"resonance": "public/resonance.db"
|
|
6
|
+
},
|
|
7
|
+
"docs": {
|
|
8
|
+
"root": "docs",
|
|
9
|
+
"webdocs": "docs/webdocs",
|
|
10
|
+
"architecture": "docs/architecture",
|
|
11
|
+
"public": "public/docs"
|
|
12
|
+
},
|
|
13
|
+
"sources": {
|
|
14
|
+
"experience": [
|
|
15
|
+
{ "path": "debriefs", "name": "Debrief" },
|
|
16
|
+
{ "path": "playbooks", "name": "Playbook" },
|
|
17
|
+
{ "path": "briefs", "name": "Brief" },
|
|
18
|
+
{ "path": "docs", "name": "Docs" }
|
|
19
|
+
],
|
|
20
|
+
"persona": {
|
|
21
|
+
"lexicon": "scripts/fixtures/conceptual-lexicon-ref-v1.79.json",
|
|
22
|
+
"cda": "scripts/fixtures/cda-ref-v63.json"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"graph": {
|
|
27
|
+
"tuning": {
|
|
28
|
+
"louvain": {
|
|
29
|
+
"persona": 0.3,
|
|
30
|
+
"experience": 0.25
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
"schema": {
|
|
36
|
+
"version": "1.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -3,8 +3,10 @@ import { existsSync, statSync } from "node:fs";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
|
|
6
|
-
const VERSION = "1.0.
|
|
7
|
-
|
|
6
|
+
const VERSION = "1.0.2";
|
|
7
|
+
|
|
8
|
+
// Database path loaded from config (lazy loaded per command)
|
|
9
|
+
let DB_PATH: string | null = null;
|
|
8
10
|
|
|
9
11
|
// Parse command line arguments
|
|
10
12
|
const args = process.argv.slice(2);
|
|
@@ -22,6 +24,7 @@ Commands:
|
|
|
22
24
|
serve Start MCP server (stdio transport)
|
|
23
25
|
stats Show database statistics
|
|
24
26
|
doctor Check installation and configuration
|
|
27
|
+
setup-mcp Generate MCP configuration JSON
|
|
25
28
|
daemon <action> Manage file watcher (start|stop|status|restart)
|
|
26
29
|
|
|
27
30
|
Options:
|
|
@@ -44,10 +47,21 @@ function showVersion() {
|
|
|
44
47
|
console.log(`amalfa v${VERSION}`);
|
|
45
48
|
}
|
|
46
49
|
|
|
50
|
+
async function getDbPath(): Promise<string> {
|
|
51
|
+
if (DB_PATH) return DB_PATH;
|
|
52
|
+
|
|
53
|
+
// Load from config
|
|
54
|
+
const { loadConfig } = await import("./config/defaults");
|
|
55
|
+
const config = await loadConfig();
|
|
56
|
+
DB_PATH = join(process.cwd(), config.database);
|
|
57
|
+
return DB_PATH;
|
|
58
|
+
}
|
|
59
|
+
|
|
47
60
|
async function checkDatabase(): Promise<boolean> {
|
|
48
|
-
|
|
61
|
+
const dbPath = await getDbPath();
|
|
62
|
+
if (!existsSync(dbPath)) {
|
|
49
63
|
console.error(`
|
|
50
|
-
â Database not found at: ${
|
|
64
|
+
â Database not found at: ${dbPath}
|
|
51
65
|
|
|
52
66
|
To initialize AMALFA:
|
|
53
67
|
1. Create markdown files in ./docs/ (or your preferred location)
|
|
@@ -66,8 +80,9 @@ async function cmdServe() {
|
|
|
66
80
|
process.exit(1);
|
|
67
81
|
}
|
|
68
82
|
|
|
83
|
+
const dbPath = await getDbPath();
|
|
69
84
|
console.error("đ Starting AMALFA MCP Server...");
|
|
70
|
-
console.error(`đ Database: ${
|
|
85
|
+
console.error(`đ Database: ${dbPath}`);
|
|
71
86
|
console.error("");
|
|
72
87
|
|
|
73
88
|
// Run MCP server (it handles stdio transport)
|
|
@@ -89,18 +104,19 @@ async function cmdStats() {
|
|
|
89
104
|
}
|
|
90
105
|
|
|
91
106
|
// Import database wrapper
|
|
107
|
+
const dbPath = await getDbPath();
|
|
92
108
|
const { ResonanceDB } = await import("./resonance/db");
|
|
93
|
-
const db = new ResonanceDB(
|
|
109
|
+
const db = new ResonanceDB(dbPath);
|
|
94
110
|
|
|
95
111
|
try {
|
|
96
112
|
const stats = db.getStats();
|
|
97
|
-
const fileSize = statSync(
|
|
113
|
+
const fileSize = statSync(dbPath).size;
|
|
98
114
|
const fileSizeMB = (fileSize / 1024 / 1024).toFixed(2);
|
|
99
115
|
|
|
100
|
-
|
|
116
|
+
console.log(`
|
|
101
117
|
đ AMALFA Database Statistics
|
|
102
118
|
|
|
103
|
-
Database: ${
|
|
119
|
+
Database: ${dbPath}
|
|
104
120
|
Size: ${fileSizeMB} MB
|
|
105
121
|
|
|
106
122
|
Nodes: ${stats.nodes.toLocaleString()}
|
|
@@ -108,7 +124,7 @@ Edges: ${stats.edges.toLocaleString()}
|
|
|
108
124
|
Embeddings: ${stats.vectors.toLocaleString()} (384-dim)
|
|
109
125
|
|
|
110
126
|
Source: ./docs (markdown files)
|
|
111
|
-
Last modified: ${new Date(statSync(
|
|
127
|
+
Last modified: ${new Date(statSync(dbPath).mtime).toISOString()}
|
|
112
128
|
|
|
113
129
|
đ To search: Use with Claude Desktop or other MCP client
|
|
114
130
|
đ To update: Run 'amalfa daemon start' (coming soon)
|
|
@@ -250,6 +266,55 @@ async function cmdDaemon() {
|
|
|
250
266
|
});
|
|
251
267
|
}
|
|
252
268
|
|
|
269
|
+
async function cmdSetupMcp() {
|
|
270
|
+
const { resolve } = await import("node:path");
|
|
271
|
+
|
|
272
|
+
const cwd = resolve(process.cwd());
|
|
273
|
+
const mcpScript = resolve(cwd, "src/mcp/index.ts");
|
|
274
|
+
|
|
275
|
+
// Minimal PATH for MCP - only include essential directories
|
|
276
|
+
const bunPath = process.execPath.replace(/\/bun$/, ''); // Directory containing bun
|
|
277
|
+
const minimalPath = [
|
|
278
|
+
bunPath,
|
|
279
|
+
'/usr/local/bin',
|
|
280
|
+
'/usr/bin',
|
|
281
|
+
'/bin',
|
|
282
|
+
'/usr/sbin',
|
|
283
|
+
'/sbin',
|
|
284
|
+
'/opt/homebrew/bin', // Apple Silicon Homebrew
|
|
285
|
+
].join(':');
|
|
286
|
+
|
|
287
|
+
const config = {
|
|
288
|
+
mcpServers: {
|
|
289
|
+
amalfa: {
|
|
290
|
+
command: "bun",
|
|
291
|
+
args: ["run", mcpScript],
|
|
292
|
+
env: {
|
|
293
|
+
PATH: minimalPath,
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
console.log("\nâ
AMALFA MCP Configuration");
|
|
300
|
+
console.log("=".repeat(60));
|
|
301
|
+
console.log(`đ Installation: ${cwd}`);
|
|
302
|
+
console.log("=".repeat(60));
|
|
303
|
+
console.log("\nđ Copy this JSON to your MCP client config:");
|
|
304
|
+
console.log(" Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json");
|
|
305
|
+
console.log(" Warp Preview: MCP settings\n");
|
|
306
|
+
console.log("=".repeat(60));
|
|
307
|
+
console.log();
|
|
308
|
+
|
|
309
|
+
console.log(JSON.stringify(config, null, 2));
|
|
310
|
+
|
|
311
|
+
console.log();
|
|
312
|
+
console.log("=".repeat(60));
|
|
313
|
+
console.log("đĄ Tip: If you move this folder, run 'amalfa setup-mcp' again");
|
|
314
|
+
console.log("=".repeat(60));
|
|
315
|
+
console.log();
|
|
316
|
+
}
|
|
317
|
+
|
|
253
318
|
async function cmdDoctor() {
|
|
254
319
|
console.log("đŠē AMALFA Health Check\n");
|
|
255
320
|
|
|
@@ -258,12 +323,14 @@ async function cmdDoctor() {
|
|
|
258
323
|
// Check Bun runtime
|
|
259
324
|
console.log("â Bun runtime: OK");
|
|
260
325
|
|
|
261
|
-
// Check database
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
326
|
+
// Check config and database
|
|
327
|
+
const dbPath = await getDbPath();
|
|
328
|
+
if (existsSync(dbPath)) {
|
|
329
|
+
const fileSizeMB = (statSync(dbPath).size / 1024 / 1024).toFixed(2);
|
|
330
|
+
console.log(`â Database found: ${dbPath} (${fileSizeMB} MB)`);
|
|
265
331
|
} else {
|
|
266
|
-
console.log(`â Database not found: ${
|
|
332
|
+
console.log(`â Database not found: ${dbPath}`);
|
|
333
|
+
console.log(` Run: amalfa init`);
|
|
267
334
|
issues++;
|
|
268
335
|
}
|
|
269
336
|
|
|
@@ -276,12 +343,23 @@ async function cmdDoctor() {
|
|
|
276
343
|
issues++;
|
|
277
344
|
}
|
|
278
345
|
|
|
279
|
-
// Check source directories
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
346
|
+
// Check source directories from config
|
|
347
|
+
const { loadConfig } = await import("./config/defaults");
|
|
348
|
+
const config = await loadConfig();
|
|
349
|
+
const sources = config.sources || ["./docs"];
|
|
350
|
+
let sourcesFound = 0;
|
|
351
|
+
for (const source of sources) {
|
|
352
|
+
const sourcePath = join(process.cwd(), source);
|
|
353
|
+
if (existsSync(sourcePath)) {
|
|
354
|
+
console.log(`â Source directory: ${sourcePath}`);
|
|
355
|
+
sourcesFound++;
|
|
356
|
+
} else {
|
|
357
|
+
console.log(`â Source directory not found: ${sourcePath}`);
|
|
358
|
+
issues++;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (sourcesFound === 0) {
|
|
362
|
+
console.log(` Configure sources in amalfa.config.json`);
|
|
285
363
|
}
|
|
286
364
|
|
|
287
365
|
// Check dependencies (FastEmbed)
|
|
@@ -338,6 +416,10 @@ async function main() {
|
|
|
338
416
|
await cmdDaemon();
|
|
339
417
|
break;
|
|
340
418
|
|
|
419
|
+
case "setup-mcp":
|
|
420
|
+
await cmdSetupMcp();
|
|
421
|
+
break;
|
|
422
|
+
|
|
341
423
|
case "version":
|
|
342
424
|
case "--version":
|
|
343
425
|
case "-v":
|
package/src/config/defaults.ts
CHANGED
|
@@ -17,6 +17,20 @@ export interface AmalfaConfig {
|
|
|
17
17
|
debounce: number;
|
|
18
18
|
};
|
|
19
19
|
excludePatterns: string[];
|
|
20
|
+
/** Graph analysis tuning parameters (optional) */
|
|
21
|
+
graph?: {
|
|
22
|
+
tuning?: {
|
|
23
|
+
louvain?: {
|
|
24
|
+
persona?: number;
|
|
25
|
+
experience?: number;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
/** Persona fixture paths (optional, for legacy Resonance features) */
|
|
30
|
+
fixtures?: {
|
|
31
|
+
lexicon?: string;
|
|
32
|
+
cda?: string;
|
|
33
|
+
};
|
|
20
34
|
}
|
|
21
35
|
|
|
22
36
|
export const DEFAULT_CONFIG: AmalfaConfig = {
|
|
@@ -31,6 +45,20 @@ export const DEFAULT_CONFIG: AmalfaConfig = {
|
|
|
31
45
|
debounce: 1000,
|
|
32
46
|
},
|
|
33
47
|
excludePatterns: ["node_modules", ".git", ".amalfa"],
|
|
48
|
+
// Optional graph tuning (for advanced use)
|
|
49
|
+
graph: {
|
|
50
|
+
tuning: {
|
|
51
|
+
louvain: {
|
|
52
|
+
persona: 0.3,
|
|
53
|
+
experience: 0.25,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
// Optional fixtures (for legacy Resonance features)
|
|
58
|
+
fixtures: {
|
|
59
|
+
lexicon: "scripts/fixtures/conceptual-lexicon-ref-v1.79.json",
|
|
60
|
+
cda: "scripts/fixtures/cda-ref-v63.json",
|
|
61
|
+
},
|
|
34
62
|
};
|
|
35
63
|
|
|
36
64
|
/**
|
|
@@ -58,19 +86,31 @@ export async function loadConfig(): Promise<AmalfaConfig> {
|
|
|
58
86
|
userConfig = imported.default || imported;
|
|
59
87
|
}
|
|
60
88
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
// Merge with defaults
|
|
90
|
+
const merged = {
|
|
91
|
+
...DEFAULT_CONFIG,
|
|
92
|
+
...userConfig,
|
|
93
|
+
embeddings: {
|
|
94
|
+
...DEFAULT_CONFIG.embeddings,
|
|
95
|
+
...(userConfig.embeddings || {}),
|
|
96
|
+
},
|
|
97
|
+
watch: {
|
|
98
|
+
...DEFAULT_CONFIG.watch,
|
|
99
|
+
...(userConfig.watch || {}),
|
|
100
|
+
},
|
|
101
|
+
graph: {
|
|
102
|
+
...DEFAULT_CONFIG.graph,
|
|
103
|
+
...(userConfig.graph || {}),
|
|
104
|
+
tuning: {
|
|
105
|
+
...(DEFAULT_CONFIG.graph?.tuning || {}),
|
|
106
|
+
...(userConfig.graph?.tuning || {}),
|
|
72
107
|
},
|
|
73
|
-
}
|
|
108
|
+
},
|
|
109
|
+
fixtures: {
|
|
110
|
+
...DEFAULT_CONFIG.fixtures,
|
|
111
|
+
...(userConfig.fixtures || {}),
|
|
112
|
+
},
|
|
113
|
+
};
|
|
74
114
|
|
|
75
115
|
// Normalize: Convert legacy 'source' to 'sources' array
|
|
76
116
|
if (merged.source && !merged.sources) {
|
package/src/core/VectorEngine.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { Database } from "bun:sqlite";
|
|
2
|
-
import { join } from "node:path";
|
|
3
2
|
import { EmbeddingModel, FlagEmbedding } from "fastembed";
|
|
4
|
-
import settings from "@/polyvis.settings.json";
|
|
5
3
|
|
|
6
4
|
// Types
|
|
7
5
|
export interface SearchResult {
|
|
@@ -89,9 +87,7 @@ export class VectorEngine {
|
|
|
89
87
|
console.warn(
|
|
90
88
|
"â ī¸ DEPRECATED: VectorEngine string path constructor bypasses DatabaseFactory. Pass Database object instead. Will be removed in v2.0.",
|
|
91
89
|
);
|
|
92
|
-
|
|
93
|
-
dbOrPath || join(process.cwd(), settings.paths.database.resonance);
|
|
94
|
-
this.db = new Database(path);
|
|
90
|
+
this.db = new Database(dbOrPath);
|
|
95
91
|
|
|
96
92
|
// Apply Safeguards if we created it
|
|
97
93
|
this.db.run("PRAGMA journal_mode = WAL;");
|
|
@@ -192,22 +188,35 @@ export class VectorEngine {
|
|
|
192
188
|
const topK = scored.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
193
189
|
|
|
194
190
|
// 5. Hydrate Content (for top K only)
|
|
191
|
+
// Note: Hollow Nodes have content=NULL, use meta.source to read from filesystem if needed
|
|
195
192
|
const results: SearchResult[] = [];
|
|
196
193
|
const contentStmt = this.db.prepare(
|
|
197
|
-
"SELECT title, content FROM nodes WHERE id = ?",
|
|
194
|
+
"SELECT title, content, meta FROM nodes WHERE id = ?",
|
|
198
195
|
);
|
|
199
196
|
|
|
200
197
|
for (const item of topK) {
|
|
201
198
|
const row = contentStmt.get(item.id) as {
|
|
202
199
|
title: string;
|
|
203
|
-
content: string;
|
|
200
|
+
content: string | null;
|
|
201
|
+
meta: string | null;
|
|
204
202
|
};
|
|
205
203
|
if (row) {
|
|
204
|
+
// For hollow nodes, extract a preview from title or meta
|
|
205
|
+
let content = row.content || "";
|
|
206
|
+
if (!content && row.meta) {
|
|
207
|
+
try {
|
|
208
|
+
const meta = JSON.parse(row.meta);
|
|
209
|
+
// Provide source path as content placeholder for hollow nodes
|
|
210
|
+
content = `[Hollow Node: ${meta.source || "no source"}]`;
|
|
211
|
+
} catch {
|
|
212
|
+
content = "[Hollow Node: parse error]";
|
|
213
|
+
}
|
|
214
|
+
}
|
|
206
215
|
results.push({
|
|
207
216
|
id: item.id,
|
|
208
217
|
score: item.score,
|
|
209
|
-
title: row.title,
|
|
210
|
-
content:
|
|
218
|
+
title: row.title,
|
|
219
|
+
content: content,
|
|
211
220
|
});
|
|
212
221
|
}
|
|
213
222
|
}
|
package/src/mcp/index.ts
CHANGED
|
@@ -8,9 +8,10 @@ import {
|
|
|
8
8
|
ListToolsRequestSchema,
|
|
9
9
|
ReadResourceRequestSchema,
|
|
10
10
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
11
|
+
import { loadConfig } from "@src/config/defaults";
|
|
11
12
|
import { VectorEngine } from "@src/core/VectorEngine";
|
|
12
13
|
import { ResonanceDB } from "@src/resonance/db";
|
|
13
|
-
import {
|
|
14
|
+
import { DaemonManager } from "../utils/DaemonManager";
|
|
14
15
|
import { getLogger } from "../utils/Logger";
|
|
15
16
|
import { ServiceLifecycle } from "../utils/ServiceLifecycle";
|
|
16
17
|
|
|
@@ -29,18 +30,68 @@ const lifecycle = new ServiceLifecycle({
|
|
|
29
30
|
|
|
30
31
|
// --- Server Logic ---
|
|
31
32
|
|
|
33
|
+
// Database path from config (loaded once at startup)
|
|
34
|
+
let DB_PATH: string;
|
|
35
|
+
|
|
32
36
|
// Helper function to create fresh database connection per request
|
|
33
37
|
function createConnection() {
|
|
34
|
-
const
|
|
35
|
-
const db = new ResonanceDB(dbPath);
|
|
38
|
+
const db = new ResonanceDB(DB_PATH);
|
|
36
39
|
const vectorEngine = new VectorEngine(db.getRawDb());
|
|
37
40
|
return { db, vectorEngine };
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
async function runServer() {
|
|
41
|
-
// 0.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
// 0. Load configuration
|
|
45
|
+
const config = await loadConfig();
|
|
46
|
+
DB_PATH = join(process.cwd(), config.database);
|
|
47
|
+
log.info({ database: DB_PATH }, "đ Database path loaded from config");
|
|
48
|
+
|
|
49
|
+
// 1. Start daemons if needed
|
|
50
|
+
const daemonManager = new DaemonManager();
|
|
51
|
+
|
|
52
|
+
// Check file watcher status
|
|
53
|
+
if (config.watch?.enabled) {
|
|
54
|
+
const watcherStatus = await daemonManager.checkFileWatcher();
|
|
55
|
+
if (!watcherStatus.running) {
|
|
56
|
+
log.info("đ Starting file watcher daemon...");
|
|
57
|
+
try {
|
|
58
|
+
await daemonManager.startFileWatcher();
|
|
59
|
+
log.info("â
File watcher daemon started");
|
|
60
|
+
} catch (e) {
|
|
61
|
+
log.warn(
|
|
62
|
+
{ err: e },
|
|
63
|
+
"â ī¸ Failed to start file watcher, continuing without it",
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
log.info(
|
|
68
|
+
{ pid: watcherStatus.pid },
|
|
69
|
+
"â
File watcher daemon already running",
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
log.info("âšī¸ File watching disabled in config");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Start vector daemon for fast embeddings
|
|
77
|
+
const vectorStatus = await daemonManager.checkVectorDaemon();
|
|
78
|
+
if (!vectorStatus.running) {
|
|
79
|
+
log.info("đ Starting vector daemon...");
|
|
80
|
+
try {
|
|
81
|
+
await daemonManager.startVectorDaemon();
|
|
82
|
+
log.info("â
Vector daemon started");
|
|
83
|
+
} catch (e) {
|
|
84
|
+
log.warn(
|
|
85
|
+
{ err: e },
|
|
86
|
+
"â ī¸ Failed to start vector daemon, searches will be slower",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
log.info(
|
|
91
|
+
{ pid: vectorStatus.pid, port: vectorStatus.port },
|
|
92
|
+
"â
Vector daemon already running",
|
|
93
|
+
);
|
|
94
|
+
}
|
|
44
95
|
|
|
45
96
|
log.info("đ AMALFA MCP Server Initializing...");
|
|
46
97
|
|
|
@@ -138,10 +189,14 @@ async function runServer() {
|
|
|
138
189
|
try {
|
|
139
190
|
const vectorResults = await vectorEngine.search(query, limit);
|
|
140
191
|
for (const r of vectorResults) {
|
|
192
|
+
// Handle hollow nodes: content may be placeholder text
|
|
193
|
+
const preview = r.content
|
|
194
|
+
? r.content.slice(0, 200).replace(/\n/g, " ")
|
|
195
|
+
: "[No preview available]";
|
|
141
196
|
candidates.set(r.id, {
|
|
142
197
|
id: r.id,
|
|
143
198
|
score: r.score,
|
|
144
|
-
preview:
|
|
199
|
+
preview: preview,
|
|
145
200
|
source: "vector",
|
|
146
201
|
});
|
|
147
202
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Database } from "bun:sqlite";
|
|
2
|
-
import settings from "@/polyvis.settings.json";
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* đ DATABASE FACTORY (The Enforcer)
|
|
@@ -14,10 +13,10 @@ import settings from "@/polyvis.settings.json";
|
|
|
14
13
|
export const DatabaseFactory = {
|
|
15
14
|
/**
|
|
16
15
|
* Connects specifically to the main Resonance Graph database.
|
|
17
|
-
*
|
|
16
|
+
* @deprecated Use connect() with explicit path from config instead.
|
|
18
17
|
*/
|
|
19
|
-
connectToResonance(options: { readonly?: boolean } = {}): Database {
|
|
20
|
-
return DatabaseFactory.connect(
|
|
18
|
+
connectToResonance(dbPath: string = ".amalfa/resonance.db", options: { readonly?: boolean } = {}): Database {
|
|
19
|
+
return DatabaseFactory.connect(dbPath, options);
|
|
21
20
|
},
|
|
22
21
|
/**
|
|
23
22
|
* Creates a fully configured, concurrent-safe SQLite connection.
|
package/src/resonance/db.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Database } from "bun:sqlite";
|
|
2
2
|
import { getLogger } from "@src/utils/Logger";
|
|
3
|
-
import settings from "@/polyvis.settings.json";
|
|
4
3
|
import { DatabaseFactory } from "./DatabaseFactory";
|
|
5
4
|
import { CURRENT_SCHEMA_VERSION, MIGRATIONS } from "./schema";
|
|
6
5
|
|
|
@@ -25,10 +24,11 @@ export class ResonanceDB {
|
|
|
25
24
|
private dbPath: string;
|
|
26
25
|
|
|
27
26
|
/**
|
|
28
|
-
* Factory method to load the default Resonance Graph
|
|
27
|
+
* Factory method to load the default Resonance Graph.
|
|
28
|
+
* @deprecated Use constructor with explicit path from config instead.
|
|
29
29
|
*/
|
|
30
|
-
static init(): ResonanceDB {
|
|
31
|
-
return new ResonanceDB(
|
|
30
|
+
static init(dbPath: string = ".amalfa/resonance.db"): ResonanceDB {
|
|
31
|
+
return new ResonanceDB(dbPath);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/**
|