@majkapp/plugin-kit 3.7.9 → 3.7.11

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/docs/KNOWLEDGE.md CHANGED
@@ -1,225 +1,490 @@
1
1
  # Knowledge API
2
2
 
3
- Store and search knowledge nodes organized into trees with reference tracking.
3
+ MAJK provides two knowledge systems:
4
4
 
5
- ## Quick Start
5
+ 1. **Knowledge Fabric** (Recommended) - Unified semantic search across all system knowledge with vector embeddings. Use this for searching, browsing, and contributing plugin knowledge.
6
+
7
+ 2. **Legacy Knowledge Trees** - Conversation-scoped knowledge trees. Still available but deprecated in favor of the Fabric.
8
+
9
+ **Start with the Knowledge Fabric** - it's more powerful, searches across everything, and supports plugin contributions.
10
+
11
+ ---
12
+
13
+ ## Quick Start (Knowledge Fabric)
6
14
 
7
15
  ```typescript
8
16
  handler: async (input, ctx) => {
9
- // Add knowledge
10
- await ctx.majk.knowledge.add({
11
- conversationId: 'conv-123',
12
- title: 'API Design Decision',
13
- content: 'We decided to use REST over GraphQL because...',
14
- references: ['file:src/api/routes.ts#L10-50'],
15
- tree: 'decisions'
17
+ const fabric = ctx.majk.knowledge.fabric;
18
+
19
+ // Search all knowledge semantically
20
+ const results = await fabric.search('authentication patterns');
21
+
22
+ // Register a contribution namespace
23
+ const handle = await fabric.registerContribution('contacts', {
24
+ initialNodes: [
25
+ { key: 'john', title: 'John Doe', content: 'CEO at Acme Corp, key decision maker...' }
26
+ ]
16
27
  });
17
28
 
18
- // Search knowledge
19
- const nodes = await ctx.majk.knowledge.search('REST API', {
20
- conversationId: 'conv-123'
29
+ // Add more nodes dynamically
30
+ await handle.contribute({
31
+ key: 'jane',
32
+ title: 'Jane Smith',
33
+ content: 'VP Engineering, technical buyer...'
21
34
  });
22
35
 
23
- return { found: nodes.length };
36
+ return { searchResults: results.results.length };
24
37
  }
25
38
  ```
26
39
 
27
- ## API Reference
40
+ ## Knowledge Fabric API
41
+
42
+ The Knowledge Fabric provides unified semantic search across:
43
+ - Project notes (knowledge trees)
44
+ - Teammates
45
+ - Tools
46
+ - Plugins
47
+ - Skills
48
+ - Reports
49
+ - Plugin-contributed knowledge
50
+
51
+ Access via `ctx.majk.knowledge.fabric`.
28
52
 
29
- ### add(input)
53
+ ### search(query, options?)
30
54
 
31
- Add a knowledge node.
55
+ Semantic search across all knowledge.
32
56
 
33
57
  ```typescript
34
- await ctx.majk.knowledge.add({
35
- conversationId: string, // Conversation to associate with
36
- title: string, // Node title
37
- content: string, // Knowledge content
38
- references?: string[], // Reference links (files, URLs, etc.)
39
- tree?: string // Tree name (default: 'default')
58
+ const response = await ctx.majk.knowledge.fabric.search('authentication', {
59
+ under: '/projects/my-project', // Scope to prefix
60
+ limit: 10, // Max results (default: 10, max: 100)
61
+ minScore: 0.3 // Minimum similarity (0-1)
40
62
  });
63
+
64
+ // Response structure
65
+ {
66
+ results: [
67
+ {
68
+ node: KnowledgeFabricNode,
69
+ score: 0.95 // Similarity score (1 = most similar)
70
+ }
71
+ ],
72
+ indexingStatus: {
73
+ complete: true, // Are all nodes indexed?
74
+ pendingCount: 0 // Nodes still being embedded
75
+ }
76
+ }
41
77
  ```
42
78
 
43
- ### search(query, options?)
79
+ ### getRoots()
44
80
 
