@fortemi/core 2026.6.9 → 2026.7.0

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/dist/index.js CHANGED
@@ -2083,7 +2083,9 @@ var ManageNoteInputSchema = z.object({
2083
2083
  });
2084
2084
  var SearchInputSchema = z.object({
2085
2085
  query: z.string(),
2086
- mode: z.enum(["text", "semantic", "hybrid"]).default("text"),
2086
+ mode: z.enum(["text", "semantic", "hybrid", "auto"]).default("text"),
2087
+ query_embedding: z.array(z.number()).optional(),
2088
+ embeddingSetId: z.string().optional(),
2087
2089
  limit: z.number().int().min(1).max(100).default(20),
2088
2090
  offset: z.number().int().min(0).default(0),
2089
2091
  tags: z.array(z.string()).optional(),
@@ -4512,15 +4514,17 @@ async function captureKnowledge(db, rawInput, events) {
4512
4514
  // src/tools/search.ts
4513
4515
  async function searchTool(db, rawInput) {
4514
4516
  const input = SearchInputSchema.parse(rawInput);
4515
- if (input.mode !== "text") {
4517
+ const semanticAvailable = !!input.query_embedding?.length;
4518
+ if ((input.mode === "semantic" || input.mode === "hybrid") && !semanticAvailable) {
4516
4519
  throw new Error(
4517
- `Search mode '${input.mode}' is not available. Only 'text' mode is currently supported. semantic_available: false`
4520
+ `Search mode '${input.mode}' requires query_embedding. semantic_available: false`
4518
4521
  );
4519
4522
  }
4520
- const repo = new SearchRepository(db);
4523
+ const repo = new SearchRepository(db, semanticAvailable);
4521
4524
  return repo.search(input.query, {
4522
4525
  limit: input.limit,
4523
4526
  offset: input.offset,
4527
+ mode: input.mode,
4524
4528
  tags: input.tags,
4525
4529
  collection_id: input.collection_id,
4526
4530
  date_from: input.date_from,
@@ -4530,8 +4534,9 @@ async function searchTool(db, rawInput) {
4530
4534
  format: input.format,
4531
4535
  source: input.source,
4532
4536
  visibility: input.visibility,
4533
- include_facets: input.include_facets
4534
- });
4537
+ include_facets: input.include_facets,
4538
+ embeddingSetId: input.embeddingSetId
4539
+ }, input.query_embedding);
4535
4540
  }
4536
4541
  function zodToJsonSchema(schema) {
4537
4542
  if (schema instanceof z.ZodObject) {
@@ -8098,19 +8103,14 @@ var REQUIRED_RECORD_FIELDS = [
8098
8103
  "privacy",
8099
8104
  "updated_at"
8100
8105
  ];
8101
- var VALID_TYPES = /* @__PURE__ */ new Set([
8102
- "crm.contact",
8103
- "crm.organization",
8104
- "crm.event",
8105
- "crm.interaction",
8106
- "aiwg.artifact",
8107
- "docs.page"
8108
- ]);
8109
8106
  var DEFAULT_QUERY_WEIGHTS = {
8110
8107
  title: 4,
8111
8108
  tag: 3,
8112
8109
  concept: 2,
8113
- text: 1
8110
+ text: 1,
8111
+ facet: 2,
8112
+ id: 1,
8113
+ source: 0.25
8114
8114
  };
8115
8115
  function hasString(value) {
8116
8116
  return typeof value === "string" && value.length > 0;
@@ -8211,7 +8211,7 @@ function validateAiwgFortemiIndexExport(value) {
8211
8211
  errors.push("items must be sorted by id: " + previousId + " before " + item.id);
8212
8212
  }
8213
8213
  if (hasString(item.id)) previousId = item.id;
8214
- if (!VALID_TYPES.has(item.type)) errors.push("items[" + index + "].type is invalid");
8214
+ if (!hasString(item.type)) errors.push("items[" + index + "].type must be a non-empty string");
8215
8215
  else counts[item.type] = (counts[item.type] ?? 0) + 1;
8216
8216
  if (!hasString(item.source?.path)) errors.push("items[" + index + "].source.path is required");
8217
8217
  if (!hasString(item.source?.repo_relative_path)) errors.push("items[" + index + "].source.repo_relative_path is required");
@@ -8306,7 +8306,7 @@ function validateProjectedRecords(items) {
8306
8306
  errors.push("items must be sorted by id: " + previousId + " before " + item.id);
8307
8307
  }
8308
8308
  if (hasString(item.id)) previousId = item.id;
8309
- if (!item.type || !VALID_TYPES.has(item.type)) errors.push("items[" + index + "].type is invalid");
8309
+ if (!hasString(item.type)) errors.push("items[" + index + "].type must be a non-empty string");
8310
8310
  if (!hasString(item.title)) errors.push("items[" + index + "].title is required");
8311
8311
  if (typeof item.text !== "string") errors.push("items[" + index + "].text is required");
8312
8312
  if (!item.facets || typeof item.facets !== "object" || Array.isArray(item.facets)) {
@@ -8471,8 +8471,99 @@ function queryMatches(item, q) {
8471
8471
  }
8472
8472
  return matches;
8473
8473
  }
8474
+ var DISCOVERY_STOPWORDS = /* @__PURE__ */ new Set([
8475
+ "a",
8476
+ "an",
8477
+ "and",
8478
+ "are",
8479
+ "as",
8480
+ "for",
8481
+ "from",
8482
+ "how",
8483
+ "i",
8484
+ "in",
8485
+ "is",
8486
+ "me",
8487
+ "of",
8488
+ "on",
8489
+ "or",
8490
+ "please",
8491
+ "the",
8492
+ "to",
8493
+ "use",
8494
+ "with"
8495
+ ]);
8496
+ function normalizeDiscoveryText(value) {
8497
+ return value.toLowerCase().replace(/[_/]+/g, " ").replace(/[^a-z0-9.-]+/g, " ").trim();
8498
+ }
8499
+ function canonicalDiscoveryName(value) {
8500
+ return normalizeDiscoveryText(value).replace(/[\s.-]+/g, "");
8501
+ }
8502
+ function discoveryTokens(value) {
8503
+ return normalizeDiscoveryText(value).split(/\s+/).filter((token) => token.length > 1 && !DISCOVERY_STOPWORDS.has(token));
8504
+ }
8505
+ function facetValues(item, names) {
8506
+ return names.flatMap((name) => item.facets[name] ?? []);
8507
+ }
8508
+ function addDiscoveryMatch(matches, match) {
8509
+ if (!matches.some((existing) => existing.field === match.field && existing.value === match.value && existing.reason === match.reason)) {
8510
+ matches.push(match);
8511
+ }
8512
+ }
8513
+ function tokenOverlapScore(tokens, value) {
8514
+ if (tokens.length === 0 || !value) return 0;
8515
+ const normalized = normalizeDiscoveryText(value);
8516
+ const hits = tokens.filter((token) => normalized.includes(token)).length;
8517
+ return hits / tokens.length;
8518
+ }
8519
+ function discoveryMatches(item, query) {
8520
+ if (!query) return [];
8521
+ const matches = [];
8522
+ const tokens = discoveryTokens(query);
8523
+ const canonicalQuery = canonicalDiscoveryName(query);
8524
+ const idParts = item.id.split(/[:/]/);
8525
+ const names = [
8526
+ item.id,
8527
+ item.title,
8528
+ ...idParts,
8529
+ ...facetValues(item, ["name", "canonical_name", "command", "skill", "agent", "rule"])
8530
+ ].filter(Boolean);
8531
+ const triggers = facetValues(item, ["trigger", "triggers", "trigger_phrase", "trigger_phrases"]);
8532
+ const capabilities = [
8533
+ ...facetValues(item, ["capability", "capabilities", "summary", "description"]),
8534
+ ...item.concepts,
8535
+ ...item.tags
8536
+ ];
8537
+ const sourceValues = [item.source?.path, item.source?.repo_relative_path, item.source?.locator].filter(Boolean);
8538
+ for (const name of names) {
8539
+ const canonicalName = canonicalDiscoveryName(name);
8540
+ if (!canonicalName) continue;
8541
+ if (canonicalName === canonicalQuery) {
8542
+ addDiscoveryMatch(matches, { field: "id", value: name, score: 80, reason: "exact canonical name" });
8543
+ } else if (canonicalName.includes(canonicalQuery) || canonicalQuery.includes(canonicalName)) {
8544
+ addDiscoveryMatch(matches, { field: "id", value: name, score: 48, reason: "near canonical name" });
8545
+ }
8546
+ }
8547
+ const titleOverlap = tokenOverlapScore(tokens, item.title);
8548
+ if (titleOverlap > 0) addDiscoveryMatch(matches, { field: "title", value: item.title, score: 18 * titleOverlap, reason: "title token overlap" });
8549
+ for (const trigger of triggers) {
8550
+ const overlap = tokenOverlapScore(tokens, trigger);
8551
+ if (overlap > 0) addDiscoveryMatch(matches, { field: "facet", value: trigger, score: 34 * overlap, reason: "trigger phrase" });
8552
+ }
8553
+ for (const capability of capabilities) {
8554
+ const overlap = tokenOverlapScore(tokens, capability);
8555
+ if (overlap > 0) addDiscoveryMatch(matches, { field: "concept", value: capability, score: 22 * overlap, reason: "capability overlap" });
8556
+ }
8557
+ const textOverlap = tokenOverlapScore(tokens, item.text);
8558
+ if (textOverlap > 0) addDiscoveryMatch(matches, { field: "text", value: item.text, score: 8 * textOverlap, reason: "body token overlap" });
8559
+ for (const source of sourceValues) {
8560
+ const overlap = tokenOverlapScore(tokens, source);
8561
+ if (overlap > 0) addDiscoveryMatch(matches, { field: "source", value: source, score: 2 * overlap, reason: "path overlap" });
8562
+ }
8563
+ return matches;
8564
+ }
8474
8565
  function rankMatches(matches, weights) {
8475
- return matches.reduce((total, match) => total + weights[match.field], 0);
8566
+ return matches.reduce((total, match) => total + (match.score ?? weights[match.field]), 0);
8476
8567
  }
8477
8568
  function clipSnippet(value, q, maxLength) {
8478
8569
  const normalizedLength = Math.max(20, maxLength);
@@ -8496,7 +8587,12 @@ function createSnippet(item, matches, q, maxLength) {
8496
8587
  }
8497
8588
  function createRankedEntries(items, q, options, ordinalBase = 0) {
8498
8589
  const weights = { ...DEFAULT_QUERY_WEIGHTS, ...options.weights };
8499
- return items.map((item, ordinal) => ({ item, ordinal: ordinalBase + ordinal, matches: queryMatches(item, q) })).filter(({ item, matches }) => {
8590
+ const profile = options.searchProfile ?? "default";
8591
+ return items.map((item, ordinal) => ({
8592
+ item,
8593
+ ordinal: ordinalBase + ordinal,
8594
+ matches: profile === "aiwg-discovery" ? discoveryMatches(item, q) : queryMatches(item, q)
8595
+ })).filter(({ item, matches }) => {
8500
8596
  if (q && matches.length === 0) return false;
8501
8597
  if (options.types && !options.types.includes(item.type)) return false;
8502
8598
  if (options.privacy && !options.privacy.includes(item.privacy.classification)) return false;
@@ -8543,7 +8639,106 @@ function createQueryResultFromRankedEntries(entries, query, options) {
8543
8639
  }
8544
8640
  function queryAiwgFortemiIndex(index, query = "", options = {}) {
8545
8641
  const q = query.trim().toLowerCase();
8546
- return createQueryResultFromRankedEntries(createRankedEntries(index.items, q, options), q, options);
8642
+ const entries = createRankedEntries(index.items, q, options);
8643
+ if (entries.length === 0 && q && options.searchProfile === "aiwg-discovery") {
8644
+ const relaxed = discoveryTokens(q).join(" ");
8645
+ return createQueryResultFromRankedEntries(createRankedEntries(index.items, relaxed, options), relaxed, options);
8646
+ }
8647
+ return createQueryResultFromRankedEntries(entries, q, options);
8648
+ }
8649
+ function cosineSimilarity2(left, right) {
8650
+ if (left.length !== right.length || left.length === 0) return 0;
8651
+ let dot = 0;
8652
+ let leftMag = 0;
8653
+ let rightMag = 0;
8654
+ for (let i = 0; i < left.length; i += 1) {
8655
+ const l = left[i];
8656
+ const r = right[i];
8657
+ dot += l * r;
8658
+ leftMag += l * l;
8659
+ rightMag += r * r;
8660
+ }
8661
+ if (leftMag === 0 || rightMag === 0) return 0;
8662
+ return dot / (Math.sqrt(leftMag) * Math.sqrt(rightMag));
8663
+ }
8664
+ function validateAiwgStaticEmbeddingSet(value) {
8665
+ const errors = [];
8666
+ const data = value;
8667
+ if (data?.schema_version !== "aiwg.fortemi.embedding.set.v1") errors.push("schema_version must be aiwg.fortemi.embedding.set.v1");
8668
+ if (!hasString(data?.id)) errors.push("id is required");
8669
+ if (!hasString(data?.model)) errors.push("model is required");
8670
+ if (!hasPositiveInteger(data?.dimensions)) errors.push("dimensions must be a positive integer");
8671
+ if (!hasString(data?.generated_at)) errors.push("generated_at is required");
8672
+ if (!hasString(data?.granularity)) errors.push("granularity is required");
8673
+ if (!Array.isArray(data?.embeddings)) errors.push("embeddings must be an array");
8674
+ for (const [index, embedding] of (data.embeddings ?? []).entries()) {
8675
+ if (!hasString(embedding.record_id)) errors.push("embeddings[" + index + "].record_id is required");
8676
+ if (!hasString(embedding.input_hash)) errors.push("embeddings[" + index + "].input_hash is required");
8677
+ if (!Array.isArray(embedding.embedding)) errors.push("embeddings[" + index + "].embedding must be an array");
8678
+ else if (hasPositiveInteger(data?.dimensions) && embedding.embedding.length !== data.dimensions) {
8679
+ errors.push("embeddings[" + index + "].embedding length must match dimensions");
8680
+ } else if (!embedding.embedding.every((number) => typeof number === "number" && Number.isFinite(number))) {
8681
+ errors.push("embeddings[" + index + "].embedding must contain finite numbers");
8682
+ }
8683
+ }
8684
+ return { valid: errors.length === 0, errors };
8685
+ }
8686
+ function assertAiwgStaticEmbeddingSet(value) {
8687
+ const result = validateAiwgStaticEmbeddingSet(value);
8688
+ if (!result.valid) throw new Error("Invalid AIWG Fortemi embedding set:\n" + result.errors.join("\n"));
8689
+ return value;
8690
+ }
8691
+ function queryAiwgSemanticIndex(index, embeddingSet, queryEmbedding, options = {}) {
8692
+ assertAiwgStaticEmbeddingSet(embeddingSet);
8693
+ if (queryEmbedding.length !== embeddingSet.dimensions) throw new Error("query embedding length must match embedding set dimensions");
8694
+ const byId = new Map(index.items.map((item) => [item.id, item]));
8695
+ const offset = options.offset ?? 0;
8696
+ const limit = options.limit ?? 20;
8697
+ return embeddingSet.embeddings.map((embedding) => {
8698
+ const item = byId.get(embedding.record_id);
8699
+ if (!item) return null;
8700
+ return { item, embedding, score: cosineSimilarity2(queryEmbedding, embedding.embedding) };
8701
+ }).filter((result) => result !== null && result.score >= (options.minScore ?? -1)).sort((left, right) => right.score - left.score || left.item.id.localeCompare(right.item.id)).slice(offset, offset + limit);
8702
+ }
8703
+ function queryAiwgHybridIndex(index, embeddingSet, query, queryEmbedding, options = {}) {
8704
+ const lexical = queryAiwgFortemiIndex(index, query, { ...options, rank: true });
8705
+ const semantic = queryAiwgSemanticIndex(index, embeddingSet, queryEmbedding, { limit: index.items.length });
8706
+ const lexicalWeight = options.lexicalWeight ?? 0.5;
8707
+ const semanticWeight = options.semanticWeight ?? 0.5;
8708
+ const lexicalScores = new Map(lexical.rankedItems?.map((entry) => [entry.item.id, entry.rank]) ?? []);
8709
+ const maxLexical = Math.max(1, ...lexicalScores.values());
8710
+ const embeddingById = new Map(semantic.flatMap((entry) => entry.embedding ? [[entry.item.id, entry.embedding]] : []));
8711
+ const semanticScores = new Map(semantic.map((entry) => [entry.item.id, entry.score]));
8712
+ const ids = /* @__PURE__ */ new Set([...lexicalScores.keys(), ...semanticScores.keys()]);
8713
+ const offset = options.offset ?? 0;
8714
+ const limit = options.limit ?? 20;
8715
+ return [...ids].map((id) => {
8716
+ const item = index.items.find((candidate) => candidate.id === id);
8717
+ const embedding = embeddingById.get(id);
8718
+ if (!item) return null;
8719
+ return {
8720
+ item,
8721
+ ...embedding ? { embedding } : {},
8722
+ score: (lexicalScores.get(id) ?? 0) / maxLexical * lexicalWeight + (semanticScores.get(id) ?? 0) * semanticWeight
8723
+ };
8724
+ }).filter((result) => result !== null && result.score >= (options.minScore ?? -1)).sort((left, right) => right.score - left.score || left.item.id.localeCompare(right.item.id)).slice(offset, offset + limit);
8725
+ }
8726
+ function findAiwgStaticDuplicatePairs(index, embeddingSet, threshold = 0.9) {
8727
+ assertAiwgStaticEmbeddingSet(embeddingSet);
8728
+ const byId = new Map(index.items.map((item) => [item.id, item]));
8729
+ const pairs = [];
8730
+ for (let leftIndex = 0; leftIndex < embeddingSet.embeddings.length; leftIndex += 1) {
8731
+ for (let rightIndex = leftIndex + 1; rightIndex < embeddingSet.embeddings.length; rightIndex += 1) {
8732
+ const leftEmbedding = embeddingSet.embeddings[leftIndex];
8733
+ const rightEmbedding = embeddingSet.embeddings[rightIndex];
8734
+ const left = byId.get(leftEmbedding.record_id);
8735
+ const right = byId.get(rightEmbedding.record_id);
8736
+ if (!left || !right) continue;
8737
+ const score = cosineSimilarity2(leftEmbedding.embedding, rightEmbedding.embedding);
8738
+ if (score >= threshold) pairs.push({ left, right, score });
8739
+ }
8740
+ }
8741
+ return pairs.sort((left, right) => right.score - left.score || left.left.id.localeCompare(right.left.id));
8547
8742
  }
8548
8743
  function chunkPartCacheKey(part) {
8549
8744
  return `${part.offset}:${part.href}`;
@@ -8642,6 +8837,104 @@ async function getChunkRecord(runtime, id) {
8642
8837
  }
8643
8838
  return record;
8644
8839
  }
8840
+ function relationshipTypeFilter(options) {
8841
+ return options?.relationshipType ?? options?.type;
8842
+ }
8843
+ function edgeFromRelationship(sourceId, relationship) {
8844
+ return {
8845
+ source_id: sourceId,
8846
+ target_id: relationship.target_id,
8847
+ type: relationship.type,
8848
+ ...relationship.source_path ? { source_path: relationship.source_path } : {}
8849
+ };
8850
+ }
8851
+ function relationshipMatches(edge, options = {}) {
8852
+ const type = relationshipTypeFilter(options);
8853
+ const direction = options.direction ?? "both";
8854
+ if (type && edge.type !== type) return false;
8855
+ if (options.sourceId && edge.source_id !== options.sourceId) return false;
8856
+ if (options.targetId && edge.target_id !== options.targetId) return false;
8857
+ if (direction === "out" && options.targetId && edge.target_id !== options.targetId) return false;
8858
+ if (direction === "in" && options.sourceId && edge.source_id !== options.sourceId) return false;
8859
+ return true;
8860
+ }
8861
+ function nodeSummary(item) {
8862
+ return { id: item.id, type: item.type, title: item.title };
8863
+ }
8864
+ function addNode(nodes, item) {
8865
+ if (item) nodes.set(item.id, nodeSummary(item));
8866
+ }
8867
+ function relationshipResultFromRecords(records, options = {}) {
8868
+ const byId = new Map(records.map((record) => [record.id, record]));
8869
+ const edges = [];
8870
+ for (const record of records) {
8871
+ for (const relationship of record.relationships ?? []) {
8872
+ const edge = edgeFromRelationship(record.id, relationship);
8873
+ if (!relationshipMatches(edge, options)) continue;
8874
+ edges.push(edge);
8875
+ }
8876
+ }
8877
+ const limitedEdges = (options.limit ? edges.slice(0, options.limit) : edges).sort((left, right) => left.source_id.localeCompare(right.source_id) || left.target_id.localeCompare(right.target_id) || left.type.localeCompare(right.type));
8878
+ const nodes = /* @__PURE__ */ new Map();
8879
+ for (const edge of limitedEdges) {
8880
+ addNode(nodes, byId.get(edge.source_id));
8881
+ addNode(nodes, byId.get(edge.target_id));
8882
+ }
8883
+ return {
8884
+ nodes: [...nodes.values()].sort((left, right) => left.id.localeCompare(right.id)),
8885
+ edges: limitedEdges,
8886
+ complete: true
8887
+ };
8888
+ }
8889
+ function neighborQueryOptions(id, options = {}) {
8890
+ const direction = options.direction ?? "both";
8891
+ return {
8892
+ ...options,
8893
+ ...direction === "out" ? { sourceId: id } : {},
8894
+ ...direction === "in" ? { targetId: id } : {}
8895
+ };
8896
+ }
8897
+ function filterNeighborResult(id, result, options = {}) {
8898
+ const direction = options.direction ?? "both";
8899
+ const edges = result.edges.filter((edge) => {
8900
+ if (direction === "out") return edge.source_id === id;
8901
+ if (direction === "in") return edge.target_id === id;
8902
+ return edge.source_id === id || edge.target_id === id;
8903
+ });
8904
+ const ids = /* @__PURE__ */ new Set();
8905
+ for (const edge of edges) {
8906
+ ids.add(edge.source_id);
8907
+ ids.add(edge.target_id);
8908
+ }
8909
+ return {
8910
+ ...result,
8911
+ edges,
8912
+ nodes: result.nodes.filter((node) => ids.has(node.id))
8913
+ };
8914
+ }
8915
+ async function recordsFromChunkedRuntime(runtime, onProgress) {
8916
+ let scannedParts = 0;
8917
+ let fetchedParts = 0;
8918
+ const records = [];
8919
+ for (const partRef of runtime.manifest.parts) {
8920
+ const loaded = await loadChunkPart(runtime, partRef);
8921
+ if (loaded.fetched) fetchedParts += 1;
8922
+ scannedParts += 1;
8923
+ onProgress?.({ phase: "part", done: scannedParts, total: runtime.manifest.parts.length, href: partRef.href });
8924
+ for (const item of loaded.part.items) {
8925
+ records.push(item.relationships ? item : await getChunkRecord(runtime, item.id));
8926
+ }
8927
+ }
8928
+ return { records, scannedParts, fetchedParts };
8929
+ }
8930
+ async function relationshipResultFromChunkedRuntime(runtime, options = {}) {
8931
+ const loaded = await recordsFromChunkedRuntime(runtime);
8932
+ return {
8933
+ ...relationshipResultFromRecords(loaded.records, options),
8934
+ scannedParts: loaded.scannedParts,
8935
+ fetchedParts: loaded.fetchedParts
8936
+ };
8937
+ }
8645
8938
  async function queryChunkedAiwgFortemiIndex(runtime, query = "", options = {}) {
8646
8939
  const q = query.trim().toLowerCase();
8647
8940
  let scannedParts = 0;
@@ -8822,6 +9115,39 @@ function createAiwgIndexController(initialIndex) {
8822
9115
  if (!found) throw new Error("Record not found: " + id);
8823
9116
  return found;
8824
9117
  },
9118
+ async neighbors(id, options) {
9119
+ try {
9120
+ const queryOptions = neighborQueryOptions(id, options);
9121
+ const result = chunked ? await relationshipResultFromChunkedRuntime(chunked, queryOptions) : relationshipResultFromRecords(requireIndex().items, queryOptions);
9122
+ return filterNeighborResult(id, result, options);
9123
+ } catch (err) {
9124
+ error = err instanceof Error ? err : new Error(String(err));
9125
+ notify();
9126
+ throw error;
9127
+ }
9128
+ },
9129
+ async relationshipQuery(options) {
9130
+ try {
9131
+ return chunked ? await relationshipResultFromChunkedRuntime(chunked, options) : relationshipResultFromRecords(requireIndex().items, options);
9132
+ } catch (err) {
9133
+ error = err instanceof Error ? err : new Error(String(err));
9134
+ notify();
9135
+ throw error;
9136
+ }
9137
+ },
9138
+ async relationshipSet(options) {
9139
+ const [left, right] = await Promise.all([
9140
+ this.neighbors(options.a, options),
9141
+ this.neighbors(options.b, options)
9142
+ ]);
9143
+ const leftIds = new Set(left.nodes.map((node) => node.id).filter((id) => id !== options.a));
9144
+ const rightIds = new Set(right.nodes.map((node) => node.id).filter((id) => id !== options.b));
9145
+ let ids;
9146
+ if (options.op === "intersection") ids = [...leftIds].filter((id) => rightIds.has(id));
9147
+ else if (options.op === "difference") ids = [...leftIds].filter((id) => !rightIds.has(id));
9148
+ else ids = [.../* @__PURE__ */ new Set([...leftIds, ...rightIds])];
9149
+ return { op: options.op, ids: ids.sort() };
9150
+ },
8825
9151
  clearChunkCache() {
8826
9152
  chunked?.partCache.clear();
8827
9153
  chunked?.detailCache.clear();
@@ -8832,6 +9158,15 @@ function createAiwgIndexController(initialIndex) {
8832
9158
  toCommunityGraph(options) {
8833
9159
  return aiwgFortemiIndexToCommunityGraph(requireIndex(), options);
8834
9160
  },
9161
+ async toCommunityGraphChunked(options) {
9162
+ if (!chunked) return aiwgFortemiIndexToCommunityGraph(requireIndex(), options);
9163
+ const loaded = await recordsFromChunkedRuntime(chunked, options?.onProgress);
9164
+ return aiwgFortemiIndexToCommunityGraph({
9165
+ generated_at: chunked.manifest.generated_at,
9166
+ source: chunked.manifest.source,
9167
+ items: loaded.records
9168
+ }, options);
9169
+ },
8835
9170
  setReviewDecision(input) {
8836
9171
  const decision = {
8837
9172
  ...input,
@@ -8908,8 +9243,8 @@ function communityIdsFor(item, options) {
8908
9243
  }
8909
9244
 
8910
9245
  // src/index.ts
8911
- var VERSION = "2026.6.8";
9246
+ var VERSION = "2026.7.0";
8912
9247
 
8913
- export { AIWG_SCAN_REQUIRED_FIELDS, ArchiveManager, AttachmentsRepository, CURRENT_MIGRATION_HEAD, CURRENT_SHARD_VERSION, CapabilityManager, CaptureKnowledgeInputSchema, CollectionsRepository, CommunitiesRepository, DB_SNAPSHOT_SCHEMA_VERSION, DbSnapshotVersionError, EMBED_REQUEST_KIND, EMBED_RESPONSE_KIND, EmbeddingSetsRepository, FallbackRouter, FortemiToolManifest, GetNoteInputSchema, GraphRepository, JOB_CAPABILITIES, JOB_PRIORITIES, JobQueueWorker, LOCAL_ENDPOINTS, LinksRepository, ListNotesInputSchema, ManageArchiveInputSchema, ManageAttachmentsInputSchema, ManageCapabilitiesInputSchema, ManageCollectionsInputSchema, ManageLinksInputSchema, ManageNoteInputSchema, ManageTagsInputSchema, MemoryBlobStore, MigrationRunner, NotesRepository, OpenAICompatibleProvider, PGliteStorageBackend, PGliteStorageBackendFactory, PGliteWorkerClient, PGliteWorkerStorageBackend, PGliteWorkerStorageBackendFactory, ProvenanceRepository, ProviderRegistry, SHARD_FORMAT, SUPPORTED_PGLITE_VERSION, SearchInputSchema, SearchRepository, SkosRepository, TagsRepository, TransactionProxy, TypedEventBus, VERSION, aiRevisionHandler, aiwgFortemiIndexToCommunityGraph, allMigrations, appendPluginScript, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, buildAiwgChunkedIndex, buildNoteConditions, buildPluginCsp, captureKnowledge, chunkText, classifyError, classifyModel, clearPrefetchedShard, collectionFromShard, collectionToShard, computeHash, computeSri, conceptTaggingHandler, cosineSimilarity, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, createBlobStore, createCosineSemanticProvider, createCspReportHandler, createFortemi, createLegacyProvider, createPGliteBackend, createPGliteInstance, createRemoteBackend, createRoutes, createShardBackend, createWorkerEmbedFunction, defaultStorageBackendFactory, detectCommunities, detectGpuCapabilities, detectInferenceCapabilities, discoverLocalProviders, dumpDbSnapshot, embeddingFromShard, embeddingGenerationHandler, embeddingSetFromShard, embeddingSetMemberToShard, embeddingSetToShard, embeddingToShard, enqueueFullWorkflow, enqueueJob, enqueueNoteCreationJobs, estimateModelFit, estimateVramMB, estimateVramTier, exportShard, fetchPluginScript, fortemiManifest, fromPrefetched, generateId, getAiwgFortemiFacets, getEmbedFunction, getFortemiBridge, getFortemiSecretStore, getJobQueueStatus, getLlmFunction, getNote, getPrefetchedSha256, handleEmbedRequests, hasFortemiSecureSecrets, importShard, isPluginScriptAllowed, isShardPrefetched, linkFromShard, linkToShard, linkingHandler, listNotes, manageArchive, manageAttachments, manageCapabilities, manageCollections, manageLinks, manageNote, manageTags, matchRoute, noteFromShard, noteSkosTagToShard, noteToShard, openShard, packTarGz, parseCspReport, prefetchShard, provenanceEdgeToShard, queryAiwgFortemiIndex, registerLlmCapability, registerSemanticCapability, registerSemanticCapabilityWorker, registerServiceWorker, restoreDbSnapshot, searchTool, selectBackend, selectLlmModel, setEmbedFunction, setLlmFunction, sha256Hex, skosConceptToShard, skosRelationToShard, skosSchemeToShard, suggestTags, tagsFromShard, tagsToShard, titleGenerationHandler, unpackTarGz, unregisterLlmCapability, unregisterSemanticCapability, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport, validateChecksums, verifyDbSnapshotMeta, verifySri };
9248
+ export { AIWG_SCAN_REQUIRED_FIELDS, ArchiveManager, AttachmentsRepository, CURRENT_MIGRATION_HEAD, CURRENT_SHARD_VERSION, CapabilityManager, CaptureKnowledgeInputSchema, CollectionsRepository, CommunitiesRepository, DB_SNAPSHOT_SCHEMA_VERSION, DbSnapshotVersionError, EMBED_REQUEST_KIND, EMBED_RESPONSE_KIND, EmbeddingSetsRepository, FallbackRouter, FortemiToolManifest, GetNoteInputSchema, GraphRepository, JOB_CAPABILITIES, JOB_PRIORITIES, JobQueueWorker, LOCAL_ENDPOINTS, LinksRepository, ListNotesInputSchema, ManageArchiveInputSchema, ManageAttachmentsInputSchema, ManageCapabilitiesInputSchema, ManageCollectionsInputSchema, ManageLinksInputSchema, ManageNoteInputSchema, ManageTagsInputSchema, MemoryBlobStore, MigrationRunner, NotesRepository, OpenAICompatibleProvider, PGliteStorageBackend, PGliteStorageBackendFactory, PGliteWorkerClient, PGliteWorkerStorageBackend, PGliteWorkerStorageBackendFactory, ProvenanceRepository, ProviderRegistry, SHARD_FORMAT, SUPPORTED_PGLITE_VERSION, SearchInputSchema, SearchRepository, SkosRepository, TagsRepository, TransactionProxy, TypedEventBus, VERSION, aiRevisionHandler, aiwgFortemiIndexToCommunityGraph, allMigrations, appendPluginScript, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, assertAiwgStaticEmbeddingSet, buildAiwgChunkedIndex, buildNoteConditions, buildPluginCsp, captureKnowledge, chunkText, classifyError, classifyModel, clearPrefetchedShard, collectionFromShard, collectionToShard, computeHash, computeSri, conceptTaggingHandler, cosineSimilarity, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, createBlobStore, createCosineSemanticProvider, createCspReportHandler, createFortemi, createLegacyProvider, createPGliteBackend, createPGliteInstance, createRemoteBackend, createRoutes, createShardBackend, createWorkerEmbedFunction, defaultStorageBackendFactory, detectCommunities, detectGpuCapabilities, detectInferenceCapabilities, discoverLocalProviders, dumpDbSnapshot, embeddingFromShard, embeddingGenerationHandler, embeddingSetFromShard, embeddingSetMemberToShard, embeddingSetToShard, embeddingToShard, enqueueFullWorkflow, enqueueJob, enqueueNoteCreationJobs, estimateModelFit, estimateVramMB, estimateVramTier, exportShard, fetchPluginScript, findAiwgStaticDuplicatePairs, fortemiManifest, fromPrefetched, generateId, getAiwgFortemiFacets, getEmbedFunction, getFortemiBridge, getFortemiSecretStore, getJobQueueStatus, getLlmFunction, getNote, getPrefetchedSha256, handleEmbedRequests, hasFortemiSecureSecrets, importShard, isPluginScriptAllowed, isShardPrefetched, linkFromShard, linkToShard, linkingHandler, listNotes, manageArchive, manageAttachments, manageCapabilities, manageCollections, manageLinks, manageNote, manageTags, matchRoute, noteFromShard, noteSkosTagToShard, noteToShard, openShard, packTarGz, parseCspReport, prefetchShard, provenanceEdgeToShard, queryAiwgFortemiIndex, queryAiwgHybridIndex, queryAiwgSemanticIndex, registerLlmCapability, registerSemanticCapability, registerSemanticCapabilityWorker, registerServiceWorker, restoreDbSnapshot, searchTool, selectBackend, selectLlmModel, setEmbedFunction, setLlmFunction, sha256Hex, skosConceptToShard, skosRelationToShard, skosSchemeToShard, suggestTags, tagsFromShard, tagsToShard, titleGenerationHandler, unpackTarGz, unregisterLlmCapability, unregisterSemanticCapability, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport, validateAiwgStaticEmbeddingSet, validateChecksums, verifyDbSnapshotMeta, verifySri };
8914
9249
  //# sourceMappingURL=index.js.map
8915
9250
  //# sourceMappingURL=index.js.map