harper-kb 0.2.0

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.
Files changed (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +288 -0
  3. package/config.yaml +13 -0
  4. package/dist/core/embeddings.d.ts +31 -0
  5. package/dist/core/embeddings.d.ts.map +1 -0
  6. package/dist/core/embeddings.js +199 -0
  7. package/dist/core/embeddings.js.map +1 -0
  8. package/dist/core/entries.d.ts +101 -0
  9. package/dist/core/entries.d.ts.map +1 -0
  10. package/dist/core/entries.js +304 -0
  11. package/dist/core/entries.js.map +1 -0
  12. package/dist/core/history.d.ts +31 -0
  13. package/dist/core/history.d.ts.map +1 -0
  14. package/dist/core/history.js +119 -0
  15. package/dist/core/history.js.map +1 -0
  16. package/dist/core/knowledge-base.d.ts +49 -0
  17. package/dist/core/knowledge-base.d.ts.map +1 -0
  18. package/dist/core/knowledge-base.js +117 -0
  19. package/dist/core/knowledge-base.js.map +1 -0
  20. package/dist/core/search.d.ts +34 -0
  21. package/dist/core/search.d.ts.map +1 -0
  22. package/dist/core/search.js +327 -0
  23. package/dist/core/search.js.map +1 -0
  24. package/dist/core/tags.d.ts +39 -0
  25. package/dist/core/tags.d.ts.map +1 -0
  26. package/dist/core/tags.js +97 -0
  27. package/dist/core/tags.js.map +1 -0
  28. package/dist/core/triage.d.ts +61 -0
  29. package/dist/core/triage.d.ts.map +1 -0
  30. package/dist/core/triage.js +136 -0
  31. package/dist/core/triage.js.map +1 -0
  32. package/dist/core/webhook-endpoints.d.ts +46 -0
  33. package/dist/core/webhook-endpoints.d.ts.map +1 -0
  34. package/dist/core/webhook-endpoints.js +85 -0
  35. package/dist/core/webhook-endpoints.js.map +1 -0
  36. package/dist/hooks.d.ts +67 -0
  37. package/dist/hooks.d.ts.map +1 -0
  38. package/dist/hooks.js +53 -0
  39. package/dist/hooks.js.map +1 -0
  40. package/dist/http-utils.d.ts +38 -0
  41. package/dist/http-utils.d.ts.map +1 -0
  42. package/dist/http-utils.js +133 -0
  43. package/dist/http-utils.js.map +1 -0
  44. package/dist/index.d.ts +27 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +78 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/mcp/protocol.d.ts +25 -0
  49. package/dist/mcp/protocol.d.ts.map +1 -0
  50. package/dist/mcp/protocol.js +105 -0
  51. package/dist/mcp/protocol.js.map +1 -0
  52. package/dist/mcp/server.d.ts +28 -0
  53. package/dist/mcp/server.d.ts.map +1 -0
  54. package/dist/mcp/server.js +144 -0
  55. package/dist/mcp/server.js.map +1 -0
  56. package/dist/mcp/tools.d.ts +26 -0
  57. package/dist/mcp/tools.d.ts.map +1 -0
  58. package/dist/mcp/tools.js +706 -0
  59. package/dist/mcp/tools.js.map +1 -0
  60. package/dist/oauth/authorize.d.ts +28 -0
  61. package/dist/oauth/authorize.d.ts.map +1 -0
  62. package/dist/oauth/authorize.js +421 -0
  63. package/dist/oauth/authorize.js.map +1 -0
  64. package/dist/oauth/init.d.ts +18 -0
  65. package/dist/oauth/init.d.ts.map +1 -0
  66. package/dist/oauth/init.js +30 -0
  67. package/dist/oauth/init.js.map +1 -0
  68. package/dist/oauth/keys.d.ts +34 -0
  69. package/dist/oauth/keys.d.ts.map +1 -0
  70. package/dist/oauth/keys.js +101 -0
  71. package/dist/oauth/keys.js.map +1 -0
  72. package/dist/oauth/metadata.d.ts +23 -0
  73. package/dist/oauth/metadata.d.ts.map +1 -0
  74. package/dist/oauth/metadata.js +57 -0
  75. package/dist/oauth/metadata.js.map +1 -0
  76. package/dist/oauth/middleware.d.ts +23 -0
  77. package/dist/oauth/middleware.d.ts.map +1 -0
  78. package/dist/oauth/middleware.js +65 -0
  79. package/dist/oauth/middleware.js.map +1 -0
  80. package/dist/oauth/register.d.ts +15 -0
  81. package/dist/oauth/register.d.ts.map +1 -0
  82. package/dist/oauth/register.js +78 -0
  83. package/dist/oauth/register.js.map +1 -0
  84. package/dist/oauth/token.d.ts +16 -0
  85. package/dist/oauth/token.d.ts.map +1 -0
  86. package/dist/oauth/token.js +184 -0
  87. package/dist/oauth/token.js.map +1 -0
  88. package/dist/oauth/validate.d.ts +40 -0
  89. package/dist/oauth/validate.d.ts.map +1 -0
  90. package/dist/oauth/validate.js +61 -0
  91. package/dist/oauth/validate.js.map +1 -0
  92. package/dist/resources/HistoryResource.d.ts +41 -0
  93. package/dist/resources/HistoryResource.d.ts.map +1 -0
  94. package/dist/resources/HistoryResource.js +61 -0
  95. package/dist/resources/HistoryResource.js.map +1 -0
  96. package/dist/resources/KnowledgeBaseResource.d.ts +60 -0
  97. package/dist/resources/KnowledgeBaseResource.d.ts.map +1 -0
  98. package/dist/resources/KnowledgeBaseResource.js +118 -0
  99. package/dist/resources/KnowledgeBaseResource.js.map +1 -0
  100. package/dist/resources/KnowledgeEntryResource.d.ts +61 -0
  101. package/dist/resources/KnowledgeEntryResource.d.ts.map +1 -0
  102. package/dist/resources/KnowledgeEntryResource.js +191 -0
  103. package/dist/resources/KnowledgeEntryResource.js.map +1 -0
  104. package/dist/resources/MeResource.d.ts +31 -0
  105. package/dist/resources/MeResource.d.ts.map +1 -0
  106. package/dist/resources/MeResource.js +40 -0
  107. package/dist/resources/MeResource.js.map +1 -0
  108. package/dist/resources/QueryLogResource.d.ts +22 -0
  109. package/dist/resources/QueryLogResource.d.ts.map +1 -0
  110. package/dist/resources/QueryLogResource.js +66 -0
  111. package/dist/resources/QueryLogResource.js.map +1 -0
  112. package/dist/resources/ServiceKeyResource.d.ts +52 -0
  113. package/dist/resources/ServiceKeyResource.d.ts.map +1 -0
  114. package/dist/resources/ServiceKeyResource.js +151 -0
  115. package/dist/resources/ServiceKeyResource.js.map +1 -0
  116. package/dist/resources/TagResource.d.ts +27 -0
  117. package/dist/resources/TagResource.d.ts.map +1 -0
  118. package/dist/resources/TagResource.js +41 -0
  119. package/dist/resources/TagResource.js.map +1 -0
  120. package/dist/resources/TriageResource.d.ts +53 -0
  121. package/dist/resources/TriageResource.d.ts.map +1 -0
  122. package/dist/resources/TriageResource.js +120 -0
  123. package/dist/resources/TriageResource.js.map +1 -0
  124. package/dist/resources/WebhookEndpointResource.d.ts +63 -0
  125. package/dist/resources/WebhookEndpointResource.d.ts.map +1 -0
  126. package/dist/resources/WebhookEndpointResource.js +115 -0
  127. package/dist/resources/WebhookEndpointResource.js.map +1 -0
  128. package/dist/types.d.ts +378 -0
  129. package/dist/types.d.ts.map +1 -0
  130. package/dist/types.js +8 -0
  131. package/dist/types.js.map +1 -0
  132. package/dist/webhooks/github.d.ts +25 -0
  133. package/dist/webhooks/github.d.ts.map +1 -0
  134. package/dist/webhooks/github.js +165 -0
  135. package/dist/webhooks/github.js.map +1 -0
  136. package/dist/webhooks/middleware.d.ts +19 -0
  137. package/dist/webhooks/middleware.d.ts.map +1 -0
  138. package/dist/webhooks/middleware.js +144 -0
  139. package/dist/webhooks/middleware.js.map +1 -0
  140. package/dist/webhooks/types.d.ts +18 -0
  141. package/dist/webhooks/types.d.ts.map +1 -0
  142. package/dist/webhooks/types.js +5 -0
  143. package/dist/webhooks/types.js.map +1 -0
  144. package/package.json +69 -0
  145. package/schema/knowledge.graphql +136 -0
  146. package/schema/oauth.graphql +45 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nathan Heskew
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,288 @@
1
+ # harper-kb
2
+
3
+ Knowledge base for [Harper](https://harper.fast/), built on Harper, with MCP server integration.
4
+
5
+ A Harper plugin that provides searchable, scoped knowledge entries with vector embeddings for semantic search. Exposes a REST API and MCP endpoint.
6
+
7
+ ## Consumers
8
+
9
+ - **Support team** — finding solutions, patterns, gotchas, customer edge cases
10
+ - **DX lab "Harper expert"** — backing knowledge for the AI expert role in Gas Town labs
11
+ - **Claude Code / IDE assistants** — Harper context via MCP without per-project CLAUDE.md files
12
+ - **Any MCP client** — Cursor, VS Code + Copilot, JetBrains, ChatGPT, Gemini, etc.
13
+
14
+ ## Quick Start
15
+
16
+ ### Prerequisites
17
+
18
+ - [Harper](https://harper.fast/) >= 4.7.0
19
+ - Node.js >= 22
20
+
21
+ ### Install
22
+
23
+ ```bash
24
+ npm install harper-kb
25
+ ```
26
+
27
+ ### Configure
28
+
29
+ Add to your application's `config.yaml`:
30
+
31
+ ```yaml
32
+ 'harper-kb':
33
+ package: 'harper-kb'
34
+ embeddingModel: nomic-embed-text # default
35
+ ```
36
+
37
+ ### Run
38
+
39
+ ```bash
40
+ harperdb dev .
41
+ ```
42
+
43
+ ## Embeddings
44
+
45
+ Vector embeddings for semantic search run locally on CPU using [Nomic](https://huggingface.co/nomic-ai) embedding models via llama.cpp. Two backends are supported:
46
+
47
+ | Backend | Install | Use case |
48
+ | ------------------------------------------------------------------------------ | ------------------------------------ | ---------------------------------------- |
49
+ | [harper-fabric-embeddings](https://github.com/heskew/harper-fabric-embeddings) | Optional dependency (auto-installed) | Production on Fabric (linux-x64, ~19 MB) |
50
+ | [node-llama-cpp](https://github.com/withcatai/node-llama-cpp) | `npm install node-llama-cpp` | Local development on any platform |
51
+
52
+ The plugin tries `harper-fabric-embeddings` first and falls back to `node-llama-cpp`. If neither is available, semantic search is skipped and keyword search still works.
53
+
54
+ ### Models
55
+
56
+ | Config key | Model | Parameters | Dimensions |
57
+ | ---------------------------- | -------------------------------------------------------------------------------------------- | ---------- | ---------- |
58
+ | `nomic-embed-text` (default) | [nomic-embed-text-v1.5-GGUF](https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF) | 137M | 768 |
59
+ | `nomic-embed-text-v2-moe` | [nomic-embed-text-v2-moe-GGUF](https://huggingface.co/nomic-ai/nomic-embed-text-v2-moe-GGUF) | 475M (MoE) | 768 |
60
+
61
+ ```yaml
62
+ 'harper-kb':
63
+ package: 'harper-kb'
64
+ embeddingModel: nomic-embed-text # v1.5 (default)
65
+ # embeddingModel: nomic-embed-text-v2-moe # v2 MoE — better quality, larger
66
+ ```
67
+
68
+ ## Architecture
69
+
70
+ ```
71
+ harper-kb
72
+ ├── src/
73
+ │ ├── index.ts ← plugin entry: handleApplication()
74
+ │ ├── hooks.ts ← extensibility hooks (onAccessCheck, loginPath)
75
+ │ ├── http-utils.ts ← request body reading, header helpers
76
+ │ ├── types.ts ← shared types + Harper global declarations
77
+ │ ├── core/ ← shared logic
78
+ │ │ ├── embeddings.ts ← model download, init, vector generation
79
+ │ │ ├── entries.ts ← CRUD + relationship management
80
+ │ │ ├── history.ts ← edit history audit log
81
+ │ │ ├── knowledge-base.ts ← KB registry (multi-tenant)
82
+ │ │ ├── search.ts ← keyword / semantic / hybrid search
83
+ │ │ ├── tags.ts ← tag registry with counts
84
+ │ │ ├── triage.ts ← webhook intake queue
85
+ │ │ └── webhook-endpoints.ts ← webhook secret management
86
+ │ ├── resources/ ← REST Resource classes
87
+ │ │ ├── HistoryResource.ts
88
+ │ │ ├── KnowledgeBaseResource.ts
89
+ │ │ ├── KnowledgeEntryResource.ts
90
+ │ │ ├── MeResource.ts
91
+ │ │ ├── QueryLogResource.ts
92
+ │ │ ├── ServiceKeyResource.ts
93
+ │ │ ├── TagResource.ts
94
+ │ │ ├── TriageResource.ts
95
+ │ │ └── WebhookEndpointResource.ts
96
+ │ ├── mcp/ ← MCP server (JSON-RPC over HTTP)
97
+ │ │ ├── protocol.ts ← JSON-RPC dispatcher
98
+ │ │ ├── server.ts ← HTTP middleware (auth, KB scoping)
99
+ │ │ └── tools.ts ← tool definitions + handlers
100
+ │ ├── oauth/ ← OAuth 2.1 authorization server
101
+ │ │ ├── authorize.ts
102
+ │ │ ├── init.ts
103
+ │ │ ├── keys.ts
104
+ │ │ ├── metadata.ts
105
+ │ │ ├── middleware.ts
106
+ │ │ ├── register.ts
107
+ │ │ ├── token.ts
108
+ │ │ └── validate.ts
109
+ │ └── webhooks/ ← webhook intake (GitHub)
110
+ │ ├── github.ts
111
+ │ ├── middleware.ts
112
+ │ └── types.ts
113
+ ├── schema/
114
+ │ ├── knowledge.graphql ← table definitions (database: "kb")
115
+ │ └── oauth.graphql ← OAuth tables
116
+ ├── config.yaml
117
+ ├── package.json
118
+ └── test/
119
+ ```
120
+
121
+ Both REST and MCP run in the Harper process, both call the same core functions with zero overhead.
122
+
123
+ ## REST API
124
+
125
+ | Endpoint | Method | Auth | Description |
126
+ | ----------------------- | --------------- | ---------- | ------------------------- |
127
+ | `/KnowledgeBase/` | GET | Public | List knowledge bases |
128
+ | `/KnowledgeBase/<id>` | GET | Public | Get KB by ID |
129
+ | `/KnowledgeBase/` | POST/PUT/DELETE | Team | Manage knowledge bases |
130
+ | `/Knowledge/<id>` | GET | Public | Get entry by ID |
131
+ | `/Knowledge/?query=...` | GET | Public | Search entries |
132
+ | `/Knowledge/` | POST | Required | Create entry |
133
+ | `/Knowledge/<id>` | PUT | Required | Update entry |
134
+ | `/Knowledge/<id>` | DELETE | Team | Deprecate entry |
135
+ | `/KnowledgeTag/` | GET | Public | List all tags |
136
+ | `/Triage/` | GET | Team | List pending triage items |
137
+ | `/Triage/` | POST | Service/AI | Submit triage item |
138
+ | `/Triage/<id>` | PUT | Team | Process triage item |
139
+ | `/QueryLog/` | GET | Team | Search analytics |
140
+ | `/ServiceKey/` | GET/POST/DELETE | Team | API key management |
141
+ | `/WebhookEndpoint/` | GET/POST/DELETE | Team | Webhook endpoint secrets |
142
+ | `/History/<entryId>` | GET | Public | Edit history for an entry |
143
+ | `/Me/` | GET | Public | Current user/session info |
144
+
145
+ ### Search Parameters
146
+
147
+ ```
148
+ GET /Knowledge/?query=MQTT+auth&tags=mqtt,config&limit=10&mode=keyword&context={"harper":"5.0","storageEngine":"lmdb"}
149
+ ```
150
+
151
+ - `query` — search text (required)
152
+ - `tags` — comma-separated tag filter
153
+ - `limit` — max results (default 10)
154
+ - `mode` — `keyword`, `semantic`, or `hybrid` (default)
155
+ - `context` — JSON applicability context for result boosting
156
+
157
+ ## MCP Endpoint
158
+
159
+ Each knowledge base gets its own MCP endpoint at `/mcp/<kbId>`. Connect any MCP-compatible client:
160
+
161
+ ```json
162
+ {
163
+ "mcpServers": {
164
+ "harper-kb": {
165
+ "url": "https://kb.harper.fast:9926/mcp/my-kb-id"
166
+ }
167
+ }
168
+ }
169
+ ```
170
+
171
+ ### Tools
172
+
173
+ | Tool | Description |
174
+ | --------------------- | ----------------------------------------------------------------- |
175
+ | `knowledge_search` | Search with keyword/semantic/hybrid modes + applicability context |
176
+ | `knowledge_add` | Add a new entry (auto-tagged `ai-generated`) |
177
+ | `knowledge_get` | Get entry by ID with full relationship chain |
178
+ | `knowledge_update` | Update an entry with edit history tracking |
179
+ | `knowledge_related` | Find related entries (explicit + semantic similarity) |
180
+ | `knowledge_list_tags` | List all tags with counts |
181
+ | `knowledge_triage` | Submit to triage queue for review |
182
+ | `knowledge_history` | Get edit history for an entry (who changed what, when, why) |
183
+ | `knowledge_reindex` | Backfill missing embeddings |
184
+ | `knowledge_link` | Create related/sibling relationships between entries |
185
+
186
+ ## Schema
187
+
188
+ Tables in the `kb` database:
189
+
190
+ - **KnowledgeBase** — KB registry (multi-tenant)
191
+ - **KnowledgeEntry** — core entries with HNSW vector index, `@relationship` directives for supersession/siblings/related, `@createdTime`/`@updatedTime`
192
+ - **KnowledgeEntryEdit** — append-only edit history audit log
193
+ - **TriageItem** — webhook intake queue (7-day TTL)
194
+ - **KnowledgeTag** — tag name as primary key with entry counts
195
+ - **QueryLog** — search analytics (30-day TTL)
196
+ - **ServiceKey** — API keys with scrypt-hashed secrets
197
+ - **WebhookEndpoint** — per-KB webhook secrets
198
+ - **WebhookDelivery** — delivery ID dedup across workers (1-hour TTL)
199
+ - **OAuthClient** — dynamic client registrations (RFC 7591)
200
+ - **OAuthCode** — authorization codes (5-minute TTL)
201
+ - **OAuthRefreshToken** — refresh tokens (30-day TTL)
202
+ - **OAuthSigningKey** — RSA key pair for JWT signing
203
+
204
+ ### Applicability Scoping
205
+
206
+ Entries carry an `appliesTo` scope:
207
+
208
+ ```json
209
+ {
210
+ "harper": ">=4.0 <5.0",
211
+ "storageEngine": "lmdb",
212
+ "node": ">=22",
213
+ "platform": "linux"
214
+ }
215
+ ```
216
+
217
+ Search results are boosted or demoted (never hidden) based on the caller's context.
218
+
219
+ ### Entry Relationships
220
+
221
+ - **Supersedes** — "This replaces that for newer versions"
222
+ - **Siblings** — "Same topic, different config" (e.g., LMDB vs RocksDB behavior)
223
+ - **Related** — loose "see also" association
224
+
225
+ ## Auth Model
226
+
227
+ | Role | Read | Write | Review | Manage |
228
+ | ----------------- | ---- | ---------------------------- | ------ | ------ |
229
+ | `team` | Yes | Yes | Yes | Yes |
230
+ | `ai_agent` | Yes | Yes (flagged `ai-generated`) | No | No |
231
+ | `service_account` | Yes | Triage queue only | No | No |
232
+
233
+ MCP uses OAuth 2.1 with PKCE for authentication. MCP clients discover auth requirements via `/.well-known/oauth-protected-resource`, register dynamically, and authenticate through a browser-based login flow (GitHub OAuth primary, Harper credentials fallback). The web UI uses GitHub OAuth via `@harperfast/oauth` with Harper credentials as fallback.
234
+
235
+ ## Development
236
+
237
+ ```bash
238
+ # Build
239
+ npm run build
240
+
241
+ # Run tests (414 tests)
242
+ npm test
243
+
244
+ # Test with coverage
245
+ npm run test:coverage
246
+
247
+ # Watch mode
248
+ npm run dev
249
+
250
+ # For local semantic search, install node-llama-cpp
251
+ npm install node-llama-cpp
252
+ ```
253
+
254
+ ### Testing
255
+
256
+ Tests use Node.js built-in test runner (`node:test`) with mock Harper globals (in-memory tables). Tests run against compiled output in `dist/`.
257
+
258
+ ```bash
259
+ npm test
260
+ ```
261
+
262
+ ## Fabric Deployment
263
+
264
+ For deploying to Harper Fabric, `harper-fabric-embeddings` is installed automatically as an optional dependency — no node-llama-cpp trimming or special build steps needed.
265
+
266
+ ```dockerfile
267
+ # Dockerfile.build
268
+ FROM --platform=linux/amd64 node:22-slim AS build
269
+ WORKDIR /build
270
+
271
+ COPY package.json package-lock.json ./
272
+ RUN npm ci --omit=dev
273
+
274
+ # Remove harperdb (provided by Fabric runtime)
275
+ RUN rm -rf node_modules/harperdb node_modules/.bin/harperdb
276
+
277
+ COPY config.yaml ./
278
+ COPY .env ./
279
+
280
+ FROM --platform=linux/amd64 node:22-slim AS package
281
+ WORKDIR /out
282
+ COPY --from=build /build /out/app
283
+ RUN tar czf /out/app.tar.gz -C /out app
284
+ ```
285
+
286
+ ## License
287
+
288
+ MIT
package/config.yaml ADDED
@@ -0,0 +1,13 @@
1
+ # Knowledge Base Plugin Configuration
2
+ # This file defines the plugin entry point and default settings
3
+ # All settings can be overridden in your application's config.yaml
4
+
5
+ # Plugin entry point (required by Harper)
6
+ pluginModule: 'dist/index.js'
7
+
8
+ # GraphQL schema for knowledge base tables
9
+ graphqlSchema:
10
+ files: 'schema/*.graphql'
11
+
12
+ # Default settings (optional - these are used if not specified in app config)
13
+ embeddingModel: 'nomic-embed-text'
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Embedding Model Management
3
+ *
4
+ * Generates vector embeddings for semantic search. Supports two backends:
5
+ *
6
+ * 1. harper-fabric-embeddings — Minimal native wrapper (~19 MB).
7
+ * Preferred on Fabric. Requires a pre-staged model file.
8
+ *
9
+ * 2. node-llama-cpp — Full-featured wrapper (~250 MB+).
10
+ * Fallback for local dev. Downloads the model on first run.
11
+ *
12
+ * The backend is selected automatically: fabric-llama-embeddings is tried
13
+ * first, and node-llama-cpp is used if it's not available.
14
+ */
15
+ /**
16
+ * Initialize the embedding model.
17
+ * Tries fabric-llama-embeddings first, then falls back to node-llama-cpp.
18
+ */
19
+ export declare function initEmbeddingModel(config: {
20
+ embeddingModel: string;
21
+ componentDir: string;
22
+ }): Promise<void>;
23
+ /**
24
+ * Generate an embedding vector for the given text.
25
+ */
26
+ export declare function generateEmbedding(text: string): Promise<number[]>;
27
+ /**
28
+ * Clean up embedding model resources.
29
+ */
30
+ export declare function dispose(): Promise<void>;
31
+ //# sourceMappingURL=embeddings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../src/core/embeddings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAiCH;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBhH;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAKvE;AAED;;GAEG;AACH,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAM7C"}
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Embedding Model Management
3
+ *
4
+ * Generates vector embeddings for semantic search. Supports two backends:
5
+ *
6
+ * 1. harper-fabric-embeddings — Minimal native wrapper (~19 MB).
7
+ * Preferred on Fabric. Requires a pre-staged model file.
8
+ *
9
+ * 2. node-llama-cpp — Full-featured wrapper (~250 MB+).
10
+ * Fallback for local dev. Downloads the model on first run.
11
+ *
12
+ * The backend is selected automatically: fabric-llama-embeddings is tried
13
+ * first, and node-llama-cpp is used if it's not available.
14
+ */
15
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
16
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
17
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
18
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
19
+ });
20
+ }
21
+ return path;
22
+ };
23
+ import { writeFile, readFile, unlink, mkdir } from 'node:fs/promises';
24
+ import { existsSync } from 'node:fs';
25
+ import path from 'node:path';
26
+ let backend = null;
27
+ // ─── Model configuration ───────────────────────────────────────────────────
28
+ const MODEL_CONFIGS = {
29
+ 'nomic-embed-text': {
30
+ repo: 'nomic-ai/nomic-embed-text-v1.5-GGUF',
31
+ file: 'nomic-embed-text-v1.5.Q4_K_M.gguf',
32
+ },
33
+ 'nomic-embed-text-v2-moe': {
34
+ repo: 'nomic-ai/nomic-embed-text-v2-moe-GGUF',
35
+ file: 'nomic-embed-text-v2-moe.Q4_K_M.gguf',
36
+ },
37
+ };
38
+ // Module-level models directory, set during initEmbeddingModel
39
+ let modelsDir = null;
40
+ // ─── Public API ─────────────────────────────────────────────────────────────
41
+ /**
42
+ * Initialize the embedding model.
43
+ * Tries fabric-llama-embeddings first, then falls back to node-llama-cpp.
44
+ */
45
+ export async function initEmbeddingModel(config) {
46
+ if (backend) {
47
+ logger?.debug?.('Embedding model already initialized');
48
+ return;
49
+ }
50
+ const modelName = config.embeddingModel || 'nomic-embed-text';
51
+ modelsDir = path.join(config.componentDir, 'models');
52
+ // Try fabric-llama-embeddings first (lightweight, Fabric-optimized)
53
+ try {
54
+ backend = await initFabricBackend(modelName);
55
+ logger?.info?.(`Embedding model "${modelName}" loaded via fabric-llama-embeddings`);
56
+ return;
57
+ }
58
+ catch (err) {
59
+ logger?.debug?.('fabric-llama-embeddings not available, trying node-llama-cpp:', err.message);
60
+ }
61
+ // Fall back to node-llama-cpp (full-featured, handles downloads)
62
+ backend = await initNodeLlamaCppBackend(modelName);
63
+ logger?.info?.(`Embedding model "${modelName}" loaded via node-llama-cpp`);
64
+ }
65
+ /**
66
+ * Generate an embedding vector for the given text.
67
+ */
68
+ export async function generateEmbedding(text) {
69
+ if (!backend) {
70
+ throw new Error('Embedding model not initialized. Call initEmbeddingModel() first.');
71
+ }
72
+ return backend.generateEmbedding(text);
73
+ }
74
+ /**
75
+ * Clean up embedding model resources.
76
+ */
77
+ export async function dispose() {
78
+ if (backend) {
79
+ await backend.dispose();
80
+ backend = null;
81
+ }
82
+ logger?.info?.('Embedding model disposed');
83
+ }
84
+ // ─── fabric-llama-embeddings backend ────────────────────────────────────────
85
+ async function initFabricBackend(modelName) {
86
+ const fabricPkg = 'harper-fabric-embeddings';
87
+ const fabricModule = (await import(__rewriteRelativeImportExtension(fabricPkg)));
88
+ // Pass modelsDir so the fabric backend can find or download the model
89
+ await fabricModule.init({ modelsDir: modelsDir, modelName });
90
+ return {
91
+ generateEmbedding: (text) => fabricModule.embed(text),
92
+ dispose: () => fabricModule.dispose(),
93
+ };
94
+ }
95
+ async function initNodeLlamaCppBackend(modelName) {
96
+ const modelPath = await downloadModelIfNeeded(modelName);
97
+ // @ts-expect-error — node-llama-cpp is an optional manual install, not a declared dependency
98
+ const { getLlama } = (await import('node-llama-cpp'));
99
+ const llama = await getLlama({ progressLogs: false, build: 'never' });
100
+ const model = await llama.loadModel({ modelPath });
101
+ const ctx = await model.createEmbeddingContext({ contextSize: 'auto' });
102
+ return {
103
+ async generateEmbedding(text) {
104
+ const result = await ctx.getEmbeddingFor(text);
105
+ return Array.from(result.vector);
106
+ },
107
+ async dispose() {
108
+ if (ctx && !ctx.disposed)
109
+ await ctx.dispose();
110
+ await model.dispose();
111
+ await llama.dispose();
112
+ },
113
+ };
114
+ }
115
+ // ─── Model download (node-llama-cpp only) ───────────────────────────────────
116
+ function getModelUri(modelName) {
117
+ const config = MODEL_CONFIGS[modelName];
118
+ if (!config) {
119
+ throw new Error(`Unknown embedding model: ${modelName}. Supported: ${Object.keys(MODEL_CONFIGS).join(', ')}`);
120
+ }
121
+ return `hf:${config.repo}/${config.file}`;
122
+ }
123
+ function getLockFilePath(modelName) {
124
+ return path.join(modelsDir, `${modelName}.lock`);
125
+ }
126
+ async function acquireDownloadLock(modelName) {
127
+ const lockPath = getLockFilePath(modelName);
128
+ try {
129
+ if (existsSync(lockPath)) {
130
+ const lockContent = await readFile(lockPath, 'utf-8');
131
+ const lockTime = parseInt(lockContent, 10);
132
+ if (!isNaN(lockTime) && Date.now() - lockTime < 10 * 60 * 1000) {
133
+ return false;
134
+ }
135
+ }
136
+ await writeFile(lockPath, String(Date.now()), { flag: 'wx' }).catch(async () => {
137
+ await writeFile(lockPath, String(Date.now()));
138
+ });
139
+ return true;
140
+ }
141
+ catch {
142
+ return false;
143
+ }
144
+ }
145
+ async function releaseDownloadLock(modelName) {
146
+ const lockPath = getLockFilePath(modelName);
147
+ try {
148
+ await unlink(lockPath);
149
+ }
150
+ catch {
151
+ // Already removed
152
+ }
153
+ }
154
+ async function waitForDownload(modelName, modelPath) {
155
+ const lockPath = getLockFilePath(modelName);
156
+ const maxWait = 10 * 60 * 1000;
157
+ const pollInterval = 2000;
158
+ const start = Date.now();
159
+ while (Date.now() - start < maxWait) {
160
+ if (existsSync(modelPath) && !existsSync(lockPath)) {
161
+ return;
162
+ }
163
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
164
+ }
165
+ throw new Error(`Timed out waiting for model download: ${modelName}`);
166
+ }
167
+ async function downloadModelIfNeeded(modelName) {
168
+ const modelUri = getModelUri(modelName);
169
+ const dir = modelsDir;
170
+ await mkdir(dir, { recursive: true });
171
+ const { createModelDownloader } =
172
+ // @ts-expect-error — node-llama-cpp is an optional manual install, not a declared dependency
173
+ (await import('node-llama-cpp'));
174
+ const downloader = await createModelDownloader({
175
+ modelUri,
176
+ dirPath: dir,
177
+ skipExisting: true,
178
+ });
179
+ const modelPath = downloader.entrypointFilePath;
180
+ if (existsSync(modelPath)) {
181
+ return modelPath;
182
+ }
183
+ const acquired = await acquireDownloadLock(modelName);
184
+ if (!acquired) {
185
+ logger?.info?.(`Another thread is downloading ${modelName}, waiting...`);
186
+ await waitForDownload(modelName, modelPath);
187
+ return modelPath;
188
+ }
189
+ try {
190
+ logger?.info?.(`Downloading embedding model: ${modelName} from ${modelUri}`);
191
+ const resultPath = await downloader.download();
192
+ logger?.info?.(`Model ${modelName} downloaded successfully to ${resultPath}`);
193
+ return resultPath;
194
+ }
195
+ finally {
196
+ await releaseDownloadLock(modelName);
197
+ }
198
+ }
199
+ //# sourceMappingURL=embeddings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../src/core/embeddings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Knowledge Entry Management
3
+ *
4
+ * CRUD operations for knowledge base entries. Handles embedding generation,
5
+ * tag synchronization, and relationship management.
6
+ */
7
+ import type { KnowledgeEntry, KnowledgeEntryInput, KnowledgeEntryUpdate } from '../types.ts';
8
+ /**
9
+ * Strip embedding vectors from an entry to keep responses compact.
10
+ * Embeddings are large float arrays not useful in API responses.
11
+ *
12
+ * NOTE: Harper database records use non-enumerable properties, so
13
+ * object spread ({...record}) produces an empty object. We must
14
+ * explicitly read each field.
15
+ */
16
+ export declare function stripEmbedding(entry: any): Omit<KnowledgeEntry, 'embedding'>;
17
+ /**
18
+ * Create a new knowledge entry.
19
+ *
20
+ * Generates an embedding from title + content, synchronizes tags,
21
+ * and stores the entry. A UUID is generated if no id is provided.
22
+ *
23
+ * @param data - Entry data to create
24
+ * @returns The created knowledge entry
25
+ */
26
+ export declare function createEntry(data: KnowledgeEntryInput): Promise<KnowledgeEntry>;
27
+ /**
28
+ * Get a knowledge entry by ID.
29
+ *
30
+ * @param id - Entry ID
31
+ * @returns The entry, or null if not found
32
+ */
33
+ export declare function getEntry(id: string): Promise<KnowledgeEntry | null>;
34
+ /**
35
+ * Update an existing knowledge entry.
36
+ *
37
+ * Merges the update data with the existing entry. If title or content changed,
38
+ * regenerates the embedding. Synchronizes tag counts if tags changed.
39
+ * Optionally logs the edit to the history table.
40
+ *
41
+ * @param id - ID of the entry to update
42
+ * @param data - Fields to update
43
+ * @param options - Optional edit tracking metadata
44
+ * @returns The updated entry
45
+ * @throws Error if the entry does not exist
46
+ */
47
+ export declare function updateEntry(id: string, data: KnowledgeEntryUpdate, options?: {
48
+ editedBy?: string;
49
+ editSummary?: string;
50
+ }): Promise<KnowledgeEntry>;
51
+ /**
52
+ * Mark an entry as deprecated.
53
+ *
54
+ * @param id - ID of the entry to deprecate
55
+ * @throws Error if the entry does not exist
56
+ */
57
+ export declare function deprecateEntry(id: string): Promise<void>;
58
+ /**
59
+ * Link a new entry as superseding an old entry.
60
+ *
61
+ * Sets newEntry.supersedesId = oldId and oldEntry.supersededById = newId.
62
+ *
63
+ * @param newId - ID of the new (superseding) entry
64
+ * @param oldId - ID of the old (superseded) entry
65
+ * @throws Error if either entry does not exist
66
+ */
67
+ export declare function linkSupersedes(newId: string, oldId: string): Promise<void>;
68
+ /**
69
+ * Link multiple entries as siblings.
70
+ *
71
+ * For each entry, adds all other entry IDs to its siblingIds array (deduplicated).
72
+ *
73
+ * @param ids - IDs of entries to link as siblings
74
+ * @throws Error if any entry does not exist
75
+ */
76
+ export declare function linkSiblings(ids: string[]): Promise<void>;
77
+ /**
78
+ * Reindex embeddings for all entries missing them.
79
+ *
80
+ * Iterates every KnowledgeEntry, generates embeddings for any that
81
+ * don't have one yet, and writes them back. Returns counts of
82
+ * processed, updated, and failed entries.
83
+ */
84
+ export declare function reindexEmbeddings(kbId: string): Promise<{
85
+ total: number;
86
+ updated: number;
87
+ failed: number;
88
+ skipped: number;
89
+ }>;
90
+ /**
91
+ * Link two entries as related.
92
+ *
93
+ * Adds relatedId to the entry's relatedIds array (deduplicated).
94
+ * This is a one-directional link; call twice for bidirectional.
95
+ *
96
+ * @param id - ID of the entry to add a related link to
97
+ * @param relatedId - ID of the related entry
98
+ * @throws Error if the entry does not exist
99
+ */
100
+ export declare function linkRelated(id: string, relatedId: string): Promise<void>;
101
+ //# sourceMappingURL=entries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../../src/core/entries.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE7F;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAyB5E;AAED;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,CAAC,CAuCpF;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAGzE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,WAAW,CAChC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,oBAAoB,EAC1B,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD,OAAO,CAAC,cAAc,CAAC,CA+CzB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW9D;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBhF;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkC/D;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB,CAAC,CAmCD;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAe9E"}