45
- Search knowledge by text.
81
+ Get top-level nodes of the knowledge hierarchy.
46
82
 
47
83
  ```typescript
48
- const nodes = await ctx.majk.knowledge.search(query, {
49
- conversationId?: string, // Filter by conversation
50
- tree?: string, // Filter by tree
51
- limit?: number // Max results
52
- });
53
- // Returns: KnowledgeNode[]
84
+ const roots = await ctx.majk.knowledge.fabric.getRoots();
85
+ // Returns: ['/projects', '/plugins', '/teammates', '/tools', ...]
54
86
  ```
55
87
 
56
- ### getByReference(ref)
88
+ ### expand(key)
57
89
 
58
- Find nodes that reference a specific resource.
90
+ Expand a node to see its children.
59
91
 
60
92
  ```typescript
61
- const nodes = await ctx.majk.knowledge.getByReference('file:src/api.ts');
62
- // Returns: KnowledgeNode[]
93
+ const result = await ctx.majk.knowledge.fabric.expand('/plugins/my-plugin');
94
+ // Returns: { node: KnowledgeFabricNode, children: KnowledgeFabricNode[] }
63
95
  ```
64
96
 
65
- ### getTree(conversationId, treeName)
97
+ ### getNode(key)
66
98
 
67
- Get all nodes in a tree.
99
+ Get a single node by key.
68
100
 
69
101
  ```typescript
70
- const tree = await ctx.majk.knowledge.getTree('conv-123', 'decisions');
71
- // Returns: { name, conversationId, nodes: KnowledgeNode[] }
102
+ const node = await ctx.majk.knowledge.fabric.getNode('/projects/proj-123/notes/a1');
103
+ // Returns: KnowledgeFabricNode | null
72
104
  ```
73
105
 
74
- ### listTrees(conversationId)
106
+ ### getStatus()
75
107
 
76
- List all trees in a conversation.
108
+ Get overall fabric status.
77
109
 
78
110
  ```typescript
79
- const trees = await ctx.majk.knowledge.listTrees('conv-123');
80
- // Returns: string[] (tree names)
111
+ const status = await ctx.majk.knowledge.fabric.getStatus();
112
+ // Returns: {
113
+ // totalNodes: 1500,
114
+ // activeNodes: 1450,
115
+ // pendingNodes: 50,
116
+ // totalEmbeddings: 1450,
117
+ // searchAvailable: true
118
+ // }
81
119
  ```
82
120
 
83
- ## Types
121
+ ## Contributing Knowledge
122
+
123
+ Plugins can contribute their own knowledge to the fabric, making it searchable alongside system knowledge.
124
+
125
+ ### registerContribution(subPrefix, options?)
126
+
127
+ Register a namespace for contributing knowledge.
84
128
 
85
129
  ```typescript
86
- interface KnowledgeNode {
87
- id: string;
88
- title: string;
89
- content: string;
90
- references: string[];
91
- conversationId: string;
92
- tree: string;
93
- createdAt: Date;
94
- }
130
+ // Default prefix: /plugins/{pluginId}/{subPrefix}
131
+ const handle = await ctx.majk.knowledge.fabric.registerContribution('contacts');
132
+ // Prefix: /plugins/my-plugin/contacts
95
133
 
96
- interface KnowledgeTree {
97
- name: string;
98
- conversationId: string;
99
- nodes: KnowledgeNode[];
100
- }
134
+ // With custom prefix (except reserved: /projects, /teammates, /tools, /skills, /reports)
135
+ const handle = await ctx.majk.knowledge.fabric.registerContribution('contacts', {
136
+ prefix: '/crm/contacts' // Custom prefix
137
+ });
138
+
139
+ // With initial nodes
140
+ const handle = await ctx.majk.knowledge.fabric.registerContribution('contacts', {
141
+ initialNodes: [
142
+ { key: 'c1', title: 'Contact 1', content: 'Details...' },
143
+ { key: 'c2', title: 'Contact 2', content: 'Details...' }
144
+ ]
145
+ });
101
146
  ```
102
147
 
