@fortemi/core 2026.7.0 → 2026.7.2
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 +47 -21
- package/dist/aiwg-index.d.ts +85 -5
- package/dist/aiwg-index.js +203 -25
- package/dist/aiwg-index.js.map +1 -1
- package/dist/index.d.ts +50 -31
- package/dist/index.js +330 -55
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -596,6 +596,19 @@ var migration0009 = {
|
|
|
596
596
|
`
|
|
597
597
|
};
|
|
598
598
|
|
|
599
|
+
// src/migrations/0010_attachment_text_metadata.ts
|
|
600
|
+
var migration0010 = {
|
|
601
|
+
version: 10,
|
|
602
|
+
name: "0010_attachment_text_metadata",
|
|
603
|
+
sql: `
|
|
604
|
+
ALTER TABLE attachment
|
|
605
|
+
ADD COLUMN IF NOT EXISTS mime_type TEXT;
|
|
606
|
+
|
|
607
|
+
ALTER TABLE attachment
|
|
608
|
+
ADD COLUMN IF NOT EXISTS extracted_text TEXT;
|
|
609
|
+
`
|
|
610
|
+
};
|
|
611
|
+
|
|
599
612
|
// src/migrations/index.ts
|
|
600
613
|
var allMigrations = [
|
|
601
614
|
migration0001,
|
|
@@ -606,7 +619,8 @@ var allMigrations = [
|
|
|
606
619
|
migration0006,
|
|
607
620
|
migration0007,
|
|
608
621
|
migration0008,
|
|
609
|
-
migration0009
|
|
622
|
+
migration0009,
|
|
623
|
+
migration0010
|
|
610
624
|
];
|
|
611
625
|
|
|
612
626
|
// src/data-archive.ts
|
|
@@ -1119,6 +1133,16 @@ function buildNoteConditions(options, startIdx, includeDeleted = false) {
|
|
|
1119
1133
|
}
|
|
1120
1134
|
|
|
1121
1135
|
// src/repositories/embedding-sets-repository.ts
|
|
1136
|
+
var ATTACHMENT_TEXT_JOIN = `
|
|
1137
|
+
LEFT JOIN (
|
|
1138
|
+
SELECT note_id,
|
|
1139
|
+
string_agg(extracted_text, ' ' ORDER BY position, created_at)
|
|
1140
|
+
FILTER (WHERE extracted_text IS NOT NULL AND extracted_text <> '') as extracted_text
|
|
1141
|
+
FROM attachment
|
|
1142
|
+
WHERE deleted_at IS NULL
|
|
1143
|
+
GROUP BY note_id
|
|
1144
|
+
) ax ON ax.note_id = n.id`;
|
|
1145
|
+
var COMBINED_TEXT_VECTOR_SQL = `to_tsvector('english', (coalesce(c.content, '') || ' ' || coalesce(ax.extracted_text, '')))`;
|
|
1122
1146
|
var DEFAULT_COMPATIBILITY = {
|
|
1123
1147
|
model: "require-same",
|
|
1124
1148
|
dimension: "require-same",
|
|
@@ -1498,7 +1522,7 @@ var EmbeddingSetsRepository = class {
|
|
|
1498
1522
|
params.push(criteria.updatedBefore);
|
|
1499
1523
|
}
|
|
1500
1524
|
if (criteria.query?.trim()) {
|
|
1501
|
-
conditions.push(`(n.tsv @@ plainto_tsquery('english', $${idx}) OR
|
|
1525
|
+
conditions.push(`(n.tsv @@ plainto_tsquery('english', $${idx}) OR ${COMBINED_TEXT_VECTOR_SQL} @@ plainto_tsquery('english', $${idx}))`);
|
|
1502
1526
|
params.push(criteria.query);
|
|
1503
1527
|
}
|
|
1504
1528
|
const result = await this.db.query(
|
|
@@ -1506,6 +1530,7 @@ var EmbeddingSetsRepository = class {
|
|
|
1506
1530
|
FROM embedding e
|
|
1507
1531
|
JOIN note n ON n.id = e.note_id
|
|
1508
1532
|
LEFT JOIN note_revised_current c ON c.note_id = n.id
|
|
1533
|
+
${ATTACHMENT_TEXT_JOIN}
|
|
1509
1534
|
WHERE ${conditions.join(" AND ")}
|
|
1510
1535
|
ORDER BY e.note_id, e.created_at DESC`,
|
|
1511
1536
|
params
|
|
@@ -1623,6 +1648,17 @@ var EmbeddingSetsRepository = class {
|
|
|
1623
1648
|
};
|
|
1624
1649
|
|
|
1625
1650
|
// src/repositories/search-repository.ts
|
|
1651
|
+
var ATTACHMENT_TEXT_JOIN2 = `
|
|
1652
|
+
LEFT JOIN (
|
|
1653
|
+
SELECT note_id,
|
|
1654
|
+
string_agg(extracted_text, ' ' ORDER BY position, created_at)
|
|
1655
|
+
FILTER (WHERE extracted_text IS NOT NULL AND extracted_text <> '') as extracted_text
|
|
1656
|
+
FROM attachment
|
|
1657
|
+
WHERE deleted_at IS NULL
|
|
1658
|
+
GROUP BY note_id
|
|
1659
|
+
) ax ON ax.note_id = n.id`;
|
|
1660
|
+
var COMBINED_TEXT_SQL = `(coalesce(c.content, '') || ' ' || coalesce(ax.extracted_text, ''))`;
|
|
1661
|
+
var COMBINED_TEXT_VECTOR_SQL2 = `to_tsvector('english', ${COMBINED_TEXT_SQL})`;
|
|
1626
1662
|
var SearchRepository = class {
|
|
1627
1663
|
constructor(db, semanticAvailable = false) {
|
|
1628
1664
|
this.db = db;
|
|
@@ -1707,7 +1743,7 @@ var SearchRepository = class {
|
|
|
1707
1743
|
const { conditions, params, nextIdx } = buildNoteConditions(options, 2);
|
|
1708
1744
|
conditions.unshift(
|
|
1709
1745
|
`(n.tsv @@ ${tsqFn}('english', $1) OR
|
|
1710
|
-
|
|
1746
|
+
${COMBINED_TEXT_VECTOR_SQL2} @@ ${tsqFn}('english', $1))`
|
|
1711
1747
|
);
|
|
1712
1748
|
let paramIdx = this.scopeToResolvedEmbeddingSet(conditions, params, nextIdx, resolvedEmbeddingSet);
|
|
1713
1749
|
const allParams = [query, ...params];
|
|
@@ -1716,6 +1752,7 @@ var SearchRepository = class {
|
|
|
1716
1752
|
`SELECT COUNT(*) as count
|
|
1717
1753
|
FROM note n
|
|
1718
1754
|
LEFT JOIN note_revised_current c ON c.note_id = n.id
|
|
1755
|
+
${ATTACHMENT_TEXT_JOIN2}
|
|
1719
1756
|
WHERE ${where}`,
|
|
1720
1757
|
allParams
|
|
1721
1758
|
);
|
|
@@ -1724,17 +1761,18 @@ var SearchRepository = class {
|
|
|
1724
1761
|
const result = await this.db.query(
|
|
1725
1762
|
`SELECT n.id, n.title, n.created_at, n.updated_at,
|
|
1726
1763
|
ts_rank(
|
|
1727
|
-
setweight(n.tsv, 'A') || setweight(
|
|
1764
|
+
setweight(n.tsv, 'A') || setweight(${COMBINED_TEXT_VECTOR_SQL2}, 'B'),
|
|
1728
1765
|
${tsqFn}('english', $1)
|
|
1729
1766
|
) as rank,
|
|
1730
1767
|
ts_headline(
|
|
1731
1768
|
'english',
|
|
1732
|
-
|
|
1769
|
+
${COMBINED_TEXT_SQL},
|
|
1733
1770
|
${tsqFn}('english', $1),
|
|
1734
1771
|
'StartSel=<mark>, StopSel=</mark>, MaxWords=35, MinWords=15'
|
|
1735
1772
|
) as snippet
|
|
1736
1773
|
FROM note n
|
|
1737
1774
|
LEFT JOIN note_revised_current c ON c.note_id = n.id
|
|
1775
|
+
${ATTACHMENT_TEXT_JOIN2}
|
|
1738
1776
|
WHERE ${where}
|
|
1739
1777
|
ORDER BY rank DESC, n.created_at DESC
|
|
1740
1778
|
LIMIT $${paramIdx++} OFFSET $${paramIdx++}`,
|
|
@@ -1750,6 +1788,7 @@ var SearchRepository = class {
|
|
|
1750
1788
|
const idsResult = await this.db.query(
|
|
1751
1789
|
`SELECT n.id FROM note n
|
|
1752
1790
|
LEFT JOIN note_revised_current c ON c.note_id = n.id
|
|
1791
|
+
${ATTACHMENT_TEXT_JOIN2}
|
|
1753
1792
|
WHERE ${where}`,
|
|
1754
1793
|
allParams
|
|
1755
1794
|
);
|
|
@@ -1796,10 +1835,11 @@ var SearchRepository = class {
|
|
|
1796
1835
|
const result = await this.db.query(
|
|
1797
1836
|
`SELECT n.id, n.title, n.created_at, n.updated_at,
|
|
1798
1837
|
(e.vector <=> $${vecIdx}::vector) as distance,
|
|
1799
|
-
LEFT(
|
|
1838
|
+
LEFT(${COMBINED_TEXT_SQL}, 200) as snippet
|
|
1800
1839
|
FROM embedding e
|
|
1801
1840
|
JOIN note n ON n.id = e.note_id
|
|
1802
1841
|
LEFT JOIN note_revised_current c ON c.note_id = n.id
|
|
1842
|
+
${ATTACHMENT_TEXT_JOIN2}
|
|
1803
1843
|
WHERE ${where}
|
|
1804
1844
|
ORDER BY e.vector <=> $${vecIdx}::vector ASC
|
|
1805
1845
|
LIMIT $${limIdx} OFFSET $${offIdx}`,
|
|
@@ -1840,7 +1880,7 @@ var SearchRepository = class {
|
|
|
1840
1880
|
const textConditions = [
|
|
1841
1881
|
...textCond.conditions,
|
|
1842
1882
|
`(n.tsv @@ ${tsqFn}('english', $1) OR
|
|
1843
|
-
|
|
1883
|
+
${COMBINED_TEXT_VECTOR_SQL2} @@ ${tsqFn}('english', $1))`
|
|
1844
1884
|
];
|
|
1845
1885
|
this.scopeToResolvedEmbeddingSet(textConditions, textCond.params, textCond.nextIdx, resolvedEmbeddingSet);
|
|
1846
1886
|
const textWhere = textConditions.join(" AND ");
|
|
@@ -1848,11 +1888,12 @@ var SearchRepository = class {
|
|
|
1848
1888
|
const textResult = await this.db.query(
|
|
1849
1889
|
`SELECT n.id,
|
|
1850
1890
|
ts_rank(
|
|
1851
|
-
setweight(n.tsv, 'A') || setweight(
|
|
1891
|
+
setweight(n.tsv, 'A') || setweight(${COMBINED_TEXT_VECTOR_SQL2}, 'B'),
|
|
1852
1892
|
${tsqFn}('english', $1)
|
|
1853
1893
|
) as rank
|
|
1854
1894
|
FROM note n
|
|
1855
1895
|
LEFT JOIN note_revised_current c ON c.note_id = n.id
|
|
1896
|
+
${ATTACHMENT_TEXT_JOIN2}
|
|
1856
1897
|
WHERE ${textWhere}
|
|
1857
1898
|
ORDER BY rank DESC
|
|
1858
1899
|
LIMIT 100`,
|
|
@@ -1886,9 +1927,10 @@ var SearchRepository = class {
|
|
|
1886
1927
|
}
|
|
1887
1928
|
const noteResult = await this.db.query(
|
|
1888
1929
|
`SELECT n.id, n.title, n.created_at, n.updated_at,
|
|
1889
|
-
LEFT(
|
|
1930
|
+
LEFT(${COMBINED_TEXT_SQL}, 200) as snippet
|
|
1890
1931
|
FROM note n
|
|
1891
1932
|
LEFT JOIN note_revised_current c ON c.note_id = n.id
|
|
1933
|
+
${ATTACHMENT_TEXT_JOIN2}
|
|
1892
1934
|
WHERE n.id = ANY($1)`,
|
|
1893
1935
|
[pageIds]
|
|
1894
1936
|
);
|
|
@@ -1936,9 +1978,10 @@ var SearchRepository = class {
|
|
|
1936
1978
|
const listParams = [...params, limit, offset];
|
|
1937
1979
|
const result = await this.db.query(
|
|
1938
1980
|
`SELECT n.id, n.title, n.created_at, n.updated_at,
|
|
1939
|
-
LEFT(
|
|
1981
|
+
LEFT(${COMBINED_TEXT_SQL}, 200) as snippet
|
|
1940
1982
|
FROM note n
|
|
1941
1983
|
LEFT JOIN note_revised_current c ON c.note_id = n.id
|
|
1984
|
+
${ATTACHMENT_TEXT_JOIN2}
|
|
1942
1985
|
WHERE ${where}
|
|
1943
1986
|
ORDER BY n.created_at DESC
|
|
1944
1987
|
LIMIT $${paramIdx++} OFFSET $${paramIdx++}`,
|
|
@@ -3811,6 +3854,29 @@ function getLlmFunction() {
|
|
|
3811
3854
|
return llmFn;
|
|
3812
3855
|
}
|
|
3813
3856
|
|
|
3857
|
+
// src/repositories/note-text.ts
|
|
3858
|
+
async function getNoteTextWithExtractedAttachments(db, noteId) {
|
|
3859
|
+
const result = await db.query(
|
|
3860
|
+
`SELECT c.content,
|
|
3861
|
+
COALESCE(string_agg(a.extracted_text, E'
|
|
3862
|
+
' ORDER BY a.position, a.created_at)
|
|
3863
|
+
FILTER (WHERE a.extracted_text IS NOT NULL AND a.extracted_text <> ''), '') as extracted_text
|
|
3864
|
+
FROM note_revised_current c
|
|
3865
|
+
LEFT JOIN attachment a ON a.note_id = c.note_id AND a.deleted_at IS NULL
|
|
3866
|
+
WHERE c.note_id = $1
|
|
3867
|
+
GROUP BY c.content`,
|
|
3868
|
+
[noteId]
|
|
3869
|
+
);
|
|
3870
|
+
if (result.rows.length === 0) return null;
|
|
3871
|
+
const content = result.rows[0].content;
|
|
3872
|
+
const extractedText = result.rows[0].extracted_text ?? "";
|
|
3873
|
+
return {
|
|
3874
|
+
content,
|
|
3875
|
+
extracted_text: extractedText,
|
|
3876
|
+
combined: [content, extractedText].filter(Boolean).join("\n")
|
|
3877
|
+
};
|
|
3878
|
+
}
|
|
3879
|
+
|
|
3814
3880
|
// src/job-queue-worker.ts
|
|
3815
3881
|
var JOB_PRIORITIES = {
|
|
3816
3882
|
ai_revision: 1,
|
|
@@ -4092,12 +4158,9 @@ function conceptTaggingHandler(job, db) {
|
|
|
4092
4158
|
return (async () => {
|
|
4093
4159
|
const llmFn2 = getLlmFunction();
|
|
4094
4160
|
if (!llmFn2) return { skipped: true, reason: "no LLM function registered" };
|
|
4095
|
-
const
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
);
|
|
4099
|
-
if (result.rows.length === 0) throw new Error(`No content found for note ${job.note_id}`);
|
|
4100
|
-
const content = result.rows[0].content;
|
|
4161
|
+
const noteText = await getNoteTextWithExtractedAttachments(db, job.note_id);
|
|
4162
|
+
if (!noteText) throw new Error(`No content found for note ${job.note_id}`);
|
|
4163
|
+
const content = noteText.combined;
|
|
4101
4164
|
const prompt = `Task: Extract 3-5 topic tags from the text below.
|
|
4102
4165
|
Rules:
|
|
4103
4166
|
- Each tag is 1-3 words, lowercase
|
|
@@ -4990,9 +5053,17 @@ var AttachmentsRepository = class {
|
|
|
4990
5053
|
}
|
|
4991
5054
|
const attachmentId = generateId();
|
|
4992
5055
|
await this.db.query(
|
|
4993
|
-
`INSERT INTO attachment (id, note_id, blob_id, filename, display_name)
|
|
4994
|
-
VALUES ($1, $2, $3, $4, $5)`,
|
|
4995
|
-
[
|
|
5056
|
+
`INSERT INTO attachment (id, note_id, blob_id, filename, display_name, mime_type, extracted_text)
|
|
5057
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)`,
|
|
5058
|
+
[
|
|
5059
|
+
attachmentId,
|
|
5060
|
+
input.noteId,
|
|
5061
|
+
blobId,
|
|
5062
|
+
input.filename,
|
|
5063
|
+
input.displayName ?? null,
|
|
5064
|
+
input.mimeType ?? null,
|
|
5065
|
+
input.extractedText ?? null
|
|
5066
|
+
]
|
|
4996
5067
|
);
|
|
4997
5068
|
return this.get(attachmentId);
|
|
4998
5069
|
}
|
|
@@ -5055,6 +5126,7 @@ var ManageAttachmentsInputSchema = z.object({
|
|
|
5055
5126
|
data_base64: z.string().optional(),
|
|
5056
5127
|
filename: z.string().optional(),
|
|
5057
5128
|
mime_type: z.string().optional(),
|
|
5129
|
+
extracted_text: z.string().optional(),
|
|
5058
5130
|
display_name: z.string().optional()
|
|
5059
5131
|
});
|
|
5060
5132
|
async function manageAttachments(db, blobStore, rawInput) {
|
|
@@ -5073,6 +5145,7 @@ async function manageAttachments(db, blobStore, rawInput) {
|
|
|
5073
5145
|
data,
|
|
5074
5146
|
filename: input.filename,
|
|
5075
5147
|
mimeType: input.mime_type,
|
|
5148
|
+
extractedText: input.extracted_text,
|
|
5076
5149
|
displayName: input.display_name
|
|
5077
5150
|
});
|
|
5078
5151
|
return { action: "attach", attachment, size_bytes: data.length };
|
|
@@ -5324,12 +5397,9 @@ function averageEmbeddings(embeddings) {
|
|
|
5324
5397
|
async function embeddingGenerationHandler(job, db) {
|
|
5325
5398
|
const fn = embedFn;
|
|
5326
5399
|
if (!fn) return { skipped: true, reason: "no embed function registered" };
|
|
5327
|
-
const
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
);
|
|
5331
|
-
if (noteResult.rows.length === 0) throw new Error(`No content for note ${job.note_id}`);
|
|
5332
|
-
const content = noteResult.rows[0].content;
|
|
5400
|
+
const noteText = await getNoteTextWithExtractedAttachments(db, job.note_id);
|
|
5401
|
+
if (!noteText) throw new Error(`No content for note ${job.note_id}`);
|
|
5402
|
+
const content = noteText.combined;
|
|
5333
5403
|
const chunks = chunkText(content);
|
|
5334
5404
|
const embeddings = await fn(chunks);
|
|
5335
5405
|
const vector2 = averageEmbeddings(embeddings);
|
|
@@ -6512,6 +6582,7 @@ function noteToShard(note) {
|
|
|
6512
6582
|
title: note.title,
|
|
6513
6583
|
original_content: note.original_content,
|
|
6514
6584
|
revised_content: note.revised_content,
|
|
6585
|
+
...note.binary_sources?.length ? { binary_sources: note.binary_sources } : {},
|
|
6515
6586
|
format: note.format,
|
|
6516
6587
|
source: note.source,
|
|
6517
6588
|
starred: note.is_starred,
|
|
@@ -6532,6 +6603,7 @@ function noteFromShard(shard) {
|
|
|
6532
6603
|
is_archived: shard.archived,
|
|
6533
6604
|
original_content: shard.original_content,
|
|
6534
6605
|
revised_content: shard.revised_content,
|
|
6606
|
+
binary_sources: shard.binary_sources,
|
|
6535
6607
|
tags: shard.tags,
|
|
6536
6608
|
created_at: shard.created_at,
|
|
6537
6609
|
updated_at: shard.updated_at,
|
|
@@ -6789,9 +6861,40 @@ async function exportShard(db, options) {
|
|
|
6789
6861
|
tags.push(row.tag);
|
|
6790
6862
|
tagsByNote.set(row.note_id, tags);
|
|
6791
6863
|
}
|
|
6864
|
+
const attachmentRows = await db.query(
|
|
6865
|
+
`SELECT a.note_id,
|
|
6866
|
+
a.id,
|
|
6867
|
+
a.filename,
|
|
6868
|
+
a.mime_type,
|
|
6869
|
+
a.extracted_text,
|
|
6870
|
+
b.content_hash,
|
|
6871
|
+
b.size_bytes,
|
|
6872
|
+
b.storage_path
|
|
6873
|
+
FROM attachment a
|
|
6874
|
+
JOIN attachment_blob b ON b.id = a.blob_id
|
|
6875
|
+
WHERE a.deleted_at IS NULL
|
|
6876
|
+
ORDER BY a.note_id, a.position, a.created_at`
|
|
6877
|
+
);
|
|
6878
|
+
const binarySourcesByNote = /* @__PURE__ */ new Map();
|
|
6879
|
+
for (const row of attachmentRows.rows) {
|
|
6880
|
+
const source = {
|
|
6881
|
+
extracted_text: row.extracted_text ?? "",
|
|
6882
|
+
attachment: {
|
|
6883
|
+
id: row.id,
|
|
6884
|
+
path: row.storage_path ?? row.filename,
|
|
6885
|
+
mime: row.mime_type,
|
|
6886
|
+
checksum: row.content_hash,
|
|
6887
|
+
bytes: Number(row.size_bytes)
|
|
6888
|
+
}
|
|
6889
|
+
};
|
|
6890
|
+
const sources = binarySourcesByNote.get(row.note_id) ?? [];
|
|
6891
|
+
sources.push(source);
|
|
6892
|
+
binarySourcesByNote.set(row.note_id, sources);
|
|
6893
|
+
}
|
|
6792
6894
|
const notes = noteRows.rows.map((row) => ({
|
|
6793
6895
|
...row,
|
|
6794
|
-
tags: tagsByNote.get(row.id) ?? []
|
|
6896
|
+
tags: tagsByNote.get(row.id) ?? [],
|
|
6897
|
+
binary_sources: binarySourcesByNote.get(row.id)
|
|
6795
6898
|
}));
|
|
6796
6899
|
const exportedNoteIds = new Set(notes.map((n) => n.id));
|
|
6797
6900
|
const shardNotes = notes.map((n) => noteToShard(n));
|
|
@@ -7653,7 +7756,8 @@ function tokenize(query) {
|
|
|
7653
7756
|
return query.toLowerCase().split(/[^a-z0-9]+/i).filter((token) => token.length > 0);
|
|
7654
7757
|
}
|
|
7655
7758
|
function noteSearchText(note) {
|
|
7656
|
-
|
|
7759
|
+
const extractedText = note.binary_sources?.map((source) => source.extracted_text).filter(Boolean).join(" ") ?? "";
|
|
7760
|
+
return `${note.title ?? ""} ${note.original_content} ${note.revised_content ?? ""} ${extractedText}`.toLowerCase();
|
|
7657
7761
|
}
|
|
7658
7762
|
function countOccurrences(haystack, needle) {
|
|
7659
7763
|
if (!needle) return 0;
|
|
@@ -7674,7 +7778,8 @@ function noteMatchesTokens(note, tokens) {
|
|
|
7674
7778
|
function rankNote(note, tokens, weights) {
|
|
7675
7779
|
if (tokens.length === 0) return 0;
|
|
7676
7780
|
const title = (note.title ?? "").toLowerCase();
|
|
7677
|
-
const
|
|
7781
|
+
const extractedText = note.binary_sources?.map((source) => source.extracted_text).filter(Boolean).join(" ") ?? "";
|
|
7782
|
+
const content = `${note.original_content} ${note.revised_content ?? ""} ${extractedText}`.toLowerCase();
|
|
7678
7783
|
const tagText = note.tags.join(" ").toLowerCase();
|
|
7679
7784
|
let score = 0;
|
|
7680
7785
|
for (const token of tokens) {
|
|
@@ -7685,7 +7790,8 @@ function rankNote(note, tokens, weights) {
|
|
|
7685
7790
|
return score;
|
|
7686
7791
|
}
|
|
7687
7792
|
function makeSnippet(note, tokens, length) {
|
|
7688
|
-
const
|
|
7793
|
+
const extractedText = note.binary_sources?.map((source) => source.extracted_text).filter(Boolean).join(" ") ?? "";
|
|
7794
|
+
const content = `${note.original_content} ${note.revised_content ?? ""} ${extractedText}`.trim();
|
|
7689
7795
|
if (tokens.length === 0) return content.slice(0, length);
|
|
7690
7796
|
const lower = content.toLowerCase();
|
|
7691
7797
|
const firstAt = tokens.map((token) => lower.indexOf(token)).filter((index) => index !== -1).sort((a, b) => a - b)[0] ?? 0;
|
|
@@ -8093,8 +8199,6 @@ var REQUIRED_RECORD_FIELDS = [
|
|
|
8093
8199
|
"id",
|
|
8094
8200
|
"type",
|
|
8095
8201
|
"source",
|
|
8096
|
-
"title",
|
|
8097
|
-
"text",
|
|
8098
8202
|
"facets",
|
|
8099
8203
|
"tags",
|
|
8100
8204
|
"concepts",
|
|
@@ -8135,6 +8239,12 @@ function isPlainRecord(value) {
|
|
|
8135
8239
|
function isOptionalStringArray(value) {
|
|
8136
8240
|
return value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
8137
8241
|
}
|
|
8242
|
+
function isSupportedIndexSchemaVersion(value) {
|
|
8243
|
+
return value === "aiwg.fortemi.index.export.v1" || value === "aiwg.fortemi.index.export.v2";
|
|
8244
|
+
}
|
|
8245
|
+
function isSupportedRecordSchemaVersion(value) {
|
|
8246
|
+
return value === "aiwg.fortemi.index.record.v1" || value === "aiwg.fortemi.index.record.v2";
|
|
8247
|
+
}
|
|
8138
8248
|
function validateOptionalRichMetadata(item, index, errors) {
|
|
8139
8249
|
if (item.skos_concepts !== void 0) {
|
|
8140
8250
|
if (!Array.isArray(item.skos_concepts)) {
|
|
@@ -8181,28 +8291,80 @@ function validateOptionalRichMetadata(item, index, errors) {
|
|
|
8181
8291
|
if (relationship.metadata !== void 0 && !isPlainRecord(relationship.metadata)) {
|
|
8182
8292
|
errors.push("items[" + index + "].relationships[" + relationshipIndex + "].metadata must be an object");
|
|
8183
8293
|
}
|
|
8294
|
+
if (relationship.direction !== void 0 && relationship.direction !== "upstream" && relationship.direction !== "downstream" && relationship.direction !== "related") {
|
|
8295
|
+
errors.push("items[" + index + "].relationships[" + relationshipIndex + "].direction must be upstream, downstream, or related");
|
|
8296
|
+
}
|
|
8297
|
+
if (relationship.target_path !== void 0 && typeof relationship.target_path !== "string") {
|
|
8298
|
+
errors.push("items[" + index + "].relationships[" + relationshipIndex + "].target_path must be a string");
|
|
8299
|
+
}
|
|
8184
8300
|
}
|
|
8185
8301
|
}
|
|
8302
|
+
if (item.search !== void 0) {
|
|
8303
|
+
if (!isPlainRecord(item.search)) {
|
|
8304
|
+
errors.push("items[" + index + "].search must be an object");
|
|
8305
|
+
} else {
|
|
8306
|
+
if (!isOptionalStringArray(item.search.triggers)) errors.push("items[" + index + "].search.triggers must be a string array");
|
|
8307
|
+
if (!isOptionalStringArray(item.search.aliases)) errors.push("items[" + index + "].search.aliases must be a string array");
|
|
8308
|
+
if (!isOptionalStringArray(item.search.tags)) errors.push("items[" + index + "].search.tags must be a string array");
|
|
8309
|
+
if (item.search.frontmatter !== void 0 && !isPlainRecord(item.search.frontmatter)) {
|
|
8310
|
+
errors.push("items[" + index + "].search.frontmatter must be an object");
|
|
8311
|
+
}
|
|
8312
|
+
}
|
|
8313
|
+
}
|
|
8314
|
+
if (item.chunks !== void 0) {
|
|
8315
|
+
if (!Array.isArray(item.chunks)) {
|
|
8316
|
+
errors.push("items[" + index + "].chunks must be an array when present");
|
|
8317
|
+
} else {
|
|
8318
|
+
for (const [chunkIndex, chunk] of item.chunks.entries()) {
|
|
8319
|
+
if (!isPlainRecord(chunk)) errors.push("items[" + index + "].chunks[" + chunkIndex + "] must be an object");
|
|
8320
|
+
if (chunk.metadata !== void 0 && !isPlainRecord(chunk.metadata)) {
|
|
8321
|
+
errors.push("items[" + index + "].chunks[" + chunkIndex + "].metadata must be an object");
|
|
8322
|
+
}
|
|
8323
|
+
}
|
|
8324
|
+
}
|
|
8325
|
+
}
|
|
8326
|
+
if (item.embeddings !== void 0) {
|
|
8327
|
+
if (!Array.isArray(item.embeddings)) {
|
|
8328
|
+
errors.push("items[" + index + "].embeddings must be an array when present");
|
|
8329
|
+
} else {
|
|
8330
|
+
for (const [embeddingIndex, embedding] of item.embeddings.entries()) {
|
|
8331
|
+
if (!isPlainRecord(embedding)) errors.push("items[" + index + "].embeddings[" + embeddingIndex + "] must be an object");
|
|
8332
|
+
const vector2 = embedding.embedding ?? embedding.vector;
|
|
8333
|
+
if (vector2 !== void 0 && (!Array.isArray(vector2) || !vector2.every((entry) => typeof entry === "number"))) {
|
|
8334
|
+
errors.push("items[" + index + "].embeddings[" + embeddingIndex + "].embedding/vector must be a number array");
|
|
8335
|
+
}
|
|
8336
|
+
if (embedding.metadata !== void 0 && !isPlainRecord(embedding.metadata)) {
|
|
8337
|
+
errors.push("items[" + index + "].embeddings[" + embeddingIndex + "].metadata must be an object");
|
|
8338
|
+
}
|
|
8339
|
+
}
|
|
8340
|
+
}
|
|
8341
|
+
}
|
|
8342
|
+
if (item.compatibility !== void 0 && !isPlainRecord(item.compatibility)) {
|
|
8343
|
+
errors.push("items[" + index + "].compatibility must be an object");
|
|
8344
|
+
}
|
|
8186
8345
|
}
|
|
8187
8346
|
function validateAiwgFortemiIndexExport(value) {
|
|
8188
8347
|
const errors = [];
|
|
8189
8348
|
const counts = {};
|
|
8190
8349
|
const data = value;
|
|
8191
|
-
if (data?.schema_version
|
|
8192
|
-
errors.push("schema_version must be aiwg.fortemi.index.export.v1");
|
|
8350
|
+
if (!isSupportedIndexSchemaVersion(data?.schema_version)) {
|
|
8351
|
+
errors.push("schema_version must be aiwg.fortemi.index.export.v1 or aiwg.fortemi.index.export.v2");
|
|
8193
8352
|
}
|
|
8194
8353
|
if (!hasString(data?.generated_at)) errors.push("generated_at is required");
|
|
8195
8354
|
if (!hasString(data?.source?.repo)) errors.push("source.repo is required");
|
|
8196
8355
|
if (!hasString(data?.source?.privacy)) errors.push("source.privacy is required");
|
|
8197
8356
|
if (!Array.isArray(data?.items)) errors.push("items must be an array");
|
|
8357
|
+
if (data.compatibility !== void 0 && !isPlainRecord(data.compatibility)) {
|
|
8358
|
+
errors.push("compatibility must be an object");
|
|
8359
|
+
}
|
|
8198
8360
|
const ids = /* @__PURE__ */ new Set();
|
|
8199
8361
|
let previousId = "";
|
|
8200
8362
|
for (const [index, item] of (data.items ?? []).entries()) {
|
|
8201
8363
|
for (const field of REQUIRED_RECORD_FIELDS) {
|
|
8202
8364
|
if (!(field in item)) errors.push("items[" + index + "]." + field + " is required");
|
|
8203
8365
|
}
|
|
8204
|
-
if (item.schema_version
|
|
8205
|
-
errors.push("items[" + index + "].schema_version must be aiwg.fortemi.index.record.v1");
|
|
8366
|
+
if (!isSupportedRecordSchemaVersion(item.schema_version)) {
|
|
8367
|
+
errors.push("items[" + index + "].schema_version must be aiwg.fortemi.index.record.v1 or aiwg.fortemi.index.record.v2");
|
|
8206
8368
|
}
|
|
8207
8369
|
if (!hasString(item.id)) errors.push("items[" + index + "].id is required");
|
|
8208
8370
|
if (hasString(item.id) && ids.has(item.id)) errors.push("duplicate id: " + item.id);
|
|
@@ -8216,6 +8378,12 @@ function validateAiwgFortemiIndexExport(value) {
|
|
|
8216
8378
|
if (!hasString(item.source?.path)) errors.push("items[" + index + "].source.path is required");
|
|
8217
8379
|
if (!hasString(item.source?.repo_relative_path)) errors.push("items[" + index + "].source.repo_relative_path is required");
|
|
8218
8380
|
if (!hasString(item.source?.locator)) errors.push("items[" + index + "].source.locator is required");
|
|
8381
|
+
if (typeof item.title !== "string" && typeof item.search?.title !== "string" && typeof item.search?.name !== "string") {
|
|
8382
|
+
errors.push("items[" + index + "].title or search.title/search.name is required");
|
|
8383
|
+
}
|
|
8384
|
+
if (typeof item.text !== "string" && typeof item.search?.body !== "string" && typeof item.search?.summary !== "string") {
|
|
8385
|
+
errors.push("items[" + index + "].text or search.body/search.summary is required");
|
|
8386
|
+
}
|
|
8219
8387
|
if (!Array.isArray(item.tags)) errors.push("items[" + index + "].tags must be an array");
|
|
8220
8388
|
if (!Array.isArray(item.concepts)) errors.push("items[" + index + "].concepts must be an array");
|
|
8221
8389
|
if (!Array.isArray(item.relationships)) errors.push("items[" + index + "].relationships must be an array");
|
|
@@ -8296,8 +8464,8 @@ function validateProjectedRecords(items) {
|
|
|
8296
8464
|
const ids = /* @__PURE__ */ new Set();
|
|
8297
8465
|
let previousId = "";
|
|
8298
8466
|
for (const [index, item] of items.entries()) {
|
|
8299
|
-
if (item.schema_version
|
|
8300
|
-
errors.push("items[" + index + "].schema_version must be aiwg.fortemi.index.record.v1");
|
|
8467
|
+
if (!isSupportedRecordSchemaVersion(item.schema_version)) {
|
|
8468
|
+
errors.push("items[" + index + "].schema_version must be aiwg.fortemi.index.record.v1 or aiwg.fortemi.index.record.v2");
|
|
8301
8469
|
}
|
|
8302
8470
|
if (!hasString(item.id)) errors.push("items[" + index + "].id is required");
|
|
8303
8471
|
if (hasString(item.id) && ids.has(item.id)) errors.push("duplicate id: " + item.id);
|
|
@@ -8307,8 +8475,12 @@ function validateProjectedRecords(items) {
|
|
|
8307
8475
|
}
|
|
8308
8476
|
if (hasString(item.id)) previousId = item.id;
|
|
8309
8477
|
if (!hasString(item.type)) errors.push("items[" + index + "].type must be a non-empty string");
|
|
8310
|
-
if (
|
|
8311
|
-
|
|
8478
|
+
if (typeof item.title !== "string" && typeof item.search?.title !== "string" && typeof item.search?.name !== "string") {
|
|
8479
|
+
errors.push("items[" + index + "].title or search.title/search.name is required");
|
|
8480
|
+
}
|
|
8481
|
+
if (typeof item.text !== "string" && typeof item.search?.body !== "string" && typeof item.search?.summary !== "string") {
|
|
8482
|
+
errors.push("items[" + index + "].text or search.body/search.summary is required");
|
|
8483
|
+
}
|
|
8312
8484
|
if (!item.facets || typeof item.facets !== "object" || Array.isArray(item.facets)) {
|
|
8313
8485
|
errors.push("items[" + index + "].facets must be an object");
|
|
8314
8486
|
}
|
|
@@ -8400,6 +8572,86 @@ function getAiwgFortemiFacets(items) {
|
|
|
8400
8572
|
}
|
|
8401
8573
|
return result;
|
|
8402
8574
|
}
|
|
8575
|
+
function recordTitle(item) {
|
|
8576
|
+
return item.title ?? item.search?.title ?? item.search?.name ?? item.id;
|
|
8577
|
+
}
|
|
8578
|
+
function recordText(item) {
|
|
8579
|
+
const base = item.text ?? item.search?.body ?? item.search?.summary ?? item.chunks?.map((chunk) => chunk.text ?? chunk.body ?? chunk.summary ?? "").filter(Boolean).join("\n") ?? "";
|
|
8580
|
+
const extractedText = "binary_sources" in item ? item.binary_sources?.map((source) => source.extracted_text).filter(Boolean).join("\n") ?? "" : "";
|
|
8581
|
+
return [base, extractedText].filter(Boolean).join("\n");
|
|
8582
|
+
}
|
|
8583
|
+
function defaultEmbeddingInput(record, granularity) {
|
|
8584
|
+
const title = recordTitle(record);
|
|
8585
|
+
const text = recordText(record);
|
|
8586
|
+
if (granularity === "title-summary") {
|
|
8587
|
+
const extractedText = record.binary_sources?.map((source) => source.extracted_text).filter(Boolean).join("\n") ?? "";
|
|
8588
|
+
return [title, record.search?.summary ?? "", extractedText].filter(Boolean).join("\n");
|
|
8589
|
+
}
|
|
8590
|
+
return [title, text].filter(Boolean).join("\n");
|
|
8591
|
+
}
|
|
8592
|
+
function generatedAtString(value) {
|
|
8593
|
+
if (value instanceof Date) return value.toISOString();
|
|
8594
|
+
return value ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
8595
|
+
}
|
|
8596
|
+
async function buildAiwgStaticEmbeddingSet(index, options) {
|
|
8597
|
+
assertAiwgFortemiIndexExport(index);
|
|
8598
|
+
const granularity = options.granularity ?? "body";
|
|
8599
|
+
const records = options.records ?? index.items;
|
|
8600
|
+
const embeddings = [];
|
|
8601
|
+
for (const record of records) {
|
|
8602
|
+
const input = options.textForRecord?.(record) ?? defaultEmbeddingInput(record, granularity);
|
|
8603
|
+
const embedding = await options.backend.embed(input, record);
|
|
8604
|
+
if (embedding.length !== options.backend.dimensions) {
|
|
8605
|
+
throw new Error(`Embedding for ${record.id} has ${embedding.length} dimensions; expected ${options.backend.dimensions}`);
|
|
8606
|
+
}
|
|
8607
|
+
embeddings.push({
|
|
8608
|
+
record_id: record.id,
|
|
8609
|
+
embedding,
|
|
8610
|
+
granularity,
|
|
8611
|
+
input_hash: computeHash(new TextEncoder().encode(input)),
|
|
8612
|
+
source_path: record.source.path
|
|
8613
|
+
});
|
|
8614
|
+
}
|
|
8615
|
+
const embeddingSet = {
|
|
8616
|
+
schema_version: "aiwg.fortemi.embedding.set.v1",
|
|
8617
|
+
id: options.id,
|
|
8618
|
+
model: options.backend.model,
|
|
8619
|
+
dimensions: options.backend.dimensions,
|
|
8620
|
+
generated_at: generatedAtString(options.generatedAt),
|
|
8621
|
+
granularity,
|
|
8622
|
+
...options.metric ? { metric: options.metric } : {},
|
|
8623
|
+
input_hash_algorithm: "sha256",
|
|
8624
|
+
embeddings
|
|
8625
|
+
};
|
|
8626
|
+
assertAiwgStaticEmbeddingSet(embeddingSet);
|
|
8627
|
+
return embeddingSet;
|
|
8628
|
+
}
|
|
8629
|
+
function recordSearchValues(item) {
|
|
8630
|
+
const search = item.search;
|
|
8631
|
+
const values = [
|
|
8632
|
+
item.id,
|
|
8633
|
+
recordTitle(item),
|
|
8634
|
+
recordText(item),
|
|
8635
|
+
search?.title,
|
|
8636
|
+
search?.name,
|
|
8637
|
+
search?.summary,
|
|
8638
|
+
search?.body,
|
|
8639
|
+
search?.capability,
|
|
8640
|
+
search?.phase,
|
|
8641
|
+
search?.type,
|
|
8642
|
+
...search?.triggers ?? [],
|
|
8643
|
+
...search?.aliases ?? [],
|
|
8644
|
+
...search?.tags ?? [],
|
|
8645
|
+
...(item.chunks ?? []).flatMap((chunk) => [chunk.text, chunk.body, chunk.summary, chunk.source_path])
|
|
8646
|
+
];
|
|
8647
|
+
if (search?.frontmatter) {
|
|
8648
|
+
for (const value of Object.values(search.frontmatter)) {
|
|
8649
|
+
if (typeof value === "string") values.push(value);
|
|
8650
|
+
else if (Array.isArray(value)) values.push(...value.filter((entry) => typeof entry === "string"));
|
|
8651
|
+
}
|
|
8652
|
+
}
|
|
8653
|
+
return values.filter((value) => typeof value === "string" && value.length > 0);
|
|
8654
|
+
}
|
|
8403
8655
|
function buildAiwgChunkedIndex(index, options = {}) {
|
|
8404
8656
|
const partSize = hasPositiveInteger(options.partSize) ? options.partSize : 500;
|
|
8405
8657
|
const projection = options.projection;
|
|
@@ -8461,14 +8713,21 @@ function matchesFacetFilters(item, filters) {
|
|
|
8461
8713
|
function queryMatches(item, q) {
|
|
8462
8714
|
if (!q) return [];
|
|
8463
8715
|
const matches = [];
|
|
8464
|
-
|
|
8465
|
-
|
|
8716
|
+
const title = recordTitle(item);
|
|
8717
|
+
const text = recordText(item);
|
|
8718
|
+
if (title.toLowerCase().includes(q)) matches.push({ field: "title", value: title });
|
|
8719
|
+
if (text.toLowerCase().includes(q)) matches.push({ field: "text", value: text });
|
|
8466
8720
|
for (const tag of item.tags) {
|
|
8467
8721
|
if (tag.toLowerCase().includes(q)) matches.push({ field: "tag", value: tag });
|
|
8468
8722
|
}
|
|
8469
8723
|
for (const concept of item.concepts) {
|
|
8470
8724
|
if (concept.toLowerCase().includes(q)) matches.push({ field: "concept", value: concept });
|
|
8471
8725
|
}
|
|
8726
|
+
for (const value of recordSearchValues(item)) {
|
|
8727
|
+
if (value !== title && value !== text && value.toLowerCase().includes(q)) {
|
|
8728
|
+
matches.push({ field: "text", value, score: DEFAULT_QUERY_WEIGHTS.text });
|
|
8729
|
+
}
|
|
8730
|
+
}
|
|
8472
8731
|
return matches;
|
|
8473
8732
|
}
|
|
8474
8733
|
var DISCOVERY_STOPWORDS = /* @__PURE__ */ new Set([
|
|
@@ -8524,17 +8783,28 @@ function discoveryMatches(item, query) {
|
|
|
8524
8783
|
const idParts = item.id.split(/[:/]/);
|
|
8525
8784
|
const names = [
|
|
8526
8785
|
item.id,
|
|
8527
|
-
item
|
|
8786
|
+
recordTitle(item),
|
|
8787
|
+
item.search?.name,
|
|
8788
|
+
item.search?.title,
|
|
8789
|
+
...item.search?.aliases ?? [],
|
|
8528
8790
|
...idParts,
|
|
8529
8791
|
...facetValues(item, ["name", "canonical_name", "command", "skill", "agent", "rule"])
|
|
8530
|
-
].filter(
|
|
8531
|
-
const triggers =
|
|
8792
|
+
].filter((value) => hasString(value));
|
|
8793
|
+
const triggers = [
|
|
8794
|
+
...facetValues(item, ["trigger", "triggers", "trigger_phrase", "trigger_phrases"]),
|
|
8795
|
+
...item.search?.triggers ?? []
|
|
8796
|
+
];
|
|
8532
8797
|
const capabilities = [
|
|
8533
8798
|
...facetValues(item, ["capability", "capabilities", "summary", "description"]),
|
|
8799
|
+
item.search?.capability,
|
|
8800
|
+
item.search?.summary,
|
|
8801
|
+
item.search?.phase,
|
|
8802
|
+
item.search?.type,
|
|
8803
|
+
...item.search?.tags ?? [],
|
|
8534
8804
|
...item.concepts,
|
|
8535
8805
|
...item.tags
|
|
8536
|
-
];
|
|
8537
|
-
const sourceValues = [item.source?.path, item.source?.repo_relative_path, item.source?.locator].filter(
|
|
8806
|
+
].filter((value) => hasString(value));
|
|
8807
|
+
const sourceValues = [item.source?.path, item.source?.repo_relative_path, item.source?.locator].filter((value) => hasString(value));
|
|
8538
8808
|
for (const name of names) {
|
|
8539
8809
|
const canonicalName = canonicalDiscoveryName(name);
|
|
8540
8810
|
if (!canonicalName) continue;
|
|
@@ -8544,8 +8814,9 @@ function discoveryMatches(item, query) {
|
|
|
8544
8814
|
addDiscoveryMatch(matches, { field: "id", value: name, score: 48, reason: "near canonical name" });
|
|
8545
8815
|
}
|
|
8546
8816
|
}
|
|
8547
|
-
const
|
|
8548
|
-
|
|
8817
|
+
const title = recordTitle(item);
|
|
8818
|
+
const titleOverlap = tokenOverlapScore(tokens, title);
|
|
8819
|
+
if (titleOverlap > 0) addDiscoveryMatch(matches, { field: "title", value: title, score: 18 * titleOverlap, reason: "title token overlap" });
|
|
8549
8820
|
for (const trigger of triggers) {
|
|
8550
8821
|
const overlap = tokenOverlapScore(tokens, trigger);
|
|
8551
8822
|
if (overlap > 0) addDiscoveryMatch(matches, { field: "facet", value: trigger, score: 34 * overlap, reason: "trigger phrase" });
|
|
@@ -8554,8 +8825,9 @@ function discoveryMatches(item, query) {
|
|
|
8554
8825
|
const overlap = tokenOverlapScore(tokens, capability);
|
|
8555
8826
|
if (overlap > 0) addDiscoveryMatch(matches, { field: "concept", value: capability, score: 22 * overlap, reason: "capability overlap" });
|
|
8556
8827
|
}
|
|
8557
|
-
const
|
|
8558
|
-
|
|
8828
|
+
const text = recordText(item);
|
|
8829
|
+
const textOverlap = tokenOverlapScore(tokens, text);
|
|
8830
|
+
if (textOverlap > 0) addDiscoveryMatch(matches, { field: "text", value: text, score: 8 * textOverlap, reason: "body token overlap" });
|
|
8559
8831
|
for (const source of sourceValues) {
|
|
8560
8832
|
const overlap = tokenOverlapScore(tokens, source);
|
|
8561
8833
|
if (overlap > 0) addDiscoveryMatch(matches, { field: "source", value: source, score: 2 * overlap, reason: "path overlap" });
|
|
@@ -8583,7 +8855,7 @@ function createSnippet(item, matches, q, maxLength) {
|
|
|
8583
8855
|
const textMatch = matches.find((match) => match.field === "text");
|
|
8584
8856
|
const titleMatch = matches.find((match) => match.field === "title");
|
|
8585
8857
|
const firstMatch = textMatch ?? titleMatch ?? matches[0];
|
|
8586
|
-
return clipSnippet(firstMatch?.value ?? item
|
|
8858
|
+
return clipSnippet(firstMatch?.value ?? recordText(item), q, maxLength);
|
|
8587
8859
|
}
|
|
8588
8860
|
function createRankedEntries(items, q, options, ordinalBase = 0) {
|
|
8589
8861
|
const weights = { ...DEFAULT_QUERY_WEIGHTS, ...options.weights };
|
|
@@ -8845,13 +9117,16 @@ function edgeFromRelationship(sourceId, relationship) {
|
|
|
8845
9117
|
source_id: sourceId,
|
|
8846
9118
|
target_id: relationship.target_id,
|
|
8847
9119
|
type: relationship.type,
|
|
8848
|
-
...relationship.source_path ? { source_path: relationship.source_path } : {}
|
|
9120
|
+
...relationship.source_path ? { source_path: relationship.source_path } : {},
|
|
9121
|
+
...relationship.target_path ? { target_path: relationship.target_path } : {},
|
|
9122
|
+
...relationship.direction ? { direction: relationship.direction } : {}
|
|
8849
9123
|
};
|
|
8850
9124
|
}
|
|
8851
9125
|
function relationshipMatches(edge, options = {}) {
|
|
8852
9126
|
const type = relationshipTypeFilter(options);
|
|
8853
9127
|
const direction = options.direction ?? "both";
|
|
8854
9128
|
if (type && edge.type !== type) return false;
|
|
9129
|
+
if (options.relationshipDirection && edge.direction !== options.relationshipDirection) return false;
|
|
8855
9130
|
if (options.sourceId && edge.source_id !== options.sourceId) return false;
|
|
8856
9131
|
if (options.targetId && edge.target_id !== options.targetId) return false;
|
|
8857
9132
|
if (direction === "out" && options.targetId && edge.target_id !== options.targetId) return false;
|
|
@@ -8859,7 +9134,7 @@ function relationshipMatches(edge, options = {}) {
|
|
|
8859
9134
|
return true;
|
|
8860
9135
|
}
|
|
8861
9136
|
function nodeSummary(item) {
|
|
8862
|
-
return { id: item.id, type: item.type, title: item
|
|
9137
|
+
return { id: item.id, type: item.type, title: recordTitle(item) };
|
|
8863
9138
|
}
|
|
8864
9139
|
function addNode(nodes, item) {
|
|
8865
9140
|
if (item) nodes.set(item.id, nodeSummary(item));
|
|
@@ -9243,8 +9518,8 @@ function communityIdsFor(item, options) {
|
|
|
9243
9518
|
}
|
|
9244
9519
|
|
|
9245
9520
|
// src/index.ts
|
|
9246
|
-
var VERSION = "2026.7.
|
|
9521
|
+
var VERSION = "2026.7.2";
|
|
9247
9522
|
|
|
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 };
|
|
9523
|
+
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, buildAiwgStaticEmbeddingSet, 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 };
|
|
9249
9524
|
//# sourceMappingURL=index.js.map
|
|
9250
9525
|
//# sourceMappingURL=index.js.map
|