@agentskit/doc-bridge 0.1.0-alpha.2 → 0.1.0-alpha.3

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.d.ts CHANGED
@@ -272,6 +272,8 @@ declare const KnowledgeEntrySchema: z.ZodObject<{
272
272
  title: z.ZodString;
273
273
  path: z.ZodString;
274
274
  description: z.ZodOptional<z.ZodString>;
275
+ /** Flattened body excerpt for full-text search (not for display). */
276
+ body: z.ZodOptional<z.ZodString>;
275
277
  links: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
276
278
  tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
277
279
  }, "strict", z.ZodTypeAny, {
@@ -280,6 +282,7 @@ declare const KnowledgeEntrySchema: z.ZodObject<{
280
282
  id: string;
281
283
  title: string;
282
284
  description?: string | undefined;
285
+ body?: string | undefined;
283
286
  links?: string[] | undefined;
284
287
  tags?: string[] | undefined;
285
288
  }, {
@@ -288,6 +291,7 @@ declare const KnowledgeEntrySchema: z.ZodObject<{
288
291
  id: string;
289
292
  title: string;
290
293
  description?: string | undefined;
294
+ body?: string | undefined;
291
295
  links?: string[] | undefined;
292
296
  tags?: string[] | undefined;
293
297
  }>;
@@ -328,6 +332,8 @@ declare const DocBridgeIndexV1Schema: z.ZodObject<{
328
332
  title: z.ZodString;
329
333
  path: z.ZodString;
330
334
  description: z.ZodOptional<z.ZodString>;
335
+ /** Flattened body excerpt for full-text search (not for display). */
336
+ body: z.ZodOptional<z.ZodString>;
331
337
  links: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
332
338
  tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
333
339
  }, "strict", z.ZodTypeAny, {
@@ -336,6 +342,7 @@ declare const DocBridgeIndexV1Schema: z.ZodObject<{
336
342
  id: string;
337
343
  title: string;
338
344
  description?: string | undefined;
345
+ body?: string | undefined;
339
346
  links?: string[] | undefined;
340
347
  tags?: string[] | undefined;
341
348
  }, {
@@ -344,6 +351,7 @@ declare const DocBridgeIndexV1Schema: z.ZodObject<{
344
351
  id: string;
345
352
  title: string;
346
353
  description?: string | undefined;
354
+ body?: string | undefined;
347
355
  links?: string[] | undefined;
348
356
  tags?: string[] | undefined;
349
357
  }>, "many">;
@@ -550,6 +558,7 @@ declare const DocBridgeIndexV1Schema: z.ZodObject<{
550
558
  id: string;
551
559
  title: string;
552
560
  description?: string | undefined;
561
+ body?: string | undefined;
553
562
  links?: string[] | undefined;
554
563
  tags?: string[] | undefined;
555
564
  }[];
@@ -623,6 +632,7 @@ declare const DocBridgeIndexV1Schema: z.ZodObject<{
623
632
  id: string;
624
633
  title: string;
625
634
  description?: string | undefined;
635
+ body?: string | undefined;
626
636
  links?: string[] | undefined;
627
637
  tags?: string[] | undefined;
628
638
  }[];
@@ -952,7 +962,11 @@ declare const DocBridgeIndexV1JsonSchema: {
952
962
  };
953
963
  readonly description: {
954
964
  readonly type: "string";
955
- readonly maxLength: 1024;
965
+ readonly maxLength: 2048;
966
+ };
967
+ readonly body: {
968
+ readonly type: "string";
969
+ readonly maxLength: 8000;
956
970
  };
957
971
  readonly links: JsonSchema;
958
972
  readonly tags: JsonSchema;
@@ -1170,7 +1184,11 @@ declare const DocBridgeJsonSchemas: {
1170
1184
  };
1171
1185
  readonly description: {
1172
1186
  readonly type: "string";
1173
- readonly maxLength: 1024;
1187
+ readonly maxLength: 2048;
1188
+ };
1189
+ readonly body: {
1190
+ readonly type: "string";
1191
+ readonly maxLength: 8000;
1174
1192
  };
1175
1193
  readonly links: JsonSchema;
1176
1194
  readonly tags: JsonSchema;
@@ -1517,7 +1535,7 @@ declare const chunksFromMarkdown: (property: string, raw: string, sourceUrl: str
1517
1535
  declare const loadFederatedChunks: (root: string, config: DocBridgeConfigV1, options?: FederatedRetrieverOptions) => Promise<DocBridgeRetrievedChunk[]>;
1518
1536
  declare const retrieveHybridChunks: (root: string, config: DocBridgeConfigV1, index: DocBridgeIndexV1, query: string, options?: FederatedRetrieverOptions) => Promise<DocBridgeRetrievedChunk[]>;
1519
1537
 
1520
- declare const PACKAGE_VERSION = "0.1.0-alpha.2";
1538
+ declare const PACKAGE_VERSION = "0.1.0-alpha.3";
1521
1539
 
1522
1540
  type FrontmatterValue = string | boolean | readonly string[];
1523
1541
  type FrontmatterData = Record<string, FrontmatterValue>;
package/dist/index.js CHANGED
@@ -423,7 +423,9 @@ var KnowledgeEntrySchema = z3.object({
423
423
  type: z3.string().min(1).max(128),
424
424
  title: z3.string().min(1).max(256),
425
425
  path: z3.string().min(1).max(512),
426
- description: z3.string().max(1024).optional(),
426
+ description: z3.string().max(2048).optional(),
427
+ /** Flattened body excerpt for full-text search (not for display). */
428
+ body: z3.string().max(8e3).optional(),
427
429
  links: z3.array(z3.string().min(1).max(512)).max(64).optional(),
428
430
  tags: z3.array(z3.string().min(1).max(64)).max(32).optional()
429
431
  }).strict();
@@ -628,7 +630,8 @@ var DocBridgeIndexV1JsonSchema = {
628
630
  type: { type: "string", minLength: 1, maxLength: 128 },
629
631
  title: { type: "string", minLength: 1, maxLength: 256 },
630
632
  path: { type: "string", minLength: 1, maxLength: 512 },
631
- description: { type: "string", maxLength: 1024 },
633
+ description: { type: "string", maxLength: 2048 },
634
+ body: { type: "string", maxLength: 8e3 },
632
635
  links: stringArray(64),
633
636
  tags: stringArray(32)
634
637
  }
@@ -821,7 +824,7 @@ var firstHeading = (markdown) => {
821
824
  }
822
825
  return void 0;
823
826
  };
824
- var firstParagraph = (markdown) => {
827
+ var firstParagraph = (markdown, maxLen = 400) => {
825
828
  const { body } = parseFrontmatter(markdown);
826
829
  const lines = body.split("\n");
827
830
  const buf = [];
@@ -833,11 +836,27 @@ var firstParagraph = (markdown) => {
833
836
  }
834
837
  if (t.startsWith("#")) continue;
835
838
  if (t.startsWith("---")) continue;
839
+ if (t.startsWith("```")) break;
840
+ if (t.startsWith("|") || t.startsWith("- [") || t.startsWith("* [")) {
841
+ if (buf.length) break;
842
+ continue;
843
+ }
836
844
  buf.push(t);
837
- if (buf.join(" ").length > 40) break;
838
- }
839
- const text = buf.join(" ").trim();
840
- return text || void 0;
845
+ if (buf.join(" ").length >= maxLen) break;
846
+ }
847
+ let text = buf.join(" ").replace(/\s+/g, " ").trim();
848
+ if (!text) return void 0;
849
+ if (text.length <= maxLen) return text;
850
+ const sliced = text.slice(0, maxLen);
851
+ const sentenceEnd = Math.max(sliced.lastIndexOf(". "), sliced.lastIndexOf("! "), sliced.lastIndexOf("? "));
852
+ if (sentenceEnd > maxLen * 0.4) return sliced.slice(0, sentenceEnd + 1).trim();
853
+ const wordEnd = sliced.lastIndexOf(" ");
854
+ return (wordEnd > 0 ? sliced.slice(0, wordEnd) : sliced).trim();
855
+ };
856
+ var extractSearchBody = (markdown, maxLen = 6e3) => {
857
+ const { body } = parseFrontmatter(markdown);
858
+ const text = body.replace(/```[\s\S]*?```/g, " ").replace(/!\[[^\]]*\]\([^)]+\)/g, " ").replace(/\[[^\]]*\]\([^)]+\)/g, " ").replace(/^#+\s+/gm, "").replace(/[|>*_`#]/g, " ").replace(/\s+/g, " ").trim();
859
+ return text.length > maxLen ? text.slice(0, maxLen) : text;
841
860
  };