103
- ## Reference Patterns
148
+ ### KnowledgeContributionHandle
104
149
 
105
- Use consistent reference formats:
150
+ The handle returned by `registerContribution()` manages your contribution.
106
151
 
107
152
  ```typescript
108
- // File references
109
- 'file:src/api/routes.ts'
110
- 'file:src/api/routes.ts#L10-50'
153
+ interface KnowledgeContributionHandle {
154
+ readonly prefix: string; // Full key prefix
155
+ readonly contributorId: string; // plugin:{pluginId}:{subPrefix}
111
156
 
112
- // URL references
113
- 'url:https://docs.example.com/api'
157
+ // Add/update a node
158
+ contribute(node: ContributeNodeInput): Promise<void>;
114
159
 
115
- // Function references
116
- 'function:createUser'
117
- 'function:src/api.ts:createUser'
160
+ // Add multiple nodes efficiently
161
+ contributeBatch(nodes: ContributeNodeInput[]): Promise<void>;
118
162
 
119
- // Commit references
120
- 'commit:abc123'
163
+ // Remove a node
164
+ remove(key: string): Promise<boolean>;
121
165
 
122
- // Issue/PR references
123
- 'issue:42'
124
- 'pr:123'
166
+ // Get node count
167
+ getNodeCount(): Promise<number>;
168
+
169
+ // List all keys
170
+ listKeys(options?: { status?: 'active' | 'pending' | 'all' }): Promise<string[]>;
171
+
172
+ // Re-sync contribution (deactivates nodes not re-contributed)
173
+ reconcile(): Promise<{ added: number; updated: number; deactivated: number }>;
174
+
175
+ // Unregister (marks all nodes inactive)
176
+ unregister(): Promise<void>;
177
+ }
125
178
  ```
126
179
 
127
- ## Common Patterns
180
+ ### contribute(node)
128
181
 
129
- ### Organize by Topic
182
+ Add or update a single node.
130
183
 
131
184
  ```typescript
132
- // Add to different trees
133
- await ctx.majk.knowledge.add({
134
- conversationId,
135
- title: 'Auth Flow Decision',
136
- content: 'Using JWT tokens...',
137
- tree: 'architecture'
185
+ await handle.contribute({
186
+ key: 'customer-123', // Relative to prefix
187
+ title: 'ACME Corporation', // Human-readable title
188
+ content: 'Enterprise customer, 500 employees, using premium tier...',
189
+ children: ['contact-1', 'contact-2'], // Optional child keys
190
+ refs: { // Optional metadata
191
+ source: 'crm-sync',
192
+ lastUpdated: Date.now()
193
+ }
138
194
  });
195
+ // Full key: /plugins/my-plugin/contacts/customer-123
196
+ ```
139
197
 
140
- await ctx.majk.knowledge.add({
141
- conversationId,
142
- title: 'JWT Security Concern',
143
- content: 'Token expiry handling...',
144
- tree: 'security'
145
- });
198
+ ### contributeBatch(nodes)
146
199
 
147
- // Query specific tree
148
- const archNodes = await ctx.majk.knowledge.getTree(conversationId, 'architecture');
200
+ Add multiple nodes efficiently.
201
+
202
+ ```typescript
203
+ await handle.contributeBatch([
204
+ { key: 'c1', title: 'Contact 1', content: 'Details...' },
205
+ { key: 'c2', title: 'Contact 2', content: 'Details...' },
206
+ { key: 'c3', title: 'Contact 3', content: 'Details...' }
207
+ ]);
149
208
  ```
150
209
 
151
- ### Track Code References
210
+ ### remove(key)
211
+
212
+ Remove a node by key.
152
213
 
