@pellux/goodvibes-sdk 0.33.10 → 0.33.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.
Files changed (40) hide show
  1. package/dist/browser-knowledge.d.ts +1 -1
  2. package/dist/browser-knowledge.d.ts.map +1 -1
  3. package/dist/browser-knowledge.js +1 -1
  4. package/dist/contracts/artifacts/operator-contract.json +75 -2
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/platform/control-plane/method-catalog-knowledge.d.ts.map +1 -1
  8. package/dist/platform/control-plane/method-catalog-knowledge.js +16 -7
  9. package/dist/platform/control-plane/routes/operator.js +2 -2
  10. package/dist/platform/daemon/http/router-route-contexts.d.ts.map +1 -1
  11. package/dist/platform/daemon/http/router-route-contexts.js +8 -8
  12. package/dist/platform/knowledge/graphql-schema.d.ts +1 -1
  13. package/dist/platform/knowledge/graphql-schema.d.ts.map +1 -1
  14. package/dist/platform/knowledge/graphql-schema.js +13 -11
  15. package/dist/platform/knowledge/graphql.d.ts.map +1 -1
  16. package/dist/platform/knowledge/graphql.js +51 -25
  17. package/dist/platform/knowledge/index.d.ts +1 -1
  18. package/dist/platform/knowledge/index.d.ts.map +1 -1
  19. package/dist/platform/knowledge/map-filters.d.ts +3 -0
  20. package/dist/platform/knowledge/map-filters.d.ts.map +1 -1
  21. package/dist/platform/knowledge/map-filters.js +20 -0
  22. package/dist/platform/knowledge/map.d.ts +2 -0
  23. package/dist/platform/knowledge/map.d.ts.map +1 -1
  24. package/dist/platform/knowledge/map.js +1 -6
  25. package/dist/platform/knowledge/packet.d.ts +6 -5
  26. package/dist/platform/knowledge/packet.d.ts.map +1 -1
  27. package/dist/platform/knowledge/packet.js +13 -8
  28. package/dist/platform/knowledge/projections.d.ts +12 -1
  29. package/dist/platform/knowledge/projections.d.ts.map +1 -1
  30. package/dist/platform/knowledge/projections.js +153 -91
  31. package/dist/platform/knowledge/service.d.ts +27 -7
  32. package/dist/platform/knowledge/service.d.ts.map +1 -1
  33. package/dist/platform/knowledge/service.js +66 -6
  34. package/dist/platform/knowledge/spaces.d.ts +6 -0
  35. package/dist/platform/knowledge/spaces.d.ts.map +1 -1
  36. package/dist/platform/knowledge/spaces.js +9 -0
  37. package/dist/platform/knowledge/types.d.ts +2 -0
  38. package/dist/platform/knowledge/types.d.ts.map +1 -1
  39. package/dist/platform/version.js +1 -1
  40. package/package.json +9 -9
@@ -1,4 +1,5 @@
1
1
  import { generatedKnowledgeCanonicalUri, generatedKnowledgeSourceId, isGeneratedKnowledgeSource, materializeGeneratedKnowledgeProjection, } from './generated-projections.js';
2
+ import { isInKnowledgeSpaceScope, resolveKnowledgeSpaceScope, } from './spaces.js';
2
3
  import { buildBulletList, dedupe, formatDateTime, joinSections, materializedTargetReference, quote, slugify, sortByTitle, } from './projection-utils.js';
