amalfa 1.0.38 → 1.0.40

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/CHANGELOG.md ADDED
@@ -0,0 +1,201 @@
1
+ # Changelog
2
+
3
+ All notable changes to AMALFA will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.40] - 2026-01-09
9
+
10
+ ### Added
11
+ - **Ember Phase 2**: Integrated `EmberService` into the `AmalfaDaemon`.
12
+ - **Optimization**: Changes to file content now trigger immediate sidecar generation (if applicable).
13
+ - **Configuration**: Added `tests` to default `excludePatterns`.
14
+ - **CLI**: Added `amalfa stop-all` (alias `kill`) to stop all running services.
15
+
16
+ ## [1.0.39] - 2026-01-09
17
+
18
+ ### Fixed
19
+ - **Documentation**: Updated CHANGELOG.md to include recent Ember Service changes (missed in 1.0.38).
20
+ - **Testing**: Fixed `analyzer.test.ts` to correctly pass file content, resolving pre-commit failures.
21
+ - **Process**: Added Changelog version verification to `pre-commit` hook to prevent future ghost releases.
22
+
23
+ ## [1.0.38] - 2026-01-09
24
+
25
+ ### Added
26
+ - **Ember Service**: Introduced the `amalfa ember` command suite for automated documentation enrichment.
27
+ - `amalfa ember scan`: Analyzes documents using graph communities to suggest missing tags (Sidecar generation).
28
+ - `amalfa ember squash`: Safely merges sidecar suggestions into markdown frontmatter using `gray-matter`.
29
+ - **Graph Intelligence**: Integrated `GraphEngine` into Ember for community detection (Louvain) and neighbor-based tag recommendation.
30
+ - **Stub Detection**: Added heuristics to automatically tag short content as `stub`.
31
+
32
+ ### Changed
33
+ - **Ingestion Pipeline**: Upgraded `AmalfaIngestor` to use `gray-matter` for robust frontmatter parsing (replacing legacy regex).
34
+ - **CLI**: Expanded `src/cli.ts` to include `ember` command handling.
35
+
36
+ ### Fixed
37
+ - **Testing**: Resolved content read logic in `analyzer.test.ts`.
38
+
39
+ ## [1.0.37] - 2026-01-09
40
+
41
+ ### Added
42
+ - **Drizzle Integration**: Added Drizzle ORM for schema management and migrations using `drizzle-kit`.
43
+ - **Hono Migration**: Migrated Sonar Agent to Hono for robust routing and standard middleware support.
44
+ - **Guardrails**: Added explicit "No ORM Runtime" policy for FAFCAS compliance (Drizzle for schema only).
45
+
46
+ ### Changed
47
+ - **Dependency Pinning**: Pinned all dependencies in `package.json` to exact versions to prevent drift.
48
+ - **Cleanup**: Removed stale deprecations and unused imports across the codebase.
49
+
50
+ ## [1.0.36] - 2026-01-09
51
+
52
+ ### Fixed
53
+ - **Pre-commit Checks**: Resolved TypeScript regex match narrowing issues in `doc-consistency-check.ts`
54
+ - **Biome Configuration**: Excluded lab/legacy scripts from linting to focus on core code quality
55
+ - **Branch Protection**: Added local pre-commit hook to prevent direct commits to main branch
56
+
57
+ ### Added
58
+ - **Documentation**: Comprehensive README files added throughout codebase (`src/`, `scripts/`, `src/cli/`, `src/config/`, `src/daemon/`, `src/resonance/services/`, `src/resonance/types/`, `src/types/`, `src/utils/`)
59
+ - **Development Tooling**: Pre-commit hook script for local branch protection
60
+
61
+ ## [1.0.35] - 2026-01-09
62
+
63
+ ### Changed
64
+ - **Version Bump**: Minor version increment for release preparation
65
+
66
+ ## [1.0.34] - 2026-01-09
67
+
68
+ ### Changed
69
+ - **Code Quality**: Applied Biome formatting and lint fixes across the entire codebase to improve consistency and maintainability.
70
+
71
+ ## [1.0.32] - 2026-01-09
72
+
73
+ ### Fixed
74
+ - **CLI**: `setup-mcp` now correctly includes the `--cwd` flag in the generated JSON config. This prevents `EROFS` (read-only file system) errors when the MCP server is launched by clients (like Claude Desktop or Antigravity) that might use a read-only root as the working directory. It forces the server to run in the user's project root where it has write permissions for logs and databases.
75
+
76
+ ## [1.0.31] - 2026-01-09
77
+
78
+ ### Fixed
79
+ - **Publishing**: Included `tsconfig.json` in the published package files. This ensures that global installations (via `npm` or `bun`) can correctly resolve path aliases (e.g., `@src/`) when running the CLI or MCP server.
80
+ - **CLI**: Improved CWD handling when running from system root.
81
+
82
+ ## [1.0.30] - 2026-01-09
83
+
84
+ ### Security
85
+ - **Dependabot**: Updated `@modelcontextprotocol/sdk` to `1.25.2` to resolve ReDoS vulnerability (GHSA-8r9q-7v3j-jr4g).
86
+
87
+ ## [1.0.29] - 2026-01-09
88
+
89
+ ### Added
90
+ - **Phase 5: Autonomous Research & Recursive Discovery (FAFCAS)**: Implemented a multi-step "Internal Monologue" research agent.
91
+ - **Discovery Loop**: Iterative SEARCH → READ → EXPLORE → ANALYZE cycles.
92
+ - **Topological Discovery**: Hub-aware entry points using PageRank and Betweenness Centrality.
93
+ - **EXPLORE Action**: Physical graph neighborhood traversal for non-semantic lead discovery.
94
+ - **Chain Verification**: Autonomous "AMALFA Auditor" that double-checks research findings for truthfulness.
95
+ - **Robust JSON Recovery**: Defensive parsing to handle non-compliant LLM outputs.
96
+ - **Phase 4: Topological Intelligence**: Integrated structural link prediction into the gardening loop.
97
+ - **Adamic-Adar Index**: Implemented topological relationship scoring in `GraphEngine`.
98
+ - **Structural Gap Detection**: 2-hop shared neighbor analysis to find "missing links."
99
+ - **Phase 3 (Chronos) Completion**: Advanced "Timeline Weaving" and temporal grounding verified.
100
+ - **Cross-Corpus Readiness**: Infrastructure for multi-repo research initiated.
101
+
102
+ ### Changed
103
+ - **Architectural Refactor**: decoupled `sonar-agent.ts` daemon from task logic.
104
+ - **Modular Task Handlers**: Synthesis, Timeline, Garden, and Research logic moved to `sonar-logic.ts`.
105
+ - **Bun-Native Async I/O**: Switched to `Bun.write` and `fs/promises` for all task processing and reporting.
106
+ - **Strict Type Safety**: Replaced `any` assertions with explicit API request interfaces.
107
+
108
+ ## [1.0.28] - 2026-01-08
109
+
110
+ ### Added
111
+ - **OpenRouter Cloud Integration**: New `sonar.cloud` config with `openrouter` provider for accessing cloud LLMs
112
+ - **Dev-Cloud/Prod-Local Strategy**: Test with large cloud models, deploy with smaller local ones
113
+ - **Model Strategy Guide**: New `docs/guides/model-strategy.md` documentation
114
+ - **RAG Pipeline**: Vector search now augments chat context for grounded responses
115
+ - **ENV API Key**: `OPENROUTER_API_KEY` read from `.env` for secure credential handling
116
+
117
+ ### Changed
118
+ - **Tiered Model Strategy**: Research tasks use cloud config, quick tasks use local `qwen2.5:1.5b`
119
+ - **Expanded Ingestion Sources**: Root markdown files now included in knowledge graph
120
+ - **Model Priority**: Updated to prioritize `qwen2.5:1.5b` as default local model
121
+
122
+ ### Removed
123
+ - Cleaned up unused Ollama models: `tinydolphin`, `tinyllama`, `phi3`, `functiongemma`, `nomic-embed-text`, `llama3.1:8b`, `mistral:7b-instruct`
124
+
125
+
126
+ ### Added
127
+ - **Staleness Detection**: `amalfa stats` now warns (`⚠️ STALE`) if source files are newer than the database.
128
+ - **JSON Mode (GBNF)**: Sonar Agent now enforces valid JSON output for `tinydolphin` compatibility.
129
+ - **Phi3 Sub-Agent**: Robust daemon (`amalfa phi3`) managing local LLM interactions for chat and analysis.
130
+ - **Search Intelligence**: New endpoints `/search/analyze`, `/search/rerank`, `/search/context`.
131
+ - **Metadata Enhancement**: AI-powered document enrichment via `/metadata/enhance` connected to ResonanceDB.
132
+ - **CLI Tooling**:
133
+ - `amalfa phi3 chat` (Interactive chat with real-time feedback)
134
+ - `amalfa phi3 status` (Rich diagnostics)
135
+ - `amalfa enhance` (Batch/Single doc enhancement)
136
+ - **FAFCAS Optimization**: Prioritized `tinydolphin` (1.1B) model for instant CPU inference.
137
+ - **OH-104 Pinch Check**: Physical file verification after WAL checkpoint to prevent silent corruption
138
+ - Test script `scripts/verify/test-hardening.ts` for validating resilience improvements
139
+
140
+ ### Changed
141
+ - **Sonar Refactor**: Renamed "Phi3" sub-agent to "Sonar Agent" (daemon, CLI, config) for better naming.
142
+ - **Default Model**: Switched from `phi3` to `tinydolphin` for vastly improved local performance.
143
+ - Hardened ingestion pipeline with explicit file size checks after database checkpoints
144
+ - Enhanced MCP gardening tool with tag deduplication logic
145
+
146
+ ## [1.0.19] - 2026-01-07
147
+
148
+ ### Fixed
149
+ - Version reporting: CLI now reads version from `package.json` instead of hardcoded value, ensuring single source of truth
150
+ - Added missing `validate-config` script to package.json for pre-publish checks
151
+
152
+ ### Documentation
153
+ - Added pre-publish checklist to prevent release issues
154
+
155
+ ## [1.0.18] - 2026-01-07
156
+
157
+ ### Added
158
+ - **Configurable notifications**: New `watch.notifications` config option to enable/disable desktop notifications from the daemon
159
+ - Comprehensive documentation for notification settings in example config
160
+
161
+ ### Changed
162
+ - **Cache consolidation**: Moved ML model cache from `.resonance/cache` to `.amalfa/cache` for cleaner project structure
163
+ - All runtime artifacts now in single `.amalfa/` directory (database, logs, PIDs, cache)
164
+ - Updated `.gitignore` and `.npmignore` to reflect new cache location
165
+
166
+ ### Fixed
167
+ - Removed legacy `.resonance/` folder - single source of truth for runtime artifacts
168
+ - Cache directory auto-creates on first use with proper error handling
169
+
170
+ ### Documentation
171
+ - Added brief and debrief for cache consolidation implementation
172
+ - Updated example config with notification settings
173
+ - Clarified single `.amalfa/` directory structure in docs
174
+
175
+ ## [1.0.17] - 2026-01-07
176
+
177
+ ### Added
178
+ - Added `briefs/` folder to watched sources
179
+ - Comprehensive test suite improvements
180
+
181
+ ### Fixed
182
+ - EdgeWeaver tests: Added `getRawDb()` mock for LouvainGate compatibility
183
+ - DatabaseFactory tests: Corrected parameter order for `connectToResonance()`
184
+ - Updated verify scripts with correct DatabaseFactory parameters
185
+
186
+ ### Removed
187
+ - Removed unnecessary tests: `olmo_parsing.test.ts`, `schema.test.ts` (outdated after v6 migration)
188
+ - Skipped daemon integration tests that require full infrastructure
189
+
190
+ ### Testing
191
+ - All core tests passing: 18 pass, 5 skip, 0 fail
192
+ - Database validation passing
193
+ - Deterministic ingestion verified (tear down and rebuild test)
194
+
195
+ ## [1.0.16] - Previous Release
196
+
197
+ Initial stable release with MCP server, daemon, and vector search capabilities.
198
+
199
+ ---
200
+
201
+ **Note**: For full details on each release, see the git commit history and associated debrief documents.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amalfa",
3
- "version": "1.0.38",
3
+ "version": "1.0.40",
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",
@@ -18,6 +18,7 @@
18
18
  "src",
