@hasna/knowledge 0.2.9 → 0.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/bin/open-knowledge-mcp.js +1447 -34
- package/bin/open-knowledge.js +63 -63
- package/docs/architecture/ai-native-knowledge-base.md +4 -1
- package/package.json +2 -2
- package/src/cli.ts +18 -74
- package/src/mcp.js +5 -27
- package/src/service.ts +157 -0
package/src/cli.ts
CHANGED
|
@@ -5,15 +5,9 @@
|
|
|
5
5
|
* Licensed under the Apache License, Version 2.0
|
|
6
6
|
*/
|
|
7
7
|
import { defaultStorePath, loadStore, saveStore, withLock, makeId, makeShortId, ensureStore, type KnowledgeItem } from './store';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { initializeWikiLayout } from './wiki-layout';
|
|
12
|
-
import { ingestOpenFilesManifest } from './manifest-ingest';
|
|
13
|
-
import { ingestSourceRef } from './source-ingest';
|
|
14
|
-
import { consumeOpenFilesOutbox } from './outbox-consume';
|
|
15
|
-
import { resolveOpenFilesSource } from './source-resolver';
|
|
16
|
-
import { approvalStatus, assertS3ReadAllowed, assertWebSearchAllowed, createApprovalGate, recordAuditEvent, recordRedactionFindings, redactSecrets, resolveSafetyPolicy } from './safety';
|
|
8
|
+
import { openKnowledgeDb } from './knowledge-db';
|
|
9
|
+
import { createKnowledgeService } from './service';
|
|
10
|
+
import { approvalStatus, assertS3ReadAllowed, assertWebSearchAllowed, createApprovalGate, recordAuditEvent, recordRedactionFindings, redactSecrets } from './safety';
|
|
17
11
|
import pkg from '../package.json' with { type: 'json' };
|
|
18
12
|
|
|
19
13
|
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
@@ -299,71 +293,49 @@ async function run(argv: string[]): Promise<void> {
|
|
|
299
293
|
|
|
300
294
|
if (!command || flags.help || command === 'help') { printCommandHelp(positional[1]); return; }
|
|
301
295
|
|
|
302
|
-
const
|
|
296
|
+
const service = createKnowledgeService({ scope: flags.scope });
|
|
303
297
|
let storePath = flags.store;
|
|
304
298
|
if (!storePath) {
|
|
305
299
|
if (flags.scope === 'project' || flags.scope === 'local') {
|
|
306
|
-
storePath =
|
|
300
|
+
storePath = service.jsonStorePath();
|
|
307
301
|
} else {
|
|
308
302
|
storePath = defaultStorePath();
|
|
309
303
|
}
|
|
310
304
|
}
|
|
311
305
|
|
|
312
306
|
if (command === 'paths') {
|
|
313
|
-
|
|
314
|
-
output({
|
|
315
|
-
ok: true,
|
|
316
|
-
scope: flags.scope ?? 'global',
|
|
317
|
-
home: resolvedWorkspace.home,
|
|
318
|
-
config_path: resolvedWorkspace.configPath,
|
|
319
|
-
json_store_path: resolvedWorkspace.jsonStorePath,
|
|
320
|
-
knowledge_db_path: resolvedWorkspace.knowledgeDbPath,
|
|
321
|
-
artifacts_dir: resolvedWorkspace.artifactsDir,
|
|
322
|
-
indexes_dir: resolvedWorkspace.indexesDir,
|
|
323
|
-
logs_dir: resolvedWorkspace.logsDir,
|
|
324
|
-
runs_dir: resolvedWorkspace.runsDir,
|
|
325
|
-
schemas_dir: resolvedWorkspace.schemasDir,
|
|
326
|
-
wiki_dir: resolvedWorkspace.wikiDir,
|
|
327
|
-
config: readKnowledgeConfig(resolvedWorkspace.configPath),
|
|
328
|
-
message: resolvedWorkspace.home,
|
|
329
|
-
}, flags.json);
|
|
307
|
+
output(service.paths(), flags.json);
|
|
330
308
|
return;
|
|
331
309
|
}
|
|
332
310
|
|
|
333
311
|
if (command === 'db') {
|
|
334
312
|
const action = positional[1] ?? 'init';
|
|
335
|
-
const resolvedWorkspace = ensureKnowledgeWorkspace(workspace.home);
|
|
336
313
|
if (action !== 'init' && action !== 'stats') {
|
|
337
314
|
throw new Error("Invalid db action. Use 'init' or 'stats'.");
|
|
338
315
|
}
|
|
339
316
|
if (action === 'init') {
|
|
340
|
-
const result =
|
|
317
|
+
const result = service.initDb();
|
|
341
318
|
output({ ok: true, ...result, message: `Initialized ${result.path}` }, flags.json);
|
|
342
319
|
return;
|
|
343
320
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
output({ ok: true, path: resolvedWorkspace.knowledgeDbPath, ...stats, message: `knowledge.db schema v${stats.schema_version}` }, flags.json);
|
|
321
|
+
const stats = service.dbStats();
|
|
322
|
+
output({ ok: true, path: service.workspace.knowledgeDbPath, ...stats, message: `knowledge.db schema v${stats.schema_version}` }, flags.json);
|
|
347
323
|
return;
|
|
348
324
|
}
|
|
349
325
|
|
|
350
326
|
if (command === 'wiki') {
|
|
351
327
|
const action = positional[1] ?? 'init';
|
|
352
328
|
if (action !== 'init') throw new Error("Invalid wiki action. Use 'init'.");
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
const artifactStore = createArtifactStore(config, resolvedWorkspace);
|
|
356
|
-
const result = await initializeWikiLayout(artifactStore);
|
|
357
|
-
output({ ok: true, ...result, message: `Initialized wiki layout in ${resolvedWorkspace.home}` }, flags.json);
|
|
329
|
+
const result = await service.initWiki();
|
|
330
|
+
output({ ok: true, ...result, message: `Initialized wiki layout in ${service.workspace.home}` }, flags.json);
|
|
358
331
|
return;
|
|
359
332
|
}
|
|
360
333
|
|
|
361
334
|
if (command === 'safety') {
|
|
362
335
|
const action = positional[1] ?? 'status';
|
|
363
|
-
const resolvedWorkspace =
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
migrateKnowledgeDb(resolvedWorkspace.knowledgeDbPath);
|
|
336
|
+
const resolvedWorkspace = service.ensureWorkspace();
|
|
337
|
+
const policy = service.safetyPolicy();
|
|
338
|
+
service.initDb();
|
|
367
339
|
const db = openKnowledgeDb(resolvedWorkspace.knowledgeDbPath);
|
|
368
340
|
try {
|
|
369
341
|
if (action === 'status') {
|
|
@@ -489,15 +461,9 @@ async function run(argv: string[]): Promise<void> {
|
|
|
489
461
|
if (action !== 'resolve') throw new Error("Invalid source action. Use 'resolve'.");
|
|
490
462
|
const sourceRef = positional[2];
|
|
491
463
|
if (!sourceRef) throw new Error('Usage: open-knowledge source resolve <source-ref>');
|
|
492
|
-
const
|
|
493
|
-
const config = readKnowledgeConfig(resolvedWorkspace.configPath);
|
|
494
|
-
const safetyPolicy = resolveSafetyPolicy(config, resolvedWorkspace);
|
|
495
|
-
const result = await resolveOpenFilesSource({
|
|
496
|
-
dbPath: resolvedWorkspace.knowledgeDbPath,
|
|
497
|
-
sourceRef,
|
|
464
|
+
const result = await service.resolveSource(sourceRef, {
|
|
498
465
|
purpose: flags.purpose,
|
|
499
466
|
limit: flags.limit,
|
|
500
|
-
safetyPolicy,
|
|
501
467
|
});
|
|
502
468
|
output({
|
|
503
469
|
ok: true,
|
|
@@ -511,31 +477,17 @@ async function run(argv: string[]): Promise<void> {
|
|
|
511
477
|
|
|
512
478
|
if (command === 'ingest') {
|
|
513
479
|
const action = positional[1] ?? '';
|
|
514
|
-
const resolvedWorkspace = ensureKnowledgeWorkspace(workspace.home);
|
|
515
|
-
const config = readKnowledgeConfig(resolvedWorkspace.configPath);
|
|
516
|
-
const safetyPolicy = resolveSafetyPolicy(config, resolvedWorkspace);
|
|
517
480
|
if (action === 'manifest') {
|
|
518
481
|
const input = positional[2];
|
|
519
482
|
if (!input) throw new Error('Usage: open-knowledge ingest manifest <file|s3://bucket/key>');
|
|
520
|
-
const result = await
|
|
521
|
-
dbPath: resolvedWorkspace.knowledgeDbPath,
|
|
522
|
-
input,
|
|
523
|
-
config,
|
|
524
|
-
safetyPolicy,
|
|
525
|
-
});
|
|
483
|
+
const result = await service.ingestManifest(input);
|
|
526
484
|
output({ ok: true, ...result, message: `Ingested ${result.items_seen} manifest item(s)` }, flags.json);
|
|
527
485
|
return;
|
|
528
486
|
}
|
|
529
487
|
if (action === 'source') {
|
|
530
488
|
const sourceRef = positional[2];
|
|
531
489
|
if (!sourceRef) throw new Error('Usage: open-knowledge ingest source <source-ref>');
|
|
532
|
-
const result = await
|
|
533
|
-
dbPath: resolvedWorkspace.knowledgeDbPath,
|
|
534
|
-
sourceRef,
|
|
535
|
-
purpose: flags.purpose,
|
|
536
|
-
config,
|
|
537
|
-
safetyPolicy,
|
|
538
|
-
});
|
|
490
|
+
const result = await service.ingestSource(sourceRef, flags.purpose);
|
|
539
491
|
output({ ok: true, ...result, message: `Ingested source ${result.source_ref} (${result.chunks_inserted} chunks)` }, flags.json);
|
|
540
492
|
return;
|
|
541
493
|
}
|
|
@@ -547,15 +499,7 @@ async function run(argv: string[]): Promise<void> {
|
|
|
547
499
|
if (action !== 'outbox') throw new Error("Invalid reindex action. Use 'outbox'.");
|
|
548
500
|
const input = positional[2];
|
|
549
501
|
if (!input) throw new Error('Usage: open-knowledge reindex outbox <file|s3://bucket/key>');
|
|
550
|
-
const
|
|
551
|
-
const config = readKnowledgeConfig(resolvedWorkspace.configPath);
|
|
552
|
-
const safetyPolicy = resolveSafetyPolicy(config, resolvedWorkspace);
|
|
553
|
-
const result = await consumeOpenFilesOutbox({
|
|
554
|
-
dbPath: resolvedWorkspace.knowledgeDbPath,
|
|
555
|
-
input,
|
|
556
|
-
config,
|
|
557
|
-
safetyPolicy,
|
|
558
|
-
});
|
|
502
|
+
const result = await service.consumeOutbox(input);
|
|
559
503
|
output({ ok: true, ...result, message: `Consumed ${result.events_seen} outbox event(s)` }, flags.json);
|
|
560
504
|
return;
|
|
561
505
|
}
|
package/src/mcp.js
CHANGED
|
@@ -5,10 +5,8 @@ import { z } from 'zod';
|
|
|
5
5
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
6
6
|
import pkg from '../package.json' with { type: 'json' };
|
|
7
7
|
import { defaultStorePath, loadStore, saveStore, makeId, withLock } from './store.ts';
|
|
8
|
-
import { ensureKnowledgeWorkspace, readKnowledgeConfig, resolveScopedWorkspace } from './workspace.ts';
|
|
9
8
|
import { parseSourceRef } from './source-ref.ts';
|
|
10
|
-
import {
|
|
11
|
-
import { resolveSafetyPolicy } from './safety.ts';
|
|
9
|
+
import { createKnowledgeService } from './service.ts';
|
|
12
10
|
|
|
13
11
|
const storePathField = z.string().optional().describe('Path to the JSON store file');
|
|
14
12
|
const scopeField = z.enum(['local', 'global', 'project']).optional().describe('Workspace scope');
|
|
@@ -28,7 +26,7 @@ function shortIdFor(id) {
|
|
|
28
26
|
function resolveStorePath(storePath, scope) {
|
|
29
27
|
if (storePath) return storePath;
|
|
30
28
|
if (scope === 'project' || scope === 'local') {
|
|
31
|
-
return
|
|
29
|
+
return createKnowledgeService({ scope }).jsonStorePath();
|
|
32
30
|
}
|
|
33
31
|
return defaultStorePath();
|
|
34
32
|
}
|
|
@@ -76,22 +74,7 @@ export function buildServer() {
|
|
|
76
74
|
registerTool(server, 'ok_paths', 'Knowledge workspace paths', 'Show resolved workspace and store paths', {
|
|
77
75
|
scope: scopeField,
|
|
78
76
|
}, async ({ scope }) => {
|
|
79
|
-
|
|
80
|
-
return jsonText({
|
|
81
|
-
ok: true,
|
|
82
|
-
scope: scope ?? 'global',
|
|
83
|
-
home: workspace.home,
|
|
84
|
-
config_path: workspace.configPath,
|
|
85
|
-
json_store_path: workspace.jsonStorePath,
|
|
86
|
-
knowledge_db_path: workspace.knowledgeDbPath,
|
|
87
|
-
artifacts_dir: workspace.artifactsDir,
|
|
88
|
-
indexes_dir: workspace.indexesDir,
|
|
89
|
-
logs_dir: workspace.logsDir,
|
|
90
|
-
runs_dir: workspace.runsDir,
|
|
91
|
-
schemas_dir: workspace.schemasDir,
|
|
92
|
-
wiki_dir: workspace.wikiDir,
|
|
93
|
-
config: readKnowledgeConfig(workspace.configPath),
|
|
94
|
-
});
|
|
77
|
+
return jsonText(createKnowledgeService({ scope }).paths());
|
|
95
78
|
});
|
|
96
79
|
|
|
97
80
|
registerTool(server, 'ok_parse_source_ref', 'Parse source reference', 'Parse and validate an open-files, S3, file, or web source ref', {
|
|
@@ -110,16 +93,11 @@ export function buildServer() {
|
|
|
110
93
|
limit: z.number().optional().describe('Maximum chunks to return, default 10'),
|
|
111
94
|
scope: scopeField,
|
|
112
95
|
}, async ({ source_ref, purpose, limit, scope }) => {
|
|
113
|
-
const
|
|
114
|
-
const config = readKnowledgeConfig(workspace.configPath);
|
|
115
|
-
const safetyPolicy = resolveSafetyPolicy(config, workspace);
|
|
96
|
+
const service = createKnowledgeService({ scope });
|
|
116
97
|
try {
|
|
117
|
-
const result = await
|
|
118
|
-
dbPath: workspace.knowledgeDbPath,
|
|
119
|
-
sourceRef: source_ref,
|
|
98
|
+
const result = await service.resolveSource(source_ref, {
|
|
120
99
|
purpose,
|
|
121
100
|
limit,
|
|
122
|
-
safetyPolicy,
|
|
123
101
|
});
|
|
124
102
|
return jsonText({ ok: true, ...result });
|
|
125
103
|
} catch (error) {
|
package/src/service.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { createArtifactStore } from './artifact-store';
|
|
2
|
+
import { consumeOpenFilesOutbox } from './outbox-consume';
|
|
3
|
+
import { getKnowledgeDbStats, migrateKnowledgeDb } from './knowledge-db';
|
|
4
|
+
import { ingestOpenFilesManifest } from './manifest-ingest';
|
|
5
|
+
import { ingestSourceRef } from './source-ingest';
|
|
6
|
+
import { resolveOpenFilesSource } from './source-resolver';
|
|
7
|
+
import { resolveSafetyPolicy } from './safety';
|
|
8
|
+
import { initializeWikiLayout } from './wiki-layout';
|
|
9
|
+
import {
|
|
10
|
+
ensureKnowledgeWorkspace,
|
|
11
|
+
readKnowledgeConfig,
|
|
12
|
+
resolveScopedWorkspace,
|
|
13
|
+
type KnowledgeConfig,
|
|
14
|
+
type KnowledgeWorkspace,
|
|
15
|
+
} from './workspace';
|
|
16
|
+
|
|
17
|
+
export interface KnowledgeServiceOptions {
|
|
18
|
+
scope?: string;
|
|
19
|
+
cwd?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface KnowledgePathsResult {
|
|
23
|
+
ok: true;
|
|
24
|
+
scope: string;
|
|
25
|
+
home: string;
|
|
26
|
+
config_path: string;
|
|
27
|
+
json_store_path: string;
|
|
28
|
+
knowledge_db_path: string;
|
|
29
|
+
artifacts_dir: string;
|
|
30
|
+
indexes_dir: string;
|
|
31
|
+
logs_dir: string;
|
|
32
|
+
runs_dir: string;
|
|
33
|
+
schemas_dir: string;
|
|
34
|
+
wiki_dir: string;
|
|
35
|
+
config: KnowledgeConfig;
|
|
36
|
+
message: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class KnowledgeService {
|
|
40
|
+
private ensuredWorkspace?: KnowledgeWorkspace;
|
|
41
|
+
private cachedConfig?: KnowledgeConfig;
|
|
42
|
+
|
|
43
|
+
constructor(private readonly options: KnowledgeServiceOptions = {}) {}
|
|
44
|
+
|
|
45
|
+
get scope(): string {
|
|
46
|
+
return this.options.scope ?? 'global';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get workspace(): KnowledgeWorkspace {
|
|
50
|
+
return this.ensuredWorkspace ?? resolveScopedWorkspace(this.options.scope, this.options.cwd);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
ensureWorkspace(): KnowledgeWorkspace {
|
|
54
|
+
if (!this.ensuredWorkspace) this.ensuredWorkspace = ensureKnowledgeWorkspace(this.workspace.home);
|
|
55
|
+
return this.ensuredWorkspace;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
jsonStorePath(): string {
|
|
59
|
+
return this.ensureWorkspace().jsonStorePath;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
config(): KnowledgeConfig {
|
|
63
|
+
if (!this.cachedConfig) {
|
|
64
|
+
const workspace = this.ensureWorkspace();
|
|
65
|
+
this.cachedConfig = readKnowledgeConfig(workspace.configPath);
|
|
66
|
+
}
|
|
67
|
+
return this.cachedConfig;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
safetyPolicy() {
|
|
71
|
+
return resolveSafetyPolicy(this.config(), this.ensureWorkspace());
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
artifactStore() {
|
|
75
|
+
return createArtifactStore(this.config(), this.ensureWorkspace());
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
paths(): KnowledgePathsResult {
|
|
79
|
+
const workspace = this.ensureWorkspace();
|
|
80
|
+
return {
|
|
81
|
+
ok: true,
|
|
82
|
+
scope: this.scope,
|
|
83
|
+
home: workspace.home,
|
|
84
|
+
config_path: workspace.configPath,
|
|
85
|
+
json_store_path: workspace.jsonStorePath,
|
|
86
|
+
knowledge_db_path: workspace.knowledgeDbPath,
|
|
87
|
+
artifacts_dir: workspace.artifactsDir,
|
|
88
|
+
indexes_dir: workspace.indexesDir,
|
|
89
|
+
logs_dir: workspace.logsDir,
|
|
90
|
+
runs_dir: workspace.runsDir,
|
|
91
|
+
schemas_dir: workspace.schemasDir,
|
|
92
|
+
wiki_dir: workspace.wikiDir,
|
|
93
|
+
config: this.config(),
|
|
94
|
+
message: workspace.home,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
initDb() {
|
|
99
|
+
return migrateKnowledgeDb(this.ensureWorkspace().knowledgeDbPath);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
dbStats() {
|
|
103
|
+
const workspace = this.ensureWorkspace();
|
|
104
|
+
migrateKnowledgeDb(workspace.knowledgeDbPath);
|
|
105
|
+
return getKnowledgeDbStats(workspace.knowledgeDbPath);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async initWiki() {
|
|
109
|
+
return initializeWikiLayout(this.artifactStore());
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async ingestManifest(input: string) {
|
|
113
|
+
const workspace = this.ensureWorkspace();
|
|
114
|
+
return ingestOpenFilesManifest({
|
|
115
|
+
dbPath: workspace.knowledgeDbPath,
|
|
116
|
+
input,
|
|
117
|
+
config: this.config(),
|
|
118
|
+
safetyPolicy: this.safetyPolicy(),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async ingestSource(sourceRef: string, purpose?: string) {
|
|
123
|
+
const workspace = this.ensureWorkspace();
|
|
124
|
+
return ingestSourceRef({
|
|
125
|
+
dbPath: workspace.knowledgeDbPath,
|
|
126
|
+
sourceRef,
|
|
127
|
+
purpose,
|
|
128
|
+
config: this.config(),
|
|
129
|
+
safetyPolicy: this.safetyPolicy(),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async resolveSource(sourceRef: string, options: { purpose?: string; limit?: number } = {}) {
|
|
134
|
+
const workspace = this.ensureWorkspace();
|
|
135
|
+
return resolveOpenFilesSource({
|
|
136
|
+
dbPath: workspace.knowledgeDbPath,
|
|
137
|
+
sourceRef,
|
|
138
|
+
purpose: options.purpose,
|
|
139
|
+
limit: options.limit,
|
|
140
|
+
safetyPolicy: this.safetyPolicy(),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async consumeOutbox(input: string) {
|
|
145
|
+
const workspace = this.ensureWorkspace();
|
|
146
|
+
return consumeOpenFilesOutbox({
|
|
147
|
+
dbPath: workspace.knowledgeDbPath,
|
|
148
|
+
input,
|
|
149
|
+
config: this.config(),
|
|
150
|
+
safetyPolicy: this.safetyPolicy(),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function createKnowledgeService(options: KnowledgeServiceOptions = {}): KnowledgeService {
|
|
156
|
+
return new KnowledgeService(options);
|
|
157
|
+
}
|