153
214
  ```typescript
154
- // Add knowledge about code
155
- await ctx.majk.knowledge.add({
156
- conversationId,
157
- title: 'Rate Limiter Implementation',
158
- content: 'The rate limiter uses a sliding window algorithm...',
159
- references: [
160
- 'file:src/middleware/rateLimiter.ts',
161
- 'file:src/config/limits.ts#L5-20',
162
- 'url:https://en.wikipedia.org/wiki/Sliding_window_protocol'
163
- ],
164
- tree: 'implementation'
215
+ const removed = await handle.remove('customer-123');
216
+ // Also works with full key:
217
+ const removed = await handle.remove('/plugins/my-plugin/contacts/customer-123');
218
+ ```
219
+
220
+ ### listContributions()
221
+
222
+ List all contributions registered by your plugin.
223
+
224
+ ```typescript
225
+ const contributions = await ctx.majk.knowledge.fabric.listContributions();
226
+ // Returns: ContributionSummary[]
227
+ // {
228
+ // prefix: '/plugins/my-plugin/contacts',
229
+ // contributorId: 'plugin:my-plugin:contacts',
230
+ // nodeCount: 42,
231
+ // pendingCount: 3,
232
+ // status: 'ready' | 'indexing' | 'unregistered'
233
+ // }
234
+ ```
235
+
236
+ ### onNodeChange(handler, options?)
237
+
238
+ Subscribe to node change events.
239
+
240
+ ```typescript
241
+ const unsubscribe = ctx.majk.knowledge.fabric.onNodeChange((event) => {
242
+ console.log(`Node ${event.key} was ${event.type}`);
243
+ // event.type: 'indexed' | 'activated' | 'deactivated' | 'reindexed'
165
244
  });
166
245
 
167
- // Later, find all knowledge about a file
168
- const related = await ctx.majk.knowledge.getByReference('file:src/middleware/rateLimiter.ts');
246
+ // Later: unsubscribe();
169
247
  ```
170
248
 
171
- ### Build Context for Analysis
249
+ ## Types
172
250
 
173
251
  ```typescript
174
- async function getProjectContext(conversationId: string) {
175
- const trees = await ctx.majk.knowledge.listTrees(conversationId);
252
+ interface KnowledgeFabricNode {
253
+ key: string; // Hierarchical path
254
+ title: string; // Human-readable title
255
+ content: string; // Searchable content
256
+ children: string[]; // Child node keys
257
+ refs: Record<string, unknown>; // Metadata/references
258
+ contributorId: string; // Who contributed this
259
+ status: 'active' | 'pending' | 'inactive';
260
+ createdAt: number; // Timestamp
261
+ lastContributed: number; // Timestamp
262
+ }
176
263
 
177
- const context = {};
178
- for (const treeName of trees) {
179
- const tree = await ctx.majk.knowledge.getTree(conversationId, treeName);
180
- context[treeName] = tree.nodes.map(n => ({
181
- title: n.title,
182
- summary: n.content.slice(0, 200)
183
- }));
184
- }
264
+ interface ContributeNodeInput {
265
+ key: string; // Relative to prefix
266
+ title: string;
267
+ content: string;
268
+ children?: string[]; // Optional child keys
269
+ refs?: Record<string, unknown>; // Optional metadata
270
+ }
271
+
272
+ interface FabricSearchOptions {
273
+ under?: string; // Scope to key prefix
274
+ limit?: number; // Max results (1-100)
275
+ minScore?: number; // Min similarity (0-1)
276
+ }
277
+
278
+ interface FabricSearchResponse {
279
+ results: Array<{
280
+ node: KnowledgeFabricNode;
281
+ score: number;
282
+ }>;
283
+ indexingStatus: {
284
+ complete: boolean;
285
+ pendingCount: number;
286
+ };
287
+ }
288
+ ```
289
+
290
+ ## Common Patterns
185
291
 
186
- return context;
292
+ ### CRM Integration
293
+
294
+ ```typescript
295
+ // Sync contacts from external CRM
296
+ async function syncContacts(ctx, crmClient) {
297
+ const handle = await ctx.majk.knowledge.fabric.registerContribution('contacts');
298
+
299
+ const contacts = await crmClient.getAllContacts();
300
+
301
+ await handle.contributeBatch(contacts.map(c => ({
302
+ key: c.id,
303
+ title: c.name,
304
+ content: `
305
+ ${c.name} - ${c.company}
306
+ Role: ${c.title}
307
+ Email: ${c.email}
308
+ Notes: ${c.notes}
309
+ Tags: ${c.tags.join(', ')}
310
+ `,
311
+ refs: {
312
+ crmId: c.id,
313
+ company: c.company,
314
+ lastSync: Date.now()
315
+ }
316
+ })));
187
317
  }
318
+
319
+ // Search contacts with natural language
320
+ const results = await ctx.majk.knowledge.fabric.search(
321
+ 'decision maker at enterprise companies'
322
+ );
188
323
  ```
