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