19
19
  "tsconfig.json",
20
20
  "README.md",
21
+ "CHANGELOG.md",
21
22
  "LICENSE"
22
23
  ],
23
24
  "keywords": [
package/src/cli.ts CHANGED
@@ -53,6 +53,7 @@ Commands:
53
53
  ember <action> Manage Ember enrichment service (scan|squash)
54
54
  scripts list List available scripts and their descriptions
55
55
  servers [--dot] Show status of all AMALFA services (--dot for graph)
56
+ stop-all (kill) Stop all running AMALFA services
56
57
 
57
58
  Options:
58
59
  --force Override pre-flight warnings (errors still block)
@@ -738,6 +739,63 @@ async function cmdServers() {
738
739
  );
739
740
  }
740
741
 
742
+ async function cmdStopAll() {
743
+ console.log("🛑 Stopping ALL Amalfa Services...\n");
744
+
745
+ // We reuse the service definitions from cmdServers logic,
746
+ // but abstracted slightly or duplicated for simplicity since they are inside cmdServers
747
+ const { AMALFA_DIRS } = await import("./config/defaults");
748
+ const { join } = await import("node:path");
749
+ const { existsSync, readFileSync, unlinkSync } = await import("node:fs");
750
+
751
+ const SERVICES = [
752
+ {
753
+ name: "Vector Daemon",
754
+ pidFile: join(AMALFA_DIRS.runtime, "vector-daemon.pid"),
755
+ },
756
+ { name: "File Watcher", pidFile: join(AMALFA_DIRS.runtime, "daemon.pid") },
757
+ { name: "Sonar Agent", pidFile: join(AMALFA_DIRS.runtime, "sonar.pid") },
758
+ // MCP usually runs as stdio, but if we track a PID file for it:
759
+ { name: "MCP Server", pidFile: join(AMALFA_DIRS.runtime, "mcp.pid") },
760
+ ];
761
+
762
+ let stoppedCount = 0;
763
+
764
+ for (const svc of SERVICES) {
765
+ if (existsSync(svc.pidFile)) {
766
+ try {
767
+ const pidStr = readFileSync(svc.pidFile, "utf-8").trim();
768
+ const pid = Number.parseInt(pidStr, 10);
769
+
770
+ if (!Number.isNaN(pid)) {
771
+ // Check if running
772
+ try {
773
+ process.kill(pid, 0); // Check existence
774
+ process.kill(pid, "SIGTERM");
775
+ console.log(`✅ Sent SIGTERM to ${svc.name} (PID: ${pid})`);
776
+ stoppedCount++;
777
+ } catch {
778
+ // Not running, just stale
779
+ console.log(`🧹 Cleaning stale PID file for ${svc.name}`);
780
+ }
781
+ }
782
+ } catch (e) {
783
+ console.warn(`⚠️ Failed to stop ${svc.name}:`, e);
784
+ }
785
+ // Always clean up PID file
786
+ try {
787
+ unlinkSync(svc.pidFile);
788
+ } catch {}
789
+ }
790
+ }
791
+
792
+ if (stoppedCount === 0) {
793
+ console.log("✨ No active services found.");
794
+ } else {
795
+ console.log(`\n✅ Stopped ${stoppedCount} service(s).`);
796
+ }
797
+ }
798
+
741
799
  async function cmdValidate() {
742
800
  console.log("🛡️ AMALFA Database Validation\n");
743
801
 
@@ -1002,6 +1060,11 @@ async function main() {
1002
1060
  await cmdServers();
1003
1061
  break;
1004
1062
 
1063
+ case "stop-all":
1064
+ case "kill":
1065
+ await cmdStopAll();
1066
+ break;
1067
+
1005
1068
  case "sonar":
1006
1069
  await cmdSonar();
1007
1070
  break;
@@ -44,6 +44,8 @@ export function initAmalfaDirs(): void {
44
44
  }
45
45
  }
46
46
 
47
+ import type { EmberConfig } from "@src/ember/types";
48
+
47
49
  export interface AmalfaConfig {
48
50
  /** @deprecated Use sources array instead */
49
51
  source?: string;
@@ -77,6 +79,8 @@ export interface AmalfaConfig {
77
79
  sonar: SonarConfig;
78
80
  /** @deprecated Use sonar instead */
79
81
  phi3?: SonarConfig;
82
+ /** Ember automated enrichment configuration */
83
+ ember: EmberConfig;
80
84
  }
81
85
 
82
86
  export interface SonarConfig {
@@ -142,12 +146,18 @@ export const DEFAULT_CONFIG: AmalfaConfig = {
142
146
  model: "BAAI/bge-small-en-v1.5",
143
147
  dimensions: 384,
144
148
  },
149
+ ember: {
150
+ enabled: true,
151
+ minConfidence: 0.8,
152
+ autoSquash: false,
153
+ backupDir: ".amalfa/backups/ember",
154
+ },
145
155
  watch: {
146
156
  enabled: true,
147
157
  debounce: 1000,
148
158
  notifications: true,
149
159
  },
150
- excludePatterns: ["node_modules", ".git", ".amalfa"],
160
+ excludePatterns: ["node_modules", ".git", ".amalfa", "tests"],
151
161
  // Optional graph tuning (for advanced use)
152
162
  graph: {
153
163
  tuning: {
@@ -276,6 +286,10 @@ export async function loadConfig(): Promise<AmalfaConfig> {
276
286
  },
277
287
  },
278
288
  } as SonarConfig,
289
+ ember: {
290
+ ...DEFAULT_CONFIG.ember,
291
+ ...(userConfig.ember || {}),
292
+ },
279
293
  };
280
294
 
281
295
  // Normalize: Convert legacy 'source' to 'sources' array
@@ -12,6 +12,7 @@ import {
12
12
  type AmalfaConfig,
13
13
  loadConfig,
14
14
  } from "@src/config/defaults";
15
+ import { EmberService } from "@src/ember";
15
16
  import { AmalfaIngestor } from "@src/pipeline/AmalfaIngestor";
16
17
  import { ResonanceDB } from "@src/resonance/db";
17
18
  import { getLogger } from "@src/utils/Logger";
@@ -157,6 +158,32 @@ function triggerIngestion(debounceMs: number) {
157
158
  // For now, we'll re-run full ingestion (hash checking prevents duplicates)
158
159
  await ingestor.ingest();
159
160
 
161
+ // --- EMBER INTEGRATION ---
162
+ if (config.ember?.enabled) {
163
+ log.info("🔥 Running Ember Analysis...");
164
+ const ember = new EmberService(db, config.ember);
165
+ let enrichedCount = 0;
166
+
167
+ // Analyze changed files only
168
+ // Note: Reading again from disk is safer than passing content from ingestor for now
169
+ for (const file of batch) {
170
+ try {
171
+ const content = await Bun.file(file).text();
172
+ const sidecar = await ember.analyze(file, content);
173
+ if (sidecar) {
174
+ await ember.generate(sidecar);
175
+ enrichedCount++;
176
+ }
177
+ } catch (err) {
178
+ log.warn({ file, err }, "Failed to analyze with Ember");
179
+ }
180
+ }
181
+ if (enrichedCount > 0) {
182
+ log.info({ enrichedCount }, "🔥 Ember enriched files");
183
+ }
184
+ }
185
+ // -------------------------
186
+
160
187
  db.close();
161
188
 
162
189
  log.info({ files: batchSize }, "✅ Update complete");
@@ -5,7 +5,7 @@ import { Glob } from "bun";
5
5
  import { EmberAnalyzer } from "./analyzer";
6
6
  import { EmberGenerator } from "./generator";
7
7
  import { EmberSquasher } from "./squasher";
8
- import type { EmberConfig } from "./types";
8
+ import type { EmberConfig, EmberSidecar } from "./types";
9
9
 
10
10
  export class EmberService {
11
11
  private analyzer: EmberAnalyzer;
@@ -50,6 +50,20 @@ export class EmberService {
50
50
  return enrichedCount;
51
51
  }
52
52
 
53
+ /**
54
+ * Analyze a single file
55
+ */
56
+ async analyze(filePath: string, content: string) {
57
+ return this.analyzer.analyze(filePath, content);
58
+ }
59
+
60
+ /**
61
+ * Generate a sidecar file
62
+ */
63
+ async generate(sidecar: EmberSidecar) {
64
+ return this.generator.generate(sidecar);
65
+ }
66
+
53
67
  /**
54
68
  * Squash all pending sidecars
55
69
  */
@@ -71,8 +85,9 @@ export class EmberService {
71
85
  private async findSidecars(): Promise<string[]> {
72
86
  const sidecars: string[] = [];
73
87
  const glob = new Glob("**/*.ember.json");
88
+ const sources = this.config.sources || ["./docs"];
74
89
  // Scan sources
75
- for (const source of this.config.sources) {
90
+ for (const source of sources) {
76
91
  // Assuming source is like "./docs"
77
92
  const sourcePath = join(process.cwd(), source);
78
93
  for (const file of glob.scanSync({ cwd: sourcePath })) {
@@ -85,14 +100,14 @@ export class EmberService {
85
100
  private async discoverFiles(): Promise<string[]> {
86
101
  const files: string[] = [];
87
102
  const glob = new Glob("**/*.{md,mdx}"); // Only markdown for now
103
+ const sources = this.config.sources || ["./docs"];
104
+ const excludes = this.config.excludePatterns || [];
88
105
 
89
- for (const source of this.config.sources) {
106
+ for (const source of sources) {
90
107
  const sourcePath = join(process.cwd(), source);
91
108
  try {
92
109
  for (const file of glob.scanSync({ cwd: sourcePath })) {
93
- const shouldExclude = this.config.excludePatterns.some((p) =>
94
- file.includes(p),
95
- );
110
+ const shouldExclude = excludes.some((p) => file.includes(p));
96
111
  if (!shouldExclude) {
97
112
  files.push(join(sourcePath, file));
98
113
  }
@@ -17,10 +17,11 @@ export interface EmberSidecar {
17
17
 
18
18
  export interface EmberConfig {
19
19
  enabled: boolean;
20
- sources: string[];
20
+ sources?: string[];
21
21
  minConfidence: number;
22
22
  backupDir: string;
23
- excludePatterns: string[];
23
+ excludePatterns?: string[];
24
+ autoSquash?: boolean;
24
25
  }
25
26
 
26
27
  export type EnrichmentType = "tag" | "link" | "summary" | "metadata";