amalfa 1.0.8 ā 1.0.10
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 +14 -4
- package/package.json +8 -2
- package/src/cli.ts +126 -1
package/README.md
CHANGED
|
@@ -270,10 +270,20 @@ bun run dev
|
|
|
270
270
|
### Commands
|
|
271
271
|
|
|
272
272
|
```bash
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
273
|
+
# CLI commands (available after global install)
|
|
274
|
+
amalfa init # Initialize database from markdown
|
|
275
|
+
amalfa serve # Start MCP server (stdio)
|
|
276
|
+
amalfa stats # Show database statistics
|
|
277
|
+
amalfa doctor # Health check
|
|
278
|
+
amalfa servers # Show all service status
|
|
279
|
+
amalfa daemon start # Start file watcher daemon
|
|
280
|
+
amalfa daemon stop # Stop file watcher daemon
|
|
281
|
+
amalfa daemon status # Check daemon status
|
|
282
|
+
amalfa setup-mcp # Generate MCP config
|
|
283
|
+
|
|
284
|
+
# Development commands
|
|
285
|
+
bun test # Run tests
|
|
286
|
+
bun run precommit # TypeScript + Biome checks
|
|
277
287
|
```
|
|
278
288
|
|
|
279
289
|
---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amalfa",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
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",
|
|
@@ -43,7 +43,13 @@
|
|
|
43
43
|
"scripts": {
|
|
44
44
|
"precommit": "bun run scripts/maintenance/pre-commit.ts",
|
|
45
45
|
"check": "biome check .",
|
|
46
|
-
"format": "biome format --write ."
|
|
46
|
+
"format": "biome format --write .",
|
|
47
|
+
"cli": "bun run src/cli.ts",
|
|
48
|
+
"cli:servers": "bun run src/cli.ts servers",
|
|
49
|
+
"cli:servers:dot": "bun run src/cli.ts servers --dot",
|
|
50
|
+
"cli:stats": "bun run src/cli.ts stats",
|
|
51
|
+
"cli:doctor": "bun run src/cli.ts doctor",
|
|
52
|
+
"cli:daemon": "bun run src/cli.ts daemon status"
|
|
47
53
|
},
|
|
48
54
|
"dependencies": {
|
|
49
55
|
"@modelcontextprotocol/sdk": "1.25.0",
|
package/src/cli.ts
CHANGED
|
@@ -3,7 +3,7 @@ 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.
|
|
6
|
+
const VERSION = "1.0.10";
|
|
7
7
|
|
|
8
8
|
// Database path loaded from config (lazy loaded per command)
|
|
9
9
|
let DB_PATH: string | null = null;
|
|
@@ -26,6 +26,7 @@ Commands:
|
|
|
26
26
|
doctor Check installation and configuration
|
|
27
27
|
setup-mcp Generate MCP configuration JSON
|
|
28
28
|
daemon <action> Manage file watcher (start|stop|status|restart)
|
|
29
|
+
servers [--dot] Show status of all AMALFA services (--dot for graph)
|
|
29
30
|
|
|
30
31
|
Options:
|
|
31
32
|
--force Override pre-flight warnings (errors still block)
|
|
@@ -315,6 +316,126 @@ async function cmdSetupMcp() {
|
|
|
315
316
|
console.log();
|
|
316
317
|
}
|
|
317
318
|
|
|
319
|
+
async function cmdServers() {
|
|
320
|
+
const showDot = args.includes("--dot");
|
|
321
|
+
|
|
322
|
+
const SERVICES = [
|
|
323
|
+
{ name: "MCP Server", pidFile: ".mcp.pid", port: "stdio", id: "mcp" },
|
|
324
|
+
{ name: "Vector Daemon", pidFile: ".vector-daemon.pid", port: "3010", id: "vector" },
|
|
325
|
+
{ name: "File Watcher", pidFile: ".amalfa-daemon.pid", port: "-", id: "watcher" },
|
|
326
|
+
];
|
|
327
|
+
|
|
328
|
+
async function isRunning(pid: number): Promise<boolean> {
|
|
329
|
+
try {
|
|
330
|
+
process.kill(pid, 0);
|
|
331
|
+
return true;
|
|
332
|
+
} catch {
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (showDot) {
|
|
338
|
+
// Generate DOT diagram
|
|
339
|
+
const statuses = new Map<string, { status: string; pid: string }>();
|
|
340
|
+
|
|
341
|
+
for (const svc of SERVICES) {
|
|
342
|
+
let status = "stopped";
|
|
343
|
+
let pidStr = "-";
|
|
344
|
+
|
|
345
|
+
if (existsSync(svc.pidFile)) {
|
|
346
|
+
try {
|
|
347
|
+
const { readFileSync } = await import("node:fs");
|
|
348
|
+
const text = readFileSync(svc.pidFile, "utf-8");
|
|
349
|
+
const pid = Number.parseInt(text.trim(), 10);
|
|
350
|
+
|
|
351
|
+
if (!Number.isNaN(pid) && await isRunning(pid)) {
|
|
352
|
+
status = "running";
|
|
353
|
+
pidStr = pid.toString();
|
|
354
|
+
} else {
|
|
355
|
+
status = "stale";
|
|
356
|
+
pidStr = `${pid}`;
|
|
357
|
+
}
|
|
358
|
+
} catch {
|
|
359
|
+
// Ignore
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
statuses.set(svc.id, { status, pid: pidStr });
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
console.log("digraph AMALFA {");
|
|
367
|
+
console.log(" rankdir=LR;");
|
|
368
|
+
console.log(" node [shape=box, style=filled];");
|
|
369
|
+
console.log("");
|
|
370
|
+
console.log(" // Nodes");
|
|
371
|
+
|
|
372
|
+
for (const svc of SERVICES) {
|
|
373
|
+
const st = statuses.get(svc.id);
|
|
374
|
+
const color = st?.status === "running" ? "lightgreen" : st?.status === "stale" ? "orange" : "lightgray";
|
|
375
|
+
const label = `${svc.name}\\nPort: ${svc.port}\\nPID: ${st?.pid || "-"}`;
|
|
376
|
+
console.log(` ${svc.id} [label="${label}", fillcolor=${color}];`);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
console.log("");
|
|
380
|
+
console.log(" // Database");
|
|
381
|
+
console.log(" db [label=\"SQLite\\n.amalfa/resonance.db\", shape=cylinder, fillcolor=lightyellow];");
|
|
382
|
+
console.log("");
|
|
383
|
+
console.log(" // Connections");
|
|
384
|
+
console.log(" mcp -> db [label=\"read/write\"];");
|
|
385
|
+
console.log(" vector -> db [label=\"embeddings\"];");
|
|
386
|
+
console.log(" watcher -> db [label=\"updates\"];");
|
|
387
|
+
console.log(" mcp -> vector [label=\"query\", style=dashed];");
|
|
388
|
+
console.log("}");
|
|
389
|
+
console.log("");
|
|
390
|
+
console.log("# Save to file: amalfa servers --dot > amalfa.dot");
|
|
391
|
+
console.log("# Render: dot -Tpng amalfa.dot -o amalfa.png");
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
console.log("\nš” AMALFA Service Status\n");
|
|
396
|
+
console.log("ā".repeat(70));
|
|
397
|
+
console.log(
|
|
398
|
+
"SERVICE".padEnd(18) +
|
|
399
|
+
"PORT".padEnd(12) +
|
|
400
|
+
"STATUS".padEnd(15) +
|
|
401
|
+
"PID".padEnd(10)
|
|
402
|
+
);
|
|
403
|
+
console.log("ā".repeat(70));
|
|
404
|
+
|
|
405
|
+
for (const svc of SERVICES) {
|
|
406
|
+
const { readFileSync } = await import("node:fs");
|
|
407
|
+
let status = "āŖļø STOPPED";
|
|
408
|
+
let pidStr = "-";
|
|
409
|
+
|
|
410
|
+
if (existsSync(svc.pidFile)) {
|
|
411
|
+
try {
|
|
412
|
+
const text = readFileSync(svc.pidFile, "utf-8");
|
|
413
|
+
const pid = Number.parseInt(text.trim(), 10);
|
|
414
|
+
|
|
415
|
+
if (!Number.isNaN(pid) && await isRunning(pid)) {
|
|
416
|
+
status = "š¢ RUNNING";
|
|
417
|
+
pidStr = pid.toString();
|
|
418
|
+
} else {
|
|
419
|
+
status = "š“ STALE";
|
|
420
|
+
pidStr = `${pid} (?)`;
|
|
421
|
+
}
|
|
422
|
+
} catch {
|
|
423
|
+
// Ignore read errors
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
console.log(
|
|
428
|
+
svc.name.padEnd(18) +
|
|
429
|
+
svc.port.padEnd(12) +
|
|
430
|
+
status.padEnd(15) +
|
|
431
|
+
pidStr.padEnd(10)
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
console.log("ā".repeat(70));
|
|
436
|
+
console.log("\nš” Tip: Use 'amalfa daemon start' to start the file watcher\n");
|
|
437
|
+
}
|
|
438
|
+
|
|
318
439
|
async function cmdDoctor() {
|
|
319
440
|
console.log("𩺠AMALFA Health Check\n");
|
|
320
441
|
|
|
@@ -420,6 +541,10 @@ async function main() {
|
|
|
420
541
|
await cmdSetupMcp();
|
|
421
542
|
break;
|
|
422
543
|
|
|
544
|
+
case "servers":
|
|
545
|
+
await cmdServers();
|
|
546
|
+
break;
|
|
547
|
+
|
|
423
548
|
case "version":
|
|
424
549
|
case "--version":
|
|
425
550
|
case "-v":
|