842
861
  var slugFromPath = (relPath) => {
843
862
  const base = relPath.replace(/\.mdx?$/, "");
@@ -895,7 +914,9 @@ var scanAgentCorpus = (root, config) => {
895
914
  const { data: frontmatter } = parseFrontmatter(raw);
896
915
  const id = frontmatterString(frontmatter, "id") ?? frontmatterString(frontmatter, "package") ?? slugFromPath(relToCorpus);
897
916
  const title = firstHeading(raw) ?? id;
898
- const description = firstParagraph(raw);
917
+ const purpose = frontmatterString(frontmatter, "purpose");
918
+ const description = purpose ?? firstParagraph(raw, 400);
919
+ const body = extractSearchBody(raw);
899
920
  return {
900
921
  id,
901
922
  type: "agent-doc",
@@ -904,7 +925,8 @@ var scanAgentCorpus = (root, config) => {
904
925
  absPath: abs,
905
926
  relPath,
906
927
  frontmatter,
907
- ...description ? { description } : {}
928
+ ...description ? { description } : {},
929
+ ...body ? { body } : {}
908
930
  };
909
931
  });
910
932
  };
@@ -1037,11 +1059,19 @@ var resolveHumanDoc = (packageId, override, fmHuman, humanDocs = {}) => {
1037
1059
  packageId,
1038
1060
  packageId.replace(/^@[^/]+\//, ""),
1039
1061
  packageId.replace(/^os-/, ""),
1040
- packageId.replace(/-pattern$/, "")
1062
+ packageId.replace(/-pattern$/, ""),
1063
+ `packages/${packageId}`,
1064
+ `reference/packages/${packageId}`,
1065
+ `packages/${packageId}/index`
1041
1066
  ];
1042
1067
  for (const alias of aliases) {
1043
1068
  if (humanDocs[alias]) return humanDocs[alias];
1044
1069
  }
1070
+ for (const [key, url] of Object.entries(humanDocs)) {
1071
+ if (key === packageId || key.endsWith(`/${packageId}`) || key.endsWith(`/${packageId}/index`) || key.endsWith(`-${packageId}`)) {
1072
+ return url;
1073
+ }
1074
+ }
1045
1075
  return void 0;
1046
1076
  };