3
4
  export class KnowledgeProjectionService {
4
5
  store;
@@ -9,16 +10,16 @@ export class KnowledgeProjectionService {
9
10
  this.artifactStore = artifactStore;
10
11
  this.getConnectors = options.connectors ?? (() => []);
11
12
  }
12
- async listTargets(limit = 25) {
13
+ async listTargets(limit = 25, scope = {}) {
13
14
  await this.store.init();
14
15
  const max = Math.max(1, limit);
15
- const targets = [this.createPresetTarget('overview'), this.createPresetTarget('bundle')];
16
+ const targets = [this.createPresetTarget('overview', scope), this.createPresetTarget('bundle', scope)];
16
17
  const remaining = Math.max(1, max - targets.length);
17
18
  const perKind = Math.max(1, Math.ceil(remaining / 4));
18
- const sources = this.store.listSources(perKind).map((source) => this.createSourceTarget(source));
19
- const nodes = this.store.listNodes(perKind).map((node) => this.createNodeTarget(node));
20
- const issues = this.store.listIssues(perKind).map((issue) => this.createIssueTarget(issue));
21
- const rollups = this.store.listNodes(Number.MAX_SAFE_INTEGER)
19
+ const sources = this.scopedSources(scope, perKind).map((source) => this.createSourceTarget(source));
20
+ const nodes = this.scopedNodes(scope, perKind).map((node) => this.createNodeTarget(node));
21
+ const issues = this.scopedIssues(scope, perKind).map((issue) => this.createIssueTarget(issue));
22
+ const rollups = this.scopedNodes(scope)
22
23
  .filter((node) => node.kind === 'domain' || node.kind === 'topic' || node.kind === 'bookmark_folder')
23
24
  .slice(0, Math.max(2, perKind))
24
25
  .map((node) => this.createRollupTarget(node));
@@ -28,27 +29,28 @@ export class KnowledgeProjectionService {
28
29
  async render(input) {
29
30
  await this.store.init();
30
31
  const limit = Math.max(1, input.limit ?? 12);
31
- const target = this.resolveTarget(input.kind, input.id);
32
+ const scope = projectionScope(input);
33
+ const target = this.resolveTarget(input.kind, input.id, scope);
32
34
  if (!target) {
33
35
  throw new Error(`Unknown knowledge projection target: ${input.kind}${input.id ? `/${input.id}` : ''}`);
34
36
  }
35
37
  switch (target.kind) {
36
38
  case 'overview':
37
- return this.bundleFromPages(target, [this.renderOverviewPage(target, limit)], { preset: 'overview' });
39
+ return this.bundleFromPages(target, [this.renderOverviewPage(target, limit, scope)], { preset: 'overview' }, scope);
38
40
  case 'bundle':
39
- return this.renderBundleTarget(target, limit);
41
+ return this.renderBundleTarget(target, limit, scope);
40
42
  case 'source':
41
- return this.bundleFromPages(target, [this.renderSourcePage(target.itemId)], {});
43
+ return this.bundleFromPages(target, [this.renderSourcePage(target.itemId, scope)], {}, scope);
42
44
  case 'node':
43
- return this.bundleFromPages(target, [this.renderNodePage(target.itemId)], {});
45
+ return this.bundleFromPages(target, [this.renderNodePage(target.itemId, scope)], {}, scope);
44
46
  case 'issue':
45
- return this.bundleFromPages(target, [this.renderIssuePage(target.itemId)], {});
47
+ return this.bundleFromPages(target, [this.renderIssuePage(target.itemId, scope)], {}, scope);
46
48
  case 'dashboard':
47
- return this.bundleFromPages(target, [this.renderDashboardPage(target, limit)], { preset: 'dashboard' });
49
+ return this.bundleFromPages(target, [this.renderDashboardPage(target, limit, scope)], { preset: 'dashboard' }, scope);
48
50
  case 'rollup':
49
- return this.bundleFromPages(target, [this.renderRollupPage(target.itemId, target)], { preset: 'rollup' });
51
+ return this.bundleFromPages(target, [this.renderRollupPage(target.itemId, target, scope)], { preset: 'rollup' }, scope);
50
52
  default:
51
- return this.bundleFromPages(target, [this.renderOverviewPage(this.createPresetTarget('overview'), limit)], {});
53
+ return this.bundleFromPages(target, [this.renderOverviewPage(this.createPresetTarget('overview', scope), limit, scope)], {}, scope);
52
54
  }
53
55
  }
54
56
  async materialize(input) {
@@ -91,31 +93,33 @@ export class KnowledgeProjectionService {
91
93
  artifactCreated: generated.artifactCreated,
92
94
  };
93
95
  }
94
- resolveTarget(kind, id) {
96
+ resolveTarget(kind, id, scope) {
95
97
  if (kind === 'overview' || kind === 'bundle')
96
- return this.createPresetTarget(kind);
98
+ return this.createPresetTarget(kind, scope);
97
99
  if (kind === 'dashboard')
98
100
  return this.createDashboardTarget(id ?? 'source-health');
99
101
  if (kind === 'rollup') {
100
102
  if (!id?.trim())
101
103
  return null;
102
104
  const node = this.store.getNode(id);
103
- return node ? this.createRollupTarget(node) : null;
105
+ return node && isInKnowledgeSpaceScope(node, scope) ? this.createRollupTarget(node) : null;
104
106
  }
105
107
  if (!id?.trim())
106
108
  return null;
107
109
  if (kind === 'source') {
108
110
  const source = this.store.getSource(id);
109
- return source ? this.createSourceTarget(source) : null;
111
+ return source && isInKnowledgeSpaceScope(source, scope) ? this.createSourceTarget(source) : null;
110
112
  }
111
113
  if (kind === 'node') {
112
114
  const node = this.store.getNode(id);
113
- return node ? this.createNodeTarget(node) : null;
115
+ return node && isInKnowledgeSpaceScope(node, scope) ? this.createNodeTarget(node) : null;
114
116
  }
115
117
  const issue = this.store.getIssue(id);
116
- return issue ? this.createIssueTarget(issue) : null;
118
+ return issue && isInKnowledgeSpaceScope(issue, scope) ? this.createIssueTarget(issue) : null;
117
119
  }
118
- createPresetTarget(kind) {
120
+ createPresetTarget(kind, scope) {
121
+ const spaceId = resolveKnowledgeSpaceScope(scope);
122
+ const metadata = spaceId === null ? { includeAllSpaces: true } : { knowledgeSpaceId: spaceId };
119
123
  if (kind === 'overview') {
120
124
  return {
121
125
  targetId: 'overview',
@@ -124,7 +128,7 @@ export class KnowledgeProjectionService {
124
128
  description: 'A compact markdown projection of the current structured knowledge store.',
125
129
  defaultPath: 'wiki/index.md',
126
130
  defaultFilename: 'knowledge-overview.md',
127
- metadata: {},
131
+ metadata,
128
132
  };
129
133
  }
130
134
  return {
@@ -134,7 +138,7 @@ export class KnowledgeProjectionService {
134
138
  description: 'A multi-page markdown bundle containing indexes, dashboards, and recent records.',
135
139
  defaultPath: 'wiki/bundle/index.md',
136
140
  defaultFilename: 'knowledge-bundle.md',
137
- metadata: {},
141
+ metadata,
138
142
  };
139
143
  }
140
144
  createDashboardTarget(id) {
@@ -221,21 +225,25 @@ export class KnowledgeProjectionService {
221
225
  },
222
226
  };
223
227
  }
224
- renderOverviewPage(target, limit) {
225
- const status = this.store.status();
226
- const sources = this.store.listSources(limit);
227
- const nodes = this.store.listNodes(limit);
228
- const issues = this.store.listIssues(limit);
228
+ renderOverviewPage(target, limit, scope) {
229
+ const sources = this.scopedSources(scope, limit);
230
+ const nodes = this.scopedNodes(scope, limit);
231
+ const issues = this.scopedIssues(scope, limit);
232
+ const allSources = this.scopedSources(scope);
233
+ const allNodes = this.scopedNodes(scope);
234
+ const allIssues = this.scopedIssues(scope);
235
+ const edgeCount = this.store.listEdges().filter((edge) => this.edgeInScope(edge, scope)).length;
236
+ const extractionCount = this.scopedExtractions(scope).length;
229
237
  const connectors = this.getConnectors();
230
238
  const runs = this.store.listJobRuns(5);
231
239
  const content = joinSections(`# ${target.title}`, 'Structured knowledge is canonical in SQL. This markdown page is a derived projection for clients, exports, and future wiki-style surfaces.', [
232
240
  '## Counts',
233
- `- sources: ${status.sourceCount}`,
234
- `- nodes: ${status.nodeCount}`,
235
- `- edges: ${status.edgeCount}`,
236
- `- issues: ${status.issueCount}`,
237
- `- extractions: ${status.extractionCount}`,
238
- `- job runs: ${status.jobRunCount}`,
241
+ `- sources: ${allSources.length}`,
242
+ `- nodes: ${allNodes.length}`,
243
+ `- edges: ${edgeCount}`,
244
+ `- issues: ${allIssues.length}`,
245
+ `- extractions: ${extractionCount}`,
246
+ `- job runs: ${this.store.listJobRuns(Number.MAX_SAFE_INTEGER).length}`,
239
247
  ].join('\n'), [
240
248
  '## Connectors',
241
249
  buildBulletList(connectors.map((connector) => `\`${connector.id}\` - ${connector.description}`)),
@@ -263,8 +271,8 @@ export class KnowledgeProjectionService {
263
271
  },
264
272
  };
265
273
  }
266
- renderSourceIndexPage(limit) {
267
- const sources = sortByTitle(this.store.listSources(Number.MAX_SAFE_INTEGER).slice(0, limit));
274
+ renderSourceIndexPage(limit, scope) {
275
+ const sources = sortByTitle(this.scopedSources(scope).slice(0, limit));
268
276
  const lines = [
269
277
  '# Sources Index',
270
278
  '',
@@ -285,8 +293,8 @@ export class KnowledgeProjectionService {
285
293
  },
286
294
  };
287
295
  }
288
- renderNodeIndexPage(limit) {
289
- const nodes = sortByTitle(this.store.listNodes(Number.MAX_SAFE_INTEGER).slice(0, limit));
296
+ renderNodeIndexPage(limit, scope) {
297
+ const nodes = sortByTitle(this.scopedNodes(scope).slice(0, limit));
290
298
  const grouped = new Map();
291
299
  for (const node of nodes) {
292
300
  const bucket = grouped.get(node.kind) ?? [];
@@ -308,8 +316,8 @@ export class KnowledgeProjectionService {
308
316
  },
309
317
  };
310
318
  }
311
- renderIssueDashboardPage(limit) {
312
- const issues = this.store.listIssues(limit);
319
+ renderIssueDashboardPage(limit, scope) {
320
+ const issues = this.scopedIssues(scope, limit);
313
321
  const severityGroups = ['error', 'warning', 'info'].map((severity) => [
314
322
  `## ${severity.toUpperCase()}`,
315
323
  buildBulletList(issues
@@ -327,10 +335,11 @@ export class KnowledgeProjectionService {
327
335
  },
328
336
  };
329
337
  }
330
- renderBacklinksPage(limit) {
331
- const items = this.store.listSources(limit).map((source) => {
338
+ renderBacklinksPage(limit, scope) {
339
+ const items = this.scopedSources(scope, limit).map((source) => {
332
340
  const incoming = this.store.listEdges()
333
- .filter((edge) => edge.toKind === 'source' && edge.toId === source.id);
341
+ .filter((edge) => edge.toKind === 'source' && edge.toId === source.id)
342
+ .filter((edge) => this.edgeInScope(edge, scope));
334
343
  return { source, incoming };
335
344
  }).filter((entry) => entry.incoming.length > 0);
336
345
  const content = [
@@ -341,11 +350,11 @@ export class KnowledgeProjectionService {
341
350
  buildBulletList(entry.incoming.map((edge) => {
342
351
  if (edge.fromKind === 'source') {
343
352
  const linked = this.store.getSource(edge.fromId);
344
- return linked ? `${this.linkToTarget(this.createSourceTarget(linked))} via \`${edge.relation}\`` : `source:${edge.fromId}`;
353
+ return linked && isInKnowledgeSpaceScope(linked, scope) ? `${this.linkToTarget(this.createSourceTarget(linked))} via \`${edge.relation}\`` : `source:${edge.fromId}`;
345
354
  }
346
355
  if (edge.fromKind === 'node') {
347
356
  const node = this.store.getNode(edge.fromId);
348
- return node ? `${this.linkToTarget(this.createNodeTarget(node))} via \`${edge.relation}\`` : `node:${edge.fromId}`;
357
+ return node && isInKnowledgeSpaceScope(node, scope) ? `${this.linkToTarget(this.createNodeTarget(node))} via \`${edge.relation}\`` : `node:${edge.fromId}`;
349
358
  }
350
359
  return `${edge.fromKind}:${edge.fromId} via \`${edge.relation}\``;
351
360
  })),
@@ -362,8 +371,8 @@ export class KnowledgeProjectionService {
362
371
  },
363
372
  };
364
373
  }
365
- renderHealthDashboardPage(limit) {
366
- const sources = this.store.listSources(limit);
374
+ renderHealthDashboardPage(limit, scope) {
375
+ const sources = this.scopedSources(scope, limit);
367
376
  const staleThreshold = Date.now() - (14 * 24 * 60 * 60 * 1000);
368
377
  const unhealthy = sources.filter((source) => (source.status !== 'indexed'
369
378
  || Boolean(source.crawlError)
@@ -395,19 +404,20 @@ export class KnowledgeProjectionService {
395
404
  },
396
405
  };
397
406
  }
398
- renderSourcePage(id) {
407
+ renderSourcePage(id, scope) {
399
408
  const source = this.store.getSource(id);
400
- if (!source)
409
+ if (!source || !isInKnowledgeSpaceScope(source, scope))
401
410
  throw new Error(`Unknown knowledge source: ${id}`);
402
411
  const extraction = this.store.getExtractionBySourceId(id);
403
412
  const view = this.store.getItem(id);
404
413
  const target = this.createSourceTarget(source);
405
414
  const relatedNodes = view?.linkedNodes ?? [];
406
415
  const relatedSources = view?.linkedSources.filter((entry) => (entry.id !== source.id && !isGeneratedKnowledgeSource(entry))) ?? [];
407
- const issues = this.store.listIssues(Number.MAX_SAFE_INTEGER).filter((issue) => issue.sourceId === source.id);
416
+ const issues = this.scopedIssues(scope).filter((issue) => issue.sourceId === source.id);
408
417
  const incoming = this.store.listEdges().filter((edge) => (edge.toKind === 'source'
409
418
  && edge.toId === source.id
410
- && !this.isGeneratedSourceReference(edge.fromKind, edge.fromId)));
419
+ && !this.isGeneratedSourceReference(edge.fromKind, edge.fromId)
420
+ && this.edgeInScope(edge, scope)));
411
421
  const content = joinSections(`# ${target.title}`, extraction?.summary ?? source.summary, [
412
422
  '## Metadata',
413
423
  `- id: \`${source.id}\``,
@@ -428,10 +438,10 @@ export class KnowledgeProjectionService {
428
438
  ...(extraction.links.length > 0 ? [`- links: ${extraction.links.join(', ')}`] : []),
429
439
  ].join('\n') : null, extraction?.excerpt ? ['## Excerpt', extraction.excerpt].join('\n') : null, [
430
440
  '## Related Nodes',
431
- buildBulletList(relatedNodes.map((node) => this.linkToTarget(this.createNodeTarget(node), `${node.title} (${node.kind})`))),
441
+ buildBulletList(relatedNodes.filter((node) => isInKnowledgeSpaceScope(node, scope)).map((node) => this.linkToTarget(this.createNodeTarget(node), `${node.title} (${node.kind})`))),
432
442
  ].join('\n'), [
433
443
  '## Related Sources',
434
- buildBulletList(relatedSources.map((entry) => this.linkToTarget(this.createSourceTarget(entry)))),
444
+ buildBulletList(relatedSources.filter((entry) => isInKnowledgeSpaceScope(entry, scope)).map((entry) => this.linkToTarget(this.createSourceTarget(entry)))),
435
445
  ].join('\n'), [
436
446
  '## Backlinks',
437
447
  buildBulletList(incoming.map((edge) => `${edge.fromKind}:${edge.fromId} via \`${edge.relation}\``)),
@@ -452,13 +462,13 @@ export class KnowledgeProjectionService {
452
462
  },
453
463
  };
454
464
  }
455
- renderNodePage(id) {
465
+ renderNodePage(id, scope) {
456
466
  const node = this.store.getNode(id);
457
- if (!node)
467
+ if (!node || !isInKnowledgeSpaceScope(node, scope))
458
468
  throw new Error(`Unknown knowledge node: ${id}`);
459
469
  const view = this.store.getItem(id);
460
470
  const target = this.createNodeTarget(node);
461
- const incoming = this.store.listEdges().filter((edge) => edge.toKind === 'node' && edge.toId === node.id);
471
+ const incoming = this.store.listEdges().filter((edge) => edge.toKind === 'node' && edge.toId === node.id && this.edgeInScope(edge, scope));
462
472
  const content = joinSections(`# ${target.title}`, node.summary, [
463
473
  '## Metadata',
464
474
  `- id: \`${node.id}\``,
@@ -472,10 +482,11 @@ export class KnowledgeProjectionService {
472
482
  '## Linked Sources',
473
483
  buildBulletList((view?.linkedSources ?? [])
474
484
  .filter((source) => !isGeneratedKnowledgeSource(source))
485
+ .filter((source) => isInKnowledgeSpaceScope(source, scope))
475
486
  .map((source) => this.linkToTarget(this.createSourceTarget(source)))),
476
487
  ].join('\n'), [
477
488
  '## Linked Nodes',
478
- buildBulletList((view?.linkedNodes ?? []).filter((entry) => entry.id !== node.id).map((entry) => this.linkToTarget(this.createNodeTarget(entry), `${entry.title} (${entry.kind})`))),
489
+ buildBulletList((view?.linkedNodes ?? []).filter((entry) => entry.id !== node.id && isInKnowledgeSpaceScope(entry, scope)).map((entry) => this.linkToTarget(this.createNodeTarget(entry), `${entry.title} (${entry.kind})`))),
479
490
  ].join('\n'), [
480
491
  '## Backlinks',
481
492
  buildBulletList(incoming
@@ -483,7 +494,7 @@ export class KnowledgeProjectionService {
483
494
  .map((edge) => `${edge.fromKind}:${edge.fromId} via \`${edge.relation}\``)),
484
495
  ].join('\n'), [
485
496
  '## Issues',
486
- buildBulletList(this.store.listIssues(Number.MAX_SAFE_INTEGER)
497
+ buildBulletList(this.scopedIssues(scope)
487
498
  .filter((issue) => issue.nodeId === node.id)
488
499
  .map((issue) => this.linkToTarget(this.createIssueTarget(issue), `${issue.severity.toUpperCase()} ${issue.code}: ${issue.message}`))),
489
500
  ].join('\n'));
@@ -499,13 +510,15 @@ export class KnowledgeProjectionService {
499
510
  },
500
511
  };
501
512
  }
502
- renderIssuePage(id) {
513
+ renderIssuePage(id, scope) {
503
514
  const issue = this.store.getIssue(id);
504
- if (!issue)
515
+ if (!issue || !isInKnowledgeSpaceScope(issue, scope))
505
516
  throw new Error(`Unknown knowledge issue: ${id}`);
506
517
  const target = this.createIssueTarget(issue);
507
- const source = issue.sourceId ? this.store.getSource(issue.sourceId) : null;
508
- const node = issue.nodeId ? this.store.getNode(issue.nodeId) : null;
518
+ const linkedSource = issue.sourceId ? this.store.getSource(issue.sourceId) : null;
519
+ const linkedNode = issue.nodeId ? this.store.getNode(issue.nodeId) : null;
520
+ const source = linkedSource && isInKnowledgeSpaceScope(linkedSource, scope) ? linkedSource : null;
521
+ const node = linkedNode && isInKnowledgeSpaceScope(linkedNode, scope) ? linkedNode : null;
509
522
  const content = joinSections(`# ${target.title}`, [
510
523
  '## Metadata',
511
524
  `- id: \`${issue.id}\``,
@@ -536,15 +549,15 @@ export class KnowledgeProjectionService {
536
549
  },
537
550
  };
538
551
  }
539
- renderDashboardPage(target, limit) {
552
+ renderDashboardPage(target, limit, scope) {
540
553
  if (target.itemId === 'backlinks') {
541
- return this.renderBacklinksPage(limit);
554
+ return this.renderBacklinksPage(limit, scope);
542
555
  }
543
- return this.renderHealthDashboardPage(limit);
556
+ return this.renderHealthDashboardPage(limit, scope);
544
557
  }
545
- renderRollupPage(nodeId, target) {
558
+ renderRollupPage(nodeId, target, scope) {
546
559
  const node = this.store.getNode(nodeId);
547
- if (!node)
560
+ if (!node || !isInKnowledgeSpaceScope(node, scope))
548
561
  throw new Error(`Unknown rollup node: ${nodeId}`);
549
562
  const edges = this.store.edgesFor('node', node.id);
550
563
  const sources = edges
@@ -555,7 +568,7 @@ export class KnowledgeProjectionService {
555
568
  return this.store.getSource(edge.toId);
556
569
  return null;
557
570
  })
558
- .filter((source) => Boolean(source));
571
+ .filter((source) => Boolean(source) && isInKnowledgeSpaceScope(source, scope));
559
572
  const linkedNodes = edges
560
573
  .map((edge) => {
561
574
  if (edge.fromKind === 'node' && edge.fromId !== node.id)
@@ -564,7 +577,7 @@ export class KnowledgeProjectionService {
564
577
  return this.store.getNode(edge.toId);
565
578
  return null;
566
579
  })
567
- .filter((entry) => Boolean(entry));
580
+ .filter((entry) => Boolean(entry) && isInKnowledgeSpaceScope(entry, scope));
568
581
  const content = joinSections(`# ${target.title}`, node.summary, [
569
582
  '## Included Sources',
570
583
  buildBulletList(sortByTitle(dedupe(sources, (source) => source.id)).map((source) => this.linkToTarget(this.createSourceTarget(source)))),
@@ -584,42 +597,46 @@ export class KnowledgeProjectionService {
584
597
  },
585
598
  };
586
599
  }
587
- renderBundleTarget(target, limit) {
588
- const overview = this.renderOverviewPage(this.createPresetTarget('overview'), limit);
589
- const sourceIndex = this.renderSourceIndexPage(Math.max(limit * 2, 24));
590
- const nodeIndex = this.renderNodeIndexPage(Math.max(limit * 2, 24));
591
- const issueDashboard = this.renderIssueDashboardPage(Math.max(limit * 2, 24));
592
- const backlinks = this.renderBacklinksPage(Math.max(limit * 2, 16));
593
- const health = this.renderHealthDashboardPage(Math.max(limit * 2, 16));
600
+ renderBundleTarget(target, limit, scope) {
601
+ const overview = this.renderOverviewPage(this.createPresetTarget('overview', scope), limit, scope);
602
+ const sourceIndex = this.renderSourceIndexPage(Math.max(limit * 2, 24), scope);
603
+ const nodeIndex = this.renderNodeIndexPage(Math.max(limit * 2, 24), scope);
604
+ const issueDashboard = this.renderIssueDashboardPage(Math.max(limit * 2, 24), scope);
605
+ const backlinks = this.renderBacklinksPage(Math.max(limit * 2, 16), scope);
606
+ const health = this.renderHealthDashboardPage(Math.max(limit * 2, 16), scope);
594
607
  const pages = [overview, sourceIndex, nodeIndex, issueDashboard, backlinks, health];
595
608
  const perKind = Math.max(1, Math.ceil(limit / 3));
596
- for (const node of this.store.listNodes(Number.MAX_SAFE_INTEGER).filter((entry) => entry.kind === 'domain' || entry.kind === 'topic').slice(0, 4)) {
597
- pages.push(this.renderRollupPage(node.id, this.createRollupTarget(node)));
609
+ for (const node of this.scopedNodes(scope).filter((entry) => entry.kind === 'domain' || entry.kind === 'topic').slice(0, 4)) {
610
+ pages.push(this.renderRollupPage(node.id, this.createRollupTarget(node), scope));
598
611
  }
599
- for (const source of this.store.listSources(perKind)) {
600
- pages.push(this.renderSourcePage(source.id));
612
+ for (const source of this.scopedSources(scope, perKind)) {
613
+ pages.push(this.renderSourcePage(source.id, scope));
601
614
  }
602
- for (const node of this.store.listNodes(perKind)) {
603
- pages.push(this.renderNodePage(node.id));
615
+ for (const node of this.scopedNodes(scope, perKind)) {
616
+ pages.push(this.renderNodePage(node.id, scope));
604
617
  }
605
- for (const issue of this.store.listIssues(perKind)) {
606
- pages.push(this.renderIssuePage(issue.id));
618
+ for (const issue of this.scopedIssues(scope, perKind)) {
619
+ pages.push(this.renderIssuePage(issue.id, scope));
607
620
  }
608
621
  return this.bundleFromPages(target, pages, {
609
622
  preset: 'bundle',
610
- sourceCount: this.store.status().sourceCount,
611
- nodeCount: this.store.status().nodeCount,
612
- issueCount: this.store.status().issueCount,
613
- });
623
+ sourceCount: this.scopedSources(scope).length,
624
+ nodeCount: this.scopedNodes(scope).length,
625
+ issueCount: this.scopedIssues(scope).length,
626
+ }, scope);
614
627
  }
615
- bundleFromPages(target, pages, metadata) {
628
+ bundleFromPages(target, pages, metadata, scope) {
629
+ const spaceId = resolveKnowledgeSpaceScope(scope);
616
630
  return {
617
631
  id: `projection-${slugify(target.targetId)}`,
618
632
  target,
619
633
  generatedAt: Date.now(),
620
634
  pageCount: pages.length,
621
635
  pages,
622
- metadata,
636
+ metadata: {
637
+ ...metadata,
638
+ ...(spaceId === null ? { includeAllSpaces: true } : { knowledgeSpaceId: spaceId }),
639
+ },
623
640
  };
624
641
  }
625
642
  linkToTarget(target, label) {
@@ -650,4 +667,49 @@ export class KnowledgeProjectionService {
650
667
  const source = this.store.getSource(id);
651
668
  return source ? isGeneratedKnowledgeSource(source) : false;
652
669
  }
670
+ edgeInScope(edge, scope) {
671
+ return this.recordReferenceInScope(edge.fromKind, edge.fromId, scope)
672
+ && this.recordReferenceInScope(edge.toKind, edge.toId, scope);
673
+ }
674
+ recordReferenceInScope(kind, id, scope) {
675
+ if (kind === 'source') {
676
+ const source = this.store.getSource(id);
677
+ return Boolean(source && isInKnowledgeSpaceScope(source, scope));
678
+ }
679
+ if (kind === 'node') {
680
+ const node = this.store.getNode(id);
681
+ return Boolean(node && isInKnowledgeSpaceScope(node, scope));
682
+ }
683
+ if (kind === 'issue') {
684
+ const issue = this.store.getIssue(id);
685
+ return Boolean(issue && isInKnowledgeSpaceScope(issue, scope));
686
+ }
687
+ return true;
688
+ }
689
+ scopedSources(scope, limit = Number.MAX_SAFE_INTEGER) {
690
+ return this.store.listSources(Number.MAX_SAFE_INTEGER)
691
+ .filter((source) => isInKnowledgeSpaceScope(source, scope))
692
+ .slice(0, Math.max(1, limit));
693
+ }
694
+ scopedNodes(scope, limit = Number.MAX_SAFE_INTEGER) {
695
+ return this.store.listNodes(Number.MAX_SAFE_INTEGER)
696
+ .filter((node) => isInKnowledgeSpaceScope(node, scope))
697
+ .slice(0, Math.max(1, limit));
698
+ }
699
+ scopedIssues(scope, limit = Number.MAX_SAFE_INTEGER) {
700
+ return this.store.listIssues(Number.MAX_SAFE_INTEGER)
701
+ .filter((issue) => isInKnowledgeSpaceScope(issue, scope))
702
+ .slice(0, Math.max(1, limit));
703
+ }
704
+ scopedExtractions(scope, limit = Number.MAX_SAFE_INTEGER) {
705
+ return this.store.listExtractions(Number.MAX_SAFE_INTEGER)
706
+ .filter((extraction) => isInKnowledgeSpaceScope(extraction, scope))
707
+ .slice(0, Math.max(1, limit));
708
+ }
709
+ }
710
+ function projectionScope(input = {}) {
711
+ return {
712
+ ...(input.knowledgeSpaceId ? { knowledgeSpaceId: input.knowledgeSpaceId } : {}),
713
+ ...(input.includeAllSpaces === true ? { includeAllSpaces: true } : {}),
714
+ };
653
715
  }
@@ -9,6 +9,7 @@ import { KnowledgeStore } from './store.js';
9
9
  import type { BrowserKnowledgeIngestOptions, BrowserKnowledgeProfile } from './browser-history/index.js';
10
10
  import type { KnowledgeBatchIngestResult, KnowledgeBookmarkSeed, KnowledgeConnector, KnowledgeConnectorDoctorReport, KnowledgeConsolidationCandidateRecord, KnowledgeConsolidationReportRecord, KnowledgeEdgeRecord, KnowledgeExtractionRecord, KnowledgeIssueRecord, KnowledgeJobMode, KnowledgeJobRecord, KnowledgeJobRunRecord, KnowledgeMaterializedProjection, KnowledgeItemView, KnowledgeMapResult, KnowledgeNodeRecord, KnowledgePacket, KnowledgePacketDetail, KnowledgeProjectionBundle, KnowledgeProjectionTarget, KnowledgeProjectionTargetKind, KnowledgeRefinementTaskRecord, KnowledgeRefinementTaskState, KnowledgeScheduleRecord, KnowledgeSearchResult, KnowledgeSourceRecord, KnowledgeSourceType, KnowledgeStatus, KnowledgeUsageRecord } from './types.js';
11
11
  import { type KnowledgeIssueReviewInput, type KnowledgeIssueReviewResult } from './review.js';
12
+ import { type KnowledgeSpaceScopeInput } from './spaces.js';
12
13
  export interface KnowledgeServiceConfig {
13
14
  readonly configManager?: {
14
15
  getControlPlaneConfigDir?: (() => string) | undefined;
@@ -34,7 +35,7 @@ export declare class KnowledgeService {
34
35
  private getPacketContext;
35
36
  private getConsolidationContext;
36
37
  attachRuntimeBus(runtimeBus: RuntimeEventBus | null | undefined): void;
37
- getStatus(): Promise<KnowledgeServiceStatus>;
38
+ getStatus(scope?: KnowledgeSpaceScopeInput): Promise<KnowledgeServiceStatus>;
38
39
  listUsageRecords(limit?: number, input?: {
39
40
  readonly targetKind?: KnowledgeUsageRecord['targetKind'] | undefined;
40
41
  readonly targetId?: string | undefined;
@@ -54,6 +55,8 @@ export declare class KnowledgeService {
54
55
  querySources(input?: {
55
56
  readonly limit?: number | undefined;
56
57
  readonly offset?: number | undefined;
58
+ readonly knowledgeSpaceId?: string | undefined;
59
+ readonly includeAllSpaces?: boolean | undefined;
57
60
  readonly status?: string | undefined;
58
61
  readonly connectorId?: string | undefined;
59
62
  readonly sourceType?: string | undefined;
@@ -67,6 +70,8 @@ export declare class KnowledgeService {
67
70
  queryNodes(input?: {
68
71
  readonly limit?: number | undefined;
69
72
  readonly offset?: number | undefined;
73
+ readonly knowledgeSpaceId?: string | undefined;
74
+ readonly includeAllSpaces?: boolean | undefined;
70
75
  readonly kind?: string | undefined;
71
76
  readonly status?: string | undefined;
72
77
  readonly query?: string | undefined;
@@ -78,6 +83,8 @@ export declare class KnowledgeService {
78
83
  queryIssues(input?: {
79
84
  readonly limit?: number | undefined;
80
85
  readonly offset?: number | undefined;
86
+ readonly knowledgeSpaceId?: string | undefined;
87
+ readonly includeAllSpaces?: boolean | undefined;
81
88
  readonly severity?: string | undefined;
82
89
  readonly status?: string | undefined;
83
90
  readonly code?: string | undefined;
@@ -87,7 +94,7 @@ export declare class KnowledgeService {
87
94
  items: KnowledgeIssueRecord[];
88
95
  };
89
96
  reviewIssue(input: KnowledgeIssueReviewInput): Promise<KnowledgeIssueReviewResult>;
90
- listExtractions(limit?: number, sourceId?: string): KnowledgeExtractionRecord[];
97
+ listExtractions(limit?: number, sourceId?: string, scope?: KnowledgeSpaceScopeInput): KnowledgeExtractionRecord[];
91
98
  getExtraction(id: string): KnowledgeExtractionRecord | null;
92
99
  getSourceExtraction(sourceId: string): KnowledgeExtractionRecord | null;
93
100
  listConnectors(): readonly KnowledgeConnector[];
@@ -97,7 +104,10 @@ export declare class KnowledgeService {
97
104
  replace?: boolean;
98
105
  }): void;
99
106
  getItem(id: string): KnowledgeItemView | null;
107
+ getItemScoped(id: string, scope?: KnowledgeSpaceScopeInput): KnowledgeItemView | null;
100
108
  getItems(ids: readonly string[]): KnowledgeItemView[];
109
+ private edgeInKnowledgeSpaceScope;
110
+ private recordReferenceInKnowledgeSpaceScope;
101
111
  recordUsage(input: {
102
112
  readonly targetKind: KnowledgeUsageRecord['targetKind'];
103
113
  readonly targetId: string;
@@ -172,17 +182,21 @@ export declare class KnowledgeService {
172
182
  syncBrowserHistory(input?: BrowserKnowledgeIngestOptions): Promise<KnowledgeBatchIngestResult & {
173
183
  readonly profiles: readonly BrowserKnowledgeProfile[];
174
184
  }>;
175
- listProjectionTargets(limit?: number): Promise<KnowledgeProjectionTarget[]>;
185
+ listProjectionTargets(limit?: number, scope?: KnowledgeSpaceScopeInput): Promise<KnowledgeProjectionTarget[]>;
176
186
  renderProjection(input: {
177
187
  readonly kind: KnowledgeProjectionTargetKind;
178
188
  readonly id?: string | undefined;
179
189
  readonly limit?: number | undefined;
190
+ readonly knowledgeSpaceId?: string | undefined;
191
+ readonly includeAllSpaces?: boolean | undefined;
180
192
  }): Promise<KnowledgeProjectionBundle>;
181
193
  materializeProjection(input: {
182
194
  readonly kind: KnowledgeProjectionTargetKind;
183
195
  readonly id?: string | undefined;
184
196
  readonly limit?: number | undefined;
185
197
  readonly filename?: string | undefined;
198
+ readonly knowledgeSpaceId?: string | undefined;
199
+ readonly includeAllSpaces?: boolean | undefined;
186
200
  }): Promise<KnowledgeMaterializedProjection>;
187
201
  map(input?: KnowledgeMapRenderOptions): Promise<KnowledgeMapResult>;
188
202
  reindex(): Promise<{
@@ -190,6 +204,12 @@ export declare class KnowledgeService {
190
204
  issues: readonly KnowledgeIssueRecord[];
191
205
  }>;
192
206
  search(query: string, limit?: number): KnowledgeSearchResult[];
207
+ searchScoped(input: {
208
+ readonly query: string;
209
+ readonly limit?: number | undefined;
210
+ readonly knowledgeSpaceId?: string | undefined;
211
+ readonly includeAllSpaces?: boolean | undefined;
212
+ }): KnowledgeSearchResult[];
193
213
  ask(input: {
194
214
  readonly query: string;
195
215
  readonly limit?: number | undefined;
@@ -202,19 +222,19 @@ export declare class KnowledgeService {
202
222
  buildPacket(task: string, writeScope?: readonly string[], limit?: number, options?: {
203
223
  readonly detail?: KnowledgePacketDetail;
204
224
  readonly budgetLimit?: number;
205
- }): Promise<KnowledgePacket>;
225
+ } & KnowledgeSpaceScopeInput): Promise<KnowledgePacket>;
206
226
  buildPacketSync(task: string, writeScope?: readonly string[], limit?: number, options?: {
207
227
  readonly detail?: KnowledgePacketDetail;
208
228
  readonly budgetLimit?: number;
209
- }): KnowledgePacket | null;
229
+ } & KnowledgeSpaceScopeInput): KnowledgePacket | null;
210
230
  buildPromptPacketSync(task: string, writeScope?: readonly string[], limit?: number, options?: {
211
231
  readonly detail?: KnowledgePacketDetail;
212
232
  readonly budgetLimit?: number;
213
- }): string | null;
233
+ } & KnowledgeSpaceScopeInput): string | null;
214
234
  buildPromptPacket(task: string, writeScope?: readonly string[], limit?: number, options?: {
215
235
  readonly detail?: KnowledgePacketDetail;
216
236
  readonly budgetLimit?: number;
217
- }): Promise<string | null>;
237
+ } & KnowledgeSpaceScopeInput): Promise<string | null>;
218
238
  listJobs(): readonly KnowledgeJobRecord[];
219
239
  getJob(id: string): KnowledgeJobRecord | null;
220
240
  saveSchedule(input: {