189
324
 
190
- ### Search Across Everything
325
+ ### Documentation Indexer
191
326
 
192
327
  ```typescript
193
- // Broad search
194
- const results = await ctx.majk.knowledge.search('authentication');
328
+ // Index documentation files
329
+ async function indexDocs(ctx, docsPath) {
330
+ const handle = await ctx.majk.knowledge.fabric.registerContribution('docs');
331
+
332
+ const files = await glob(`${docsPath}/**/*.md`);
333
+
334
+ for (const file of files) {
335
+ const content = await fs.readFile(file, 'utf-8');
336
+ const title = extractTitle(content);
337
+
338
+ await handle.contribute({
339
+ key: path.relative(docsPath, file),
340
+ title,
341
+ content,
342
+ refs: {
343
+ filePath: file,
344
+ indexed: Date.now()
345
+ }
346
+ });
347
+ }
348
+ }
349
+
350
+ // Search documentation
351
+ const results = await ctx.majk.knowledge.fabric.search('how to configure authentication');
352
+ ```
353
+
354
+ ### Scoped Search
195
355
 
196
- // Filtered search
197
- const securityResults = await ctx.majk.knowledge.search('authentication', {
198
- conversationId,
199
- tree: 'security',
356
+ ```typescript
357
+ // Search only within your plugin's knowledge
358
+ const handle = await ctx.majk.knowledge.fabric.registerContribution('data');
359
+
360
+ const results = await ctx.majk.knowledge.fabric.search('important topic', {
361
+ under: handle.prefix, // Only search your contribution
200
362
  limit: 5
201
363
  });
364
+
365
+ // Search within a specific project
366
+ const projectResults = await ctx.majk.knowledge.fabric.search('auth', {
367
+ under: '/projects/proj-abc123'
368
+ });
369
+ ```
370
+
371
+ ### Reconciliation
372
+
373
+ ```typescript
374
+ // Re-sync when source data changes
375
+ async function resyncData(ctx) {
376
+ const handle = await ctx.majk.knowledge.fabric.registerContribution('data');
377
+
378
+ // Contribute current data
379
+ const currentData = await fetchCurrentData();
380
+ await handle.contributeBatch(currentData.map(d => ({
381
+ key: d.id,
382
+ title: d.name,
383
+ content: d.description
384
+ })));
385
+
386
+ // Reconcile - deactivates nodes not in currentData
387
+ const stats = await handle.reconcile();
388
+ console.log(`Added: ${stats.added}, Updated: ${stats.updated}, Removed: ${stats.deactivated}`);
389
+ }
390
+ ```
391
+
392
+ ### Browse Hierarchy
393
+
394
+ ```typescript
395
+ // Build a tree view of knowledge
396
+ async function browseKnowledge(ctx) {
397
+ const fabric = ctx.majk.knowledge.fabric;
398
+
399
+ // Get root nodes
400
+ const roots = await fabric.getRoots();
401
+
402
+ // Expand to see children
403
+ for (const root of roots) {
404
+ const expanded = await fabric.expand(root.key);
405
+ console.log(`${root.title}:`);
406
+ for (const child of expanded?.children || []) {
407
+ console.log(` - ${child.title}`);
408
+ }
409
+ }
410
+ }
202
411
  ```
203
412
 
413
+ ## Reserved Prefixes
414
+
415
+ These prefixes are reserved for system use and cannot be used for custom contributions:
416
+
417
+ - `/projects` - Project notes and knowledge trees
418
+ - `/teammates` - Teammate configurations
419
+ - `/tools` - Tool definitions
420
+ - `/skills` - Skill definitions
421
+ - `/reports` - Report storage
422
+ - `/characterizations` - System characterizations
423
+
424
+ Use the default `/plugins/{pluginId}/...` prefix or choose a custom unreserved prefix.
425
+
204
426
  ## Best Practices
205
427
 
206
- 1. **Use meaningful titles** - Clear, searchable node titles
207
- 2. **Consistent tree names** - Standardize tree names across conversations
208
- 3. **Rich references** - Link to files, URLs, commits for traceability
209
- 4. **Structured content** - Use markdown for formatted content
210
- 5. **Search-friendly content** - Include keywords that users might search for
428
+ 1. **Use meaningful content** - Include keywords and context for better search results
429
+ 2. **Structure with hierarchy** - Use parent/child relationships for organized browsing
430
+ 3. **Add metadata in refs** - Store source information, timestamps, IDs for traceability
431
+ 4. **Reconcile periodically** - Keep knowledge in sync with external sources
432
+ 5. **Scope searches** - Use `under` option to search specific namespaces
433
+ 6. **Handle indexing status** - Check `indexingStatus.complete` for real-time accuracy
434
+
435
+ ---
436
+
437
+ ## Legacy Knowledge Trees API (Deprecated)
438
+
439
+ > **Note:** The following methods work with conversation-scoped knowledge trees. They are deprecated in favor of the Knowledge Fabric which provides unified search across all knowledge. Use `ctx.majk.knowledge.fabric` for new development.
440
+
441
+ ### add(input) [DEPRECATED]
442
+
443
+ ```typescript
444
+ // DEPRECATED - use fabric.registerContribution() instead
445
+ await ctx.majk.knowledge.add({
446
+ conversationId: string,
447
+ title: string,
448
+ content: string,
449
+ references?: string[],
450
+ tree?: string
451
+ });
452
+ ```
453
+
454
+ ### search(query, options?) [DEPRECATED]
455
+
456
+ ```typescript
457
+ // DEPRECATED - use fabric.search() instead
458
+ const nodes = await ctx.majk.knowledge.search(query, {
459
+ conversationId?: string,
460
+ tree?: string,
461
+ limit?: number
462
+ });
463
+ ```
211
464
 
212
- ## Tree Organization Examples
465
+ ### getByReference(ref) [DEPRECATED]
213
466
 
467
+ ```typescript
468
+ // DEPRECATED - use fabric for knowledge operations
469
+ const nodes = await ctx.majk.knowledge.getByReference('file:src/api.ts');
214
470
  ```
215
- decisions/ - Architecture and design decisions
216
- security/ - Security considerations and findings
217
- implementation/ - How things are implemented
218
- bugs/ - Known issues and their context
219
- research/ - Background research and findings
471
+
472
+ ### getTree(conversationId, treeName) [DEPRECATED]
473
+
474
+ ```typescript
475
+ // DEPRECATED - use fabric for knowledge operations
476
+ const tree = await ctx.majk.knowledge.getTree('conv-123', 'decisions');
477
+ ```
478
+
479
+ ### listTrees(conversationId) [DEPRECATED]
480
+
481
+ ```typescript
482
+ // DEPRECATED - use fabric for knowledge operations
483
+ const trees = await ctx.majk.knowledge.listTrees('conv-123');
220
484
  ```
221
485
 
222
486
  ## Next Steps
223
487
 
224
- Run `npx @majkapp/plugin-kit --reports` - Reports and knowledge base
225
- Run `npx @majkapp/plugin-kit --context` - Context API overview
488
+ Run `npx @majkapp/plugin-kit --llm:reports` - Reports and knowledge management
489
+ Run `npx @majkapp/plugin-kit --llm:context` - Context API overview
490
+ Run `npx @majkapp/plugin-kit --llm:skills` - Skills system
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@majkapp/plugin-kit",
3
- "version": "3.7.9",
3
+ "version": "3.7.11",
4
4
  "description": "Pure plugin definition library for MAJK - outputs plugin definitions, not HTTP servers",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",