1047
1077
  var buildLookup = (config, packages, corpus, indexOutFile, humanDocs = {}, root = process.cwd()) => {
@@ -1127,7 +1157,7 @@ var buildLookup = (config, packages, corpus, indexOutFile, humanDocs = {}, root
1127
1157
  };
1128
1158
 
1129
1159
  // src/version.ts
1130
- var PACKAGE_VERSION = "0.1.0-alpha.2";
1160
+ var PACKAGE_VERSION = "0.1.0-alpha.3";
1131
1161
 
1132
1162
  // src/index-builder/capabilities.ts
1133
1163
  var renderCapabilitiesJson = (config, index, paths) => {
@@ -1800,19 +1830,58 @@ import { relative, resolve as resolve4 } from "path";
1800
1830
  import { z as z5, ZodError } from "zod";
1801
1831
 
1802
1832
  // src/query/search.ts
1803
- var tokenize = (value) => value.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 2);
1833
+ var tokenize = (value) => value.toLowerCase().split(/[^a-z0-9@/_-]+/).filter((t) => t.length >= 2);
1834
+ var PACKAGE_INTENT = /\b(package|module|pkg|edit|change|where|owns?|ownership|handoff|start)\b/i;
1835
+ var scoreHay = (tokens, hay, weight = 1) => {
1836
+ let score = 0;
1837
+ for (const token of tokens) {
1838
+ if (!hay.includes(token)) continue;
1839
+ score += token.length * weight;
1840
+ if (new RegExp(`(?:^|[^a-z0-9])${token}(?:[^a-z0-9]|$)`).test(hay)) {
1841
+ score += token.length;
1842
+ }
1843
+ }
1844
+ return score;
1845
+ };
1846
+ var identityBoost = (id, path, tokens, term) => {
1847
+ const idLower = id.toLowerCase();
1848
+ const termLower = term.toLowerCase().trim();
1849
+ const base = path.split("/").pop()?.replace(/\.mdx?$/i, "").toLowerCase() ?? "";
1850
+ let boost = 0;
1851
+ if (idLower === termLower || base === termLower) boost += 200;
1852
+ if (tokens.length === 1 && (idLower === tokens[0] || base === tokens[0])) boost += 200;
1853
+ for (const token of tokens) {
1854
+ if (idLower === token) boost += 120;
1855
+ else if (idLower.startsWith(`${token}-`) || idLower.endsWith(`-${token}`)) boost += 40;
1856
+ else if (idLower.includes(token) && idLower.length <= token.length + 4) boost += 30;
1857
+ if (base === token) boost += 100;
1858
+ }
1859
+ if (tokens.includes(idLower)) boost += Math.max(0, 40 - idLower.length);
1860
+ return boost;
1861
+ };
1862
+ var preferOwnership = (term) => PACKAGE_INTENT.test(term) || /^(where|how).*(edit|change|package|module)/i.test(term);
1804
1863
  var searchIndex = (index, term, limit = 20) => {
1805
1864
  const tokens = tokenize(term);
1806
1865
  if (!tokens.length) return [];
1807
- const matches = [];
1808
- for (const entry of index.knowledge) {
1809
- const hay = `${entry.id} ${entry.title} ${entry.description ?? ""} ${entry.path}`.toLowerCase();
1810
- let score = 0;
1811
- for (const token of tokens) {
1812
- if (hay.includes(token)) score += token.length;
1866
+ const wantOwnership = preferOwnership(term);
1867
+ const byPath = /* @__PURE__ */ new Map();
1868
+ const consider = (match) => {
1869
+ const key = match.path;
1870
+ const existing = byPath.get(key);
1871
+ if (!existing) {
1872
+ byPath.set(key, match);
1873
+ return;
1813
1874
  }
1875
+ const prefer = match.score > existing.score || match.score === existing.score && match.type === "ownership" && existing.type !== "ownership" || wantOwnership && match.type === "ownership" && existing.type !== "ownership" && match.score >= existing.score - 20;
1876
+ if (prefer) byPath.set(key, match);
1877
+ };
1878
+ for (const entry of index.knowledge) {
1879
+ const body = entry.body ?? "";
1880
+ const hay = `${entry.id} ${entry.title} ${entry.description ?? ""} ${entry.path} ${body}`.toLowerCase();
1881
+ let score = scoreHay(tokens, hay, 1);
1882
+ score += identityBoost(entry.id, entry.path, tokens, term);
1814
1883
  if (score > 0) {
1815
- matches.push({
1884
+ consider({
1816
1885
  type: "knowledge",
1817
1886
  id: entry.id,
1818
1887
  path: entry.path,
@@ -1822,22 +1891,31 @@ var searchIndex = (index, term, limit = 20) => {
1822
1891
  }
1823
1892
  }
1824
1893
  for (const [id, owner] of Object.entries(index.lookup?.ownership ?? {})) {
1825
- const hay = `${id} ${owner.path} ${owner.purpose ?? ""} ${owner.group ?? ""}`.toLowerCase();
1826
- let score = 0;
1827
- for (const token of tokens) {
1828
- if (hay.includes(token)) score += token.length * 2;
1829
- }
1894
+ const path = owner.agentDoc ?? owner.path;
1895
+ const hay = `${id} ${owner.path} ${owner.purpose ?? ""} ${owner.group ?? ""} ${owner.agentDoc ?? ""} ${owner.humanDoc ?? ""}`.toLowerCase();
1896
+ let score = scoreHay(tokens, hay, 2);
1897
+ score += identityBoost(id, path, tokens, term);
1898
+ if (wantOwnership) score += 25;
1899
+ score += 15;
1830
1900
  if (score > 0) {
1831
- matches.push({
1901
+ consider({
1832
1902
  type: "ownership",
1833
1903
  id,
1834
- path: owner.agentDoc ?? owner.path,
1904
+ path,
1835
1905
  ...owner.purpose ? { summary: owner.purpose } : {},
1836
1906
  score
1837
1907
  });
1838
1908
  }
1839
1909
  }
1840
- return matches.sort((a, b) => b.score - a.score).slice(0, limit);
1910
+ return [...byPath.values()].sort((a, b) => {
1911
+ if (b.score !== a.score) return b.score - a.score;
1912
+ const aExact = tokens.includes(a.id.toLowerCase()) ? 1 : 0;
1913
+ const bExact = tokens.includes(b.id.toLowerCase()) ? 1 : 0;
1914
+ if (bExact !== aExact) return bExact - aExact;
1915
+ if (a.type === "ownership" && b.type !== "ownership") return -1;
1916
+ if (b.type === "ownership" && a.type !== "ownership") return 1;
1917
+ return a.id.localeCompare(b.id);
1918
+ }).slice(0, limit);
1841
1919
  };
1842
1920
 
1843
1921
  // src/retriever/doc-bridge-retriever.ts
@@ -2315,10 +2393,14 @@ var defaultFetchText = async (url) => {
2315
2393
  return res.text();
2316
2394
  };
2317
2395
  var sourceText = async (root, source, fetchText) => {
2318
- if (/^https?:\/\//.test(source)) return fetchText(source);
2319
- const path = resolve5(root, source);
2320
- if (!existsSync9(path)) throw new Error(`Federation source not found: ${source}`);
2321
- return readFileSync13(path, "utf8");
2396
+ try {
2397
+ if (/^https?:\/\//.test(source)) return await fetchText(source);
2398
+ const path = resolve5(root, source);
2399
+ if (!existsSync9(path)) return null;
2400
+ return readFileSync13(path, "utf8");
2401
+ } catch {
2402
+ return null;
2403
+ }
2322
2404
  };
2323
2405
  var sameOrigin = (base, target) => {
2324
2406
  if (!/^https?:\/\//.test(base) || !/^https?:\/\//.test(target)) return true;
@@ -2357,22 +2439,28 @@ var chunksFromMarkdown = (property, raw, sourceUrl) => {
2357
2439
  var loadFederatedChunks = async (root, config, options = {}) => {
2358
2440
  const fetchText = options.fetchText ?? defaultFetchText;
2359
2441
  const chunks = [];
2442
+ const warnings = [];
2360
2443
  for (const source of config.federation?.sources ?? []) {
2361
2444
  if (source.includeInRetriever === false || !source.llmsTxt) continue;
2362
2445
  const llms = await sourceText(root, source.llmsTxt, fetchText);
2446
+ if (!llms) {
2447
+ warnings.push(`federation source skipped (unavailable): ${source.id} \u2192 ${source.llmsTxt}`);
2448
+ continue;
2449
+ }
2363
2450
  chunks.push(...chunksFromMarkdown(source.id, llms, source.llmsTxt));
2364
2451
  const links = parseLlmsTxtLinks(llms);
2365
2452
  for (const link of links) {
2366
2453
  const url = !/^https?:\/\//.test(link.url) && source.rawBaseUrl ? `${source.rawBaseUrl.replace(/\/$/, "")}/${link.url.replace(/^\//, "")}` : link.url;
2367
2454
  if (!/\.(md|txt)(?:$|\?)/.test(url)) continue;
2368
2455
  if (!sameOrigin(source.llmsTxt, url)) continue;
2369
- try {
2370
- const raw = await sourceText(root, url, fetchText);
2371
- chunks.push(...chunksFromMarkdown(source.id, raw, url));
2372
- } catch {
2373
- }
2456
+ const raw = await sourceText(root, url, fetchText);
2457
+ if (raw) chunks.push(...chunksFromMarkdown(source.id, raw, url));
2374
2458
  }
2375
2459
  }
2460
+ if (warnings.length && process.stderr.isTTY) {
2461
+ for (const w of warnings) process.stderr.write(`${w}
2462
+ `);
2463
+ }
2376
2464
  return chunks;
2377
2465
  };
2378
2466
  var retrieveHybridChunks = async (root, config, index, query, options = {}) => {