@hasna/knowledge 0.2.8 → 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 +22 -0
- package/bin/open-knowledge-mcp.js +1447 -34
- package/bin/open-knowledge.js +64 -59
- package/docs/architecture/ai-native-knowledge-base.md +10 -1
- package/package.json +2 -2
- package/src/cli.ts +33 -72
- package/src/manifest-ingest.ts +36 -10
- package/src/mcp.js +5 -27
- package/src/service.ts +157 -0
- package/src/source-ingest.ts +268 -0
package/src/cli.ts
CHANGED
|
@@ -5,14 +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 { consumeOpenFilesOutbox } from './outbox-consume';
|
|
14
|
-
import { resolveOpenFilesSource } from './source-resolver';
|
|
15
|
-
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';
|
|
16
11
|
import pkg from '../package.json' with { type: 'json' };
|
|
17
12
|
|
|
18
13
|
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
@@ -170,6 +165,7 @@ Commands:
|
|
|
170
165
|
wiki init Initialize scalable wiki/schema/index/log artifacts
|
|
171
166
|
source resolve <source-ref> Resolve read-only source content and citation evidence
|
|
172
167
|
ingest manifest <file|s3://> Ingest an open-files manifest into knowledge.db
|
|
168
|
+
ingest source <source-ref> Ingest a read-only source ref into knowledge.db
|
|
173
169
|
reindex outbox <file|s3://> Consume open-files change events and invalidate chunks
|
|
174
170
|
safety status|check|approve|audit|redact
|
|
175
171
|
help [command] Show help
|
|
@@ -235,7 +231,7 @@ function printCommandHelp(command: string): void {
|
|
|
235
231
|
if (command === 'db') { console.log('Usage: open-knowledge db init|stats [--scope local|global|project] [--json]'); return; }
|
|
236
232
|
if (command === 'wiki') { console.log('Usage: open-knowledge wiki init [--scope local|global|project] [--json]'); return; }
|
|
237
233
|
if (command === 'source') { console.log('Usage: open-knowledge source resolve <source-ref> [--purpose knowledge_answer|knowledge_index] [--limit <n>] [--scope local|global|project] [--json]'); return; }
|
|
238
|
-
if (command === 'ingest') { console.log('Usage: open-knowledge ingest manifest <file|s3://bucket/key> [--scope local|global|project] [--json]'); return; }
|
|
234
|
+
if (command === 'ingest') { console.log('Usage: open-knowledge ingest manifest <file|s3://bucket/key> | source <source-ref> [--purpose knowledge_index] [--scope local|global|project] [--json]'); return; }
|
|
239
235
|
if (command === 'reindex') { console.log('Usage: open-knowledge reindex outbox <file|s3://bucket/key> [--scope local|global|project] [--json]'); return; }
|
|
240
236
|
if (command === 'safety') { console.log('Usage: open-knowledge safety status|check|approve|audit|redact [args] [--scope local|global|project] [--json]'); return; }
|
|
241
237
|
printGlobalHelp();
|
|
@@ -297,71 +293,49 @@ async function run(argv: string[]): Promise<void> {
|
|
|
297
293
|
|
|
298
294
|
if (!command || flags.help || command === 'help') { printCommandHelp(positional[1]); return; }
|
|
299
295
|
|
|
300
|
-
const
|
|
296
|
+
const service = createKnowledgeService({ scope: flags.scope });
|
|
301
297
|
let storePath = flags.store;
|
|
302
298
|
if (!storePath) {
|
|
303
299
|
if (flags.scope === 'project' || flags.scope === 'local') {
|
|
304
|
-
storePath =
|
|
300
|
+
storePath = service.jsonStorePath();
|
|
305
301
|
} else {
|
|
306
302
|
storePath = defaultStorePath();
|
|
307
303
|
}
|
|
308
304
|
}
|
|
309
305
|
|
|
310
306
|
if (command === 'paths') {
|
|
311
|
-
|
|
312
|
-
output({
|
|
313
|
-
ok: true,
|
|
314
|
-
scope: flags.scope ?? 'global',
|
|
315
|
-
home: resolvedWorkspace.home,
|
|
316
|
-
config_path: resolvedWorkspace.configPath,
|
|
317
|
-
json_store_path: resolvedWorkspace.jsonStorePath,
|
|
318
|
-
knowledge_db_path: resolvedWorkspace.knowledgeDbPath,
|
|
319
|
-
artifacts_dir: resolvedWorkspace.artifactsDir,
|
|
320
|
-
indexes_dir: resolvedWorkspace.indexesDir,
|
|
321
|
-
logs_dir: resolvedWorkspace.logsDir,
|
|
322
|
-
runs_dir: resolvedWorkspace.runsDir,
|
|
323
|
-
schemas_dir: resolvedWorkspace.schemasDir,
|
|
324
|
-
wiki_dir: resolvedWorkspace.wikiDir,
|
|
325
|
-
config: readKnowledgeConfig(resolvedWorkspace.configPath),
|
|
326
|
-
message: resolvedWorkspace.home,
|
|
327
|
-
}, flags.json);
|
|
307
|
+
output(service.paths(), flags.json);
|
|
328
308
|
return;
|
|
329
309
|
}
|
|
330
310
|
|
|
331
311
|
if (command === 'db') {
|
|
332
312
|
const action = positional[1] ?? 'init';
|
|
333
|
-
const resolvedWorkspace = ensureKnowledgeWorkspace(workspace.home);
|
|
334
313
|
if (action !== 'init' && action !== 'stats') {
|
|
335
314
|
throw new Error("Invalid db action. Use 'init' or 'stats'.");
|
|
336
315
|
}
|
|
337
316
|
if (action === 'init') {
|
|
338
|
-
const result =
|
|
317
|
+
const result = service.initDb();
|
|
339
318
|
output({ ok: true, ...result, message: `Initialized ${result.path}` }, flags.json);
|
|
340
319
|
return;
|
|
341
320
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
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);
|
|
345
323
|
return;
|
|
346
324
|
}
|
|
347
325
|
|
|
348
326
|
if (command === 'wiki') {
|
|
349
327
|
const action = positional[1] ?? 'init';
|
|
350
328
|
if (action !== 'init') throw new Error("Invalid wiki action. Use 'init'.");
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
const artifactStore = createArtifactStore(config, resolvedWorkspace);
|
|
354
|
-
const result = await initializeWikiLayout(artifactStore);
|
|
355
|
-
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);
|
|
356
331
|
return;
|
|
357
332
|
}
|
|
358
333
|
|
|
359
334
|
if (command === 'safety') {
|
|
360
335
|
const action = positional[1] ?? 'status';
|
|
361
|
-
const resolvedWorkspace =
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
migrateKnowledgeDb(resolvedWorkspace.knowledgeDbPath);
|
|
336
|
+
const resolvedWorkspace = service.ensureWorkspace();
|
|
337
|
+
const policy = service.safetyPolicy();
|
|
338
|
+
service.initDb();
|
|
365
339
|
const db = openKnowledgeDb(resolvedWorkspace.knowledgeDbPath);
|
|
366
340
|
try {
|
|
367
341
|
if (action === 'status') {
|
|
@@ -487,15 +461,9 @@ async function run(argv: string[]): Promise<void> {
|
|
|
487
461
|
if (action !== 'resolve') throw new Error("Invalid source action. Use 'resolve'.");
|
|
488
462
|
const sourceRef = positional[2];
|
|
489
463
|
if (!sourceRef) throw new Error('Usage: open-knowledge source resolve <source-ref>');
|
|
490
|
-
const
|
|
491
|
-
const config = readKnowledgeConfig(resolvedWorkspace.configPath);
|
|
492
|
-
const safetyPolicy = resolveSafetyPolicy(config, resolvedWorkspace);
|
|
493
|
-
const result = await resolveOpenFilesSource({
|
|
494
|
-
dbPath: resolvedWorkspace.knowledgeDbPath,
|
|
495
|
-
sourceRef,
|
|
464
|
+
const result = await service.resolveSource(sourceRef, {
|
|
496
465
|
purpose: flags.purpose,
|
|
497
466
|
limit: flags.limit,
|
|
498
|
-
safetyPolicy,
|
|
499
467
|
});
|
|
500
468
|
output({
|
|
501
469
|
ok: true,
|
|
@@ -509,20 +477,21 @@ async function run(argv: string[]): Promise<void> {
|
|
|
509
477
|
|
|
510
478
|
if (command === 'ingest') {
|
|
511
479
|
const action = positional[1] ?? '';
|
|
512
|
-
if (action
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
480
|
+
if (action === 'manifest') {
|
|
481
|
+
const input = positional[2];
|
|
482
|
+
if (!input) throw new Error('Usage: open-knowledge ingest manifest <file|s3://bucket/key>');
|
|
483
|
+
const result = await service.ingestManifest(input);
|
|
484
|
+
output({ ok: true, ...result, message: `Ingested ${result.items_seen} manifest item(s)` }, flags.json);
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
if (action === 'source') {
|
|
488
|
+
const sourceRef = positional[2];
|
|
489
|
+
if (!sourceRef) throw new Error('Usage: open-knowledge ingest source <source-ref>');
|
|
490
|
+
const result = await service.ingestSource(sourceRef, flags.purpose);
|
|
491
|
+
output({ ok: true, ...result, message: `Ingested source ${result.source_ref} (${result.chunks_inserted} chunks)` }, flags.json);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
throw new Error("Invalid ingest action. Use 'manifest' or 'source'.");
|
|
526
495
|
}
|
|
527
496
|
|
|
528
497
|
if (command === 'reindex') {
|
|
@@ -530,15 +499,7 @@ async function run(argv: string[]): Promise<void> {
|
|
|
530
499
|
if (action !== 'outbox') throw new Error("Invalid reindex action. Use 'outbox'.");
|
|
531
500
|
const input = positional[2];
|
|
532
501
|
if (!input) throw new Error('Usage: open-knowledge reindex outbox <file|s3://bucket/key>');
|
|
533
|
-
const
|
|
534
|
-
const config = readKnowledgeConfig(resolvedWorkspace.configPath);
|
|
535
|
-
const safetyPolicy = resolveSafetyPolicy(config, resolvedWorkspace);
|
|
536
|
-
const result = await consumeOpenFilesOutbox({
|
|
537
|
-
dbPath: resolvedWorkspace.knowledgeDbPath,
|
|
538
|
-
input,
|
|
539
|
-
config,
|
|
540
|
-
safetyPolicy,
|
|
541
|
-
});
|
|
502
|
+
const result = await service.consumeOutbox(input);
|
|
542
503
|
output({ ok: true, ...result, message: `Consumed ${result.events_seen} outbox event(s)` }, flags.json);
|
|
543
504
|
return;
|
|
544
505
|
}
|
package/src/manifest-ingest.ts
CHANGED
|
@@ -24,6 +24,17 @@ export interface ManifestIngestOptions {
|
|
|
24
24
|
chunkOverlapChars?: number;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
export interface ManifestItemsIngestOptions {
|
|
28
|
+
dbPath: string;
|
|
29
|
+
items: ManifestObject[];
|
|
30
|
+
sourceLabel: string;
|
|
31
|
+
readAction?: string;
|
|
32
|
+
safetyPolicy?: SafetyPolicy;
|
|
33
|
+
now?: Date;
|
|
34
|
+
maxChunkChars?: number;
|
|
35
|
+
chunkOverlapChars?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
export interface ManifestIngestResult {
|
|
28
39
|
path: string;
|
|
29
40
|
db_path: string;
|
|
@@ -36,7 +47,7 @@ export interface ManifestIngestResult {
|
|
|
36
47
|
skipped: number;
|
|
37
48
|
}
|
|
38
49
|
|
|
39
|
-
type ManifestObject = Record<string, unknown>;
|
|
50
|
+
export type ManifestObject = Record<string, unknown>;
|
|
40
51
|
|
|
41
52
|
interface NormalizedManifestItem {
|
|
42
53
|
raw: ManifestObject;
|
|
@@ -405,6 +416,23 @@ function insertChunks(db: Database, sourceRevisionId: string, item: NormalizedMa
|
|
|
405
416
|
}
|
|
406
417
|
|
|
407
418
|
export async function ingestOpenFilesManifest(options: ManifestIngestOptions): Promise<ManifestIngestResult> {
|
|
419
|
+
const now = options.now ?? new Date();
|
|
420
|
+
if (options.safetyPolicy) assertWriteAllowed(options.dbPath, options.safetyPolicy);
|
|
421
|
+
migrateKnowledgeDb(options.dbPath);
|
|
422
|
+
const text = await readManifestInput(options.input, options.config, options.safetyPolicy);
|
|
423
|
+
const items = parseManifestText(text);
|
|
424
|
+
return ingestOpenFilesManifestItems({
|
|
425
|
+
dbPath: options.dbPath,
|
|
426
|
+
items,
|
|
427
|
+
sourceLabel: options.input,
|
|
428
|
+
safetyPolicy: options.safetyPolicy,
|
|
429
|
+
now,
|
|
430
|
+
maxChunkChars: options.maxChunkChars,
|
|
431
|
+
chunkOverlapChars: options.chunkOverlapChars,
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export async function ingestOpenFilesManifestItems(options: ManifestItemsIngestOptions): Promise<ManifestIngestResult> {
|
|
408
436
|
const now = (options.now ?? new Date()).toISOString();
|
|
409
437
|
const maxChunkChars = options.maxChunkChars ?? 4000;
|
|
410
438
|
const chunkOverlapChars = options.chunkOverlapChars ?? 200;
|
|
@@ -413,8 +441,6 @@ export async function ingestOpenFilesManifest(options: ManifestIngestOptions): P
|
|
|
413
441
|
|
|
414
442
|
if (options.safetyPolicy) assertWriteAllowed(options.dbPath, options.safetyPolicy);
|
|
415
443
|
migrateKnowledgeDb(options.dbPath);
|
|
416
|
-
const text = await readManifestInput(options.input, options.config, options.safetyPolicy);
|
|
417
|
-
const items = parseManifestText(text);
|
|
418
444
|
const db = openKnowledgeDb(options.dbPath);
|
|
419
445
|
try {
|
|
420
446
|
const result = db.transaction(() => {
|
|
@@ -426,13 +452,13 @@ export async function ingestOpenFilesManifest(options: ManifestIngestOptions): P
|
|
|
426
452
|
let skipped = 0;
|
|
427
453
|
recordAuditEvent(db, {
|
|
428
454
|
event_type: 'source_read',
|
|
429
|
-
action: options.
|
|
430
|
-
target_uri: options.
|
|
455
|
+
action: options.readAction ?? (options.sourceLabel.startsWith('s3://') ? 's3_manifest_read' : 'local_manifest_read'),
|
|
456
|
+
target_uri: options.sourceLabel,
|
|
431
457
|
decision: 'allow',
|
|
432
|
-
metadata: { items: items.length, read_only: true },
|
|
458
|
+
metadata: { items: options.items.length, read_only: true },
|
|
433
459
|
created_at: now,
|
|
434
460
|
});
|
|
435
|
-
for (const raw of items) {
|
|
461
|
+
for (const raw of options.items) {
|
|
436
462
|
const item = normalizeManifestItem(raw, now);
|
|
437
463
|
const sourceId = upsertSource(db, item, now);
|
|
438
464
|
const revisionId = upsertRevision(db, sourceId, item, now);
|
|
@@ -450,13 +476,13 @@ export async function ingestOpenFilesManifest(options: ManifestIngestOptions): P
|
|
|
450
476
|
action: 'knowledge_manifest_ingest',
|
|
451
477
|
target_uri: options.dbPath,
|
|
452
478
|
decision: 'allow',
|
|
453
|
-
metadata: { items: items.length, sources: seenSources.size, revisions: seenRevisions.size, chunks_inserted: chunksInserted, redactions },
|
|
479
|
+
metadata: { items: options.items.length, sources: seenSources.size, revisions: seenRevisions.size, chunks_inserted: chunksInserted, redactions },
|
|
454
480
|
created_at: now,
|
|
455
481
|
});
|
|
456
482
|
return {
|
|
457
|
-
path: options.
|
|
483
|
+
path: options.sourceLabel,
|
|
458
484
|
db_path: options.dbPath,
|
|
459
|
-
items_seen: items.length,
|
|
485
|
+
items_seen: options.items.length,
|
|
460
486
|
sources_upserted: seenSources.size,
|
|
461
487
|
revisions_upserted: seenRevisions.size,
|
|
462
488
|
chunks_inserted: chunksInserted,
|
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
|
+
}
|