@agentskit/doc-bridge 0.1.0-alpha.1 → 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/CHANGELOG.md +28 -0
- package/README.md +1 -1
- package/dist/cli/program.js +416 -148
- package/dist/cli/program.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +6 -3
- package/dist/config/index.js.map +1 -1
- package/dist/{index-CD_zmKXf.d.ts → index-CPUJbTbg.d.ts} +19 -10
- package/dist/index.d.ts +25 -6
- package/dist/index.js +398 -132
- package/dist/index.js.map +1 -1
- package/docs/DOGFOOD-ROUND2.md +142 -0
- package/docs/DOGFOOD.md +92 -0
- package/package.json +32 -14
- package/scripts/prepare.mjs +44 -0
- package/src/cli/program.ts +947 -0
- package/src/config/defaults.ts +63 -0
- package/src/config/define-config.ts +6 -0
- package/src/config/index.ts +15 -0
- package/src/config/load-config.ts +138 -0
- package/src/config/schema.ts +294 -0
- package/src/federation/llms.ts +154 -0
- package/src/gates/run-gates.ts +274 -0
- package/src/index-builder/build-handoffs.ts +232 -0
- package/src/index-builder/build-index.ts +137 -0
- package/src/index-builder/capabilities.ts +37 -0
- package/src/index-builder/content-hash.ts +19 -0
- package/src/index-builder/human-adapters/core.ts +100 -0
- package/src/index-builder/human-adapters/docusaurus.ts +113 -0
- package/src/index-builder/human-adapters/fumadocs.ts +70 -0
- package/src/index-builder/human-adapters/index.ts +52 -0
- package/src/index-builder/human-adapters/plain-markdown.ts +10 -0
- package/src/index-builder/llms-txt.ts +19 -0
- package/src/index-builder/plugins/human-markdown.ts +7 -0
- package/src/index-builder/plugins/pnpm-monorepo.ts +72 -0
- package/src/index-builder/scan-corpus.ts +185 -0
- package/src/index.ts +120 -0
- package/src/intelligence/adapter.ts +90 -0
- package/src/intelligence/chat.ts +148 -0
- package/src/intelligence/peers.ts +59 -0
- package/src/intelligence/rag.ts +98 -0
- package/src/lib/glob-expand.ts +33 -0
- package/src/lib/markdown.ts +117 -0
- package/src/lib/package-manager.ts +104 -0
- package/src/lib/paths.ts +6 -0
- package/src/lib/walk.ts +45 -0
- package/src/mcp/server.ts +276 -0
- package/src/memory/ingest.ts +51 -0
- package/src/memory/pipeline.ts +119 -0
- package/src/query/load-index.ts +25 -0
- package/src/query/query.ts +142 -0
- package/src/query/search.ts +126 -0
- package/src/retriever/doc-bridge-retriever.ts +62 -0
- package/src/schemas/agent-handoff.ts +82 -0
- package/src/schemas/doc-bridge-index.ts +108 -0
- package/src/schemas/json-schemas.ts +157 -0
- package/src/schemas/memory-candidate.ts +37 -0
- package/src/shims/agentskit-peers.d.ts +80 -0
- package/src/validate.ts +67 -0
- package/src/version.ts +1 -0
- package/tsconfig.json +21 -0
- package/tsup.config.ts +15 -0
package/dist/cli/program.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/cli/program.ts
|
|
2
|
-
import { existsSync as
|
|
2
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync2, readFileSync as readFileSync15, writeFileSync as writeFileSync2 } from "fs";
|
|
3
3
|
import { dirname as dirname4, resolve as resolve6 } from "path";
|
|
4
4
|
import { createInterface } from "readline/promises";
|
|
5
5
|
|
|
@@ -20,7 +20,7 @@ var applyConfigDefaults = (config) => {
|
|
|
20
20
|
agent: {
|
|
21
21
|
...config.corpus.agent,
|
|
22
22
|
index: agentIndex,
|
|
23
|
-
include: config.corpus.agent.include ?? ["**/*.md"],
|
|
23
|
+
include: config.corpus.agent.include ?? ["**/*.{md,mdx}"],
|
|
24
24
|
exclude: config.corpus.agent.exclude ?? [...DEFAULT_AGENT_EXCLUDE]
|
|
25
25
|
}
|
|
26
26
|
},
|
|
@@ -113,9 +113,11 @@ var OwnershipEntrySchema = z.object({
|
|
|
113
113
|
humanDoc: z.string().min(1).max(512).optional()
|
|
114
114
|
}).strict();
|
|
115
115
|
var RoutingConfigSchema = z.object({
|
|
116
|
-
plugin: z.enum(["pnpm-monorepo", "npm-workspaces", "yarn-workspaces", "custom"]).optional(),
|
|
116
|
+
plugin: z.enum(["pnpm-monorepo", "npm-workspaces", "yarn-workspaces", "pattern-files", "custom"]).optional(),
|
|
117
117
|
options: z.object({
|
|
118
118
|
packages: z.array(z.string().min(1).max(256)).max(128).optional(),
|
|
119
|
+
/** Infer ownership from corpus paths/frontmatter (default true). */
|
|
120
|
+
ownershipFromCorpus: z.boolean().optional(),
|
|
119
121
|
ownership: z.record(z.string().min(1).max(256), OwnershipEntrySchema).optional(),
|
|
120
122
|
intents: z.array(
|
|
121
123
|
z.object({
|
|
@@ -135,7 +137,8 @@ var RoutingConfigSchema = z.object({
|
|
|
135
137
|
}).strict().optional()
|
|
136
138
|
}).strict();
|
|
137
139
|
var GatesConfigSchema = z.object({
|
|
138
|
-
|
|
140
|
+
/** minimal: freshness · standard: + human links · strict: + okf-type · playbook: freshness + okf soft style */
|
|
141
|
+
preset: z.enum(["minimal", "standard", "strict", "playbook"]).optional(),
|
|
139
142
|
include: z.array(
|
|
140
143
|
z.enum([
|
|
141
144
|
"index-freshness",
|
|
@@ -343,16 +346,80 @@ var projectRootFromConfigPath = (configFilePath, projectRootField) => {
|
|
|
343
346
|
};
|
|
344
347
|
|
|
345
348
|
// src/index-builder/build-index.ts
|
|
346
|
-
import { mkdirSync, readFileSync as
|
|
347
|
-
import { dirname as dirname3, join as
|
|
349
|
+
import { mkdirSync, readFileSync as readFileSync8, writeFileSync } from "fs";
|
|
350
|
+
import { dirname as dirname3, join as join10 } from "path";
|
|
348
351
|
|
|
349
352
|
// src/lib/paths.ts
|
|
350
353
|
import { resolve as resolve2 } from "path";
|
|
351
354
|
var toPosix = (value) => value.split("\\").join("/");
|
|
352
355
|
|
|
356
|
+
// src/lib/package-manager.ts
|
|
357
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
358
|
+
import { join as join2 } from "path";
|
|
359
|
+
var detectPackageManager = (root) => {
|
|
360
|
+
if (existsSync2(join2(root, "pnpm-lock.yaml")) || existsSync2(join2(root, "pnpm-workspace.yaml"))) {
|
|
361
|
+
return "pnpm";
|
|
362
|
+
}
|
|
363
|
+
if (existsSync2(join2(root, "yarn.lock"))) return "yarn";
|
|
364
|
+
if (existsSync2(join2(root, "bun.lockb")) || existsSync2(join2(root, "bun.lock"))) return "bun";
|
|
365
|
+
if (existsSync2(join2(root, "package-lock.json"))) return "npm";
|
|
366
|
+
try {
|
|
367
|
+
const pkg = JSON.parse(readFileSync2(join2(root, "package.json"), "utf8"));
|
|
368
|
+
const pm = pkg.packageManager?.split("@")[0];
|
|
369
|
+
if (pm === "pnpm" || pm === "npm" || pm === "yarn" || pm === "bun") return pm;
|
|
370
|
+
} catch {
|
|
371
|
+
}
|
|
372
|
+
return "npm";
|
|
373
|
+
};
|
|
374
|
+
var defaultChecksForTarget = (root, opts) => {
|
|
375
|
+
const pm = detectPackageManager(root);
|
|
376
|
+
if (/\.mdx?$/.test(opts.packagePath) || opts.packagePath.includes("/pillars/")) {
|
|
377
|
+
try {
|
|
378
|
+
const pkg = JSON.parse(readFileSync2(join2(root, "package.json"), "utf8"));
|
|
379
|
+
const scripts = pkg.scripts ?? {};
|
|
380
|
+
if (scripts["check:okf-type"]) return ["pnpm run check:okf-type"];
|
|
381
|
+
if (scripts["docs:bridge:gate"]) return ["pnpm run docs:bridge:gate"];
|
|
382
|
+
if (scripts.test) return [pm === "pnpm" ? "pnpm test" : "npm test"];
|
|
383
|
+
} catch {
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
const isWorkspace = existsSync2(join2(root, "pnpm-workspace.yaml")) || existsSync2(join2(root, "lerna.json")) || Boolean(
|
|
387
|
+
(() => {
|
|
388
|
+
try {
|
|
389
|
+
const pkg = JSON.parse(readFileSync2(join2(root, "package.json"), "utf8"));
|
|
390
|
+
return Boolean(pkg.workspaces);
|
|
391
|
+
} catch {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
})()
|
|
395
|
+
);
|
|
396
|
+
const filter = opts.packageName ?? (opts.packagePath.startsWith("packages/") || opts.packagePath.startsWith("apps/") ? opts.packageId : void 0);
|
|
397
|
+
if (pm === "pnpm") {
|
|
398
|
+
if (isWorkspace && filter) {
|
|
399
|
+
const base = [`pnpm --filter ${filter} test`];
|
|
400
|
+
if (opts.strict) base.push(`pnpm --filter ${filter} lint`);
|
|
401
|
+
return base;
|
|
402
|
+
}
|
|
403
|
+
return opts.strict ? ["pnpm test", "pnpm run lint"] : ["pnpm test"];
|
|
404
|
+
}
|
|
405
|
+
if (pm === "yarn") {
|
|
406
|
+
if (isWorkspace && filter) {
|
|
407
|
+
return opts.strict ? [`yarn workspace ${filter} test`, `yarn workspace ${filter} lint`] : [`yarn workspace ${filter} test`];
|
|
408
|
+
}
|
|
409
|
+
return opts.strict ? ["yarn test", "yarn lint"] : ["yarn test"];
|
|
410
|
+
}
|
|
411
|
+
if (pm === "bun") {
|
|
412
|
+
return opts.strict ? ["bun test", "bun run lint"] : ["bun test"];
|
|
413
|
+
}
|
|
414
|
+
if (isWorkspace && filter) {
|
|
415
|
+
return opts.strict ? [`npm test -w ${filter}`, `npm run lint -w ${filter}`] : [`npm test -w ${filter}`];
|
|
416
|
+
}
|
|
417
|
+
return opts.strict ? ["npm test", "npm run lint"] : ["npm test"];
|
|
418
|
+
};
|
|
419
|
+
|
|
353
420
|
// src/index-builder/scan-corpus.ts
|
|
354
|
-
import { readFileSync as
|
|
355
|
-
import { join as
|
|
421
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
422
|
+
import { join as join4 } from "path";
|
|
356
423
|
|
|
357
424
|
// src/lib/markdown.ts
|
|
358
425
|
var parseFrontmatter = (markdown) => {
|
|
@@ -402,7 +469,7 @@ var firstHeading = (markdown) => {
|
|
|
402
469
|
}
|
|
403
470
|
return void 0;
|
|
404
471
|
};
|
|
405
|
-
var firstParagraph = (markdown) => {
|
|
472
|
+
var firstParagraph = (markdown, maxLen = 400) => {
|
|
406
473
|
const { body } = parseFrontmatter(markdown);
|
|
407
474
|
const lines = body.split("\n");
|
|
408
475
|
const buf = [];
|
|
@@ -414,11 +481,27 @@ var firstParagraph = (markdown) => {
|
|
|
414
481
|
}
|
|
415
482
|
if (t.startsWith("#")) continue;
|
|
416
483
|
if (t.startsWith("---")) continue;
|
|
484
|
+
if (t.startsWith("```")) break;
|
|
485
|
+
if (t.startsWith("|") || t.startsWith("- [") || t.startsWith("* [")) {
|
|
486
|
+
if (buf.length) break;
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
417
489
|
buf.push(t);
|
|
418
|
-
if (buf.join(" ").length
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
|
|
490
|
+
if (buf.join(" ").length >= maxLen) break;
|
|
491
|
+
}
|
|
492
|
+
let text = buf.join(" ").replace(/\s+/g, " ").trim();
|
|
493
|
+
if (!text) return void 0;
|
|
494
|
+
if (text.length <= maxLen) return text;
|
|
495
|
+
const sliced = text.slice(0, maxLen);
|
|
496
|
+
const sentenceEnd = Math.max(sliced.lastIndexOf(". "), sliced.lastIndexOf("! "), sliced.lastIndexOf("? "));
|
|
497
|
+
if (sentenceEnd > maxLen * 0.4) return sliced.slice(0, sentenceEnd + 1).trim();
|
|
498
|
+
const wordEnd = sliced.lastIndexOf(" ");
|
|
499
|
+
return (wordEnd > 0 ? sliced.slice(0, wordEnd) : sliced).trim();
|
|
500
|
+
};
|
|
501
|
+
var extractSearchBody = (markdown, maxLen = 6e3) => {
|
|
502
|
+
const { body } = parseFrontmatter(markdown);
|
|
503
|
+
const text = body.replace(/```[\s\S]*?```/g, " ").replace(/!\[[^\]]*\]\([^)]+\)/g, " ").replace(/\[[^\]]*\]\([^)]+\)/g, " ").replace(/^#+\s+/gm, "").replace(/[|>*_`#]/g, " ").replace(/\s+/g, " ").trim();
|
|
504
|
+
return text.length > maxLen ? text.slice(0, maxLen) : text;
|
|
422
505
|
};
|
|
423
506
|
var slugFromPath = (relPath) => {
|
|
424
507
|
const base = relPath.replace(/\.mdx?$/, "");
|
|
@@ -428,7 +511,7 @@ var slugFromPath = (relPath) => {
|
|
|
428
511
|
|
|
429
512
|
// src/lib/walk.ts
|
|
430
513
|
import { readdirSync, statSync } from "fs";
|
|
431
|
-
import { join as
|
|
514
|
+
import { join as join3 } from "path";
|
|
432
515
|
var DEFAULT_SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "coverage", ".doc-bridge"]);
|
|
433
516
|
var walkFiles = (root, opts) => {
|
|
434
517
|
const extensions = opts?.extensions ?? [".md"];
|
|
@@ -442,7 +525,7 @@ var walkFiles = (root, opts) => {
|
|
|
442
525
|
return;
|
|
443
526
|
}
|
|
444
527
|
for (const name of entries) {
|
|
445
|
-
const abs =
|
|
528
|
+
const abs = join3(dir, name);
|
|
446
529
|
let st;
|
|
447
530
|
try {
|
|
448
531
|
st = statSync(abs);
|
|
@@ -466,17 +549,19 @@ var walkFiles = (root, opts) => {
|
|
|
466
549
|
|
|
467
550
|
// src/index-builder/scan-corpus.ts
|
|
468
551
|
var scanAgentCorpus = (root, config) => {
|
|
469
|
-
const agentRoot =
|
|
552
|
+
const agentRoot = join4(root, config.corpus.agent.root);
|
|
470
553
|
const files = walkFiles(agentRoot, { extensions: [".md", ".mdx"] });
|
|
471
554
|
const corpusRelRoot = toPosix(config.corpus.agent.root);
|
|
472
555
|
return files.map((abs) => {
|
|
473
556
|
const relToCorpus = toPosix(abs.replace(`${toPosix(agentRoot)}/`, ""));
|
|
474
557
|
const relPath = `${corpusRelRoot}/${relToCorpus}`;
|
|
475
|
-
const raw =
|
|
558
|
+
const raw = readFileSync3(abs, "utf8");
|
|
476
559
|
const { data: frontmatter } = parseFrontmatter(raw);
|
|
477
560
|
const id = frontmatterString(frontmatter, "id") ?? frontmatterString(frontmatter, "package") ?? slugFromPath(relToCorpus);
|
|
478
561
|
const title = firstHeading(raw) ?? id;
|
|
479
|
-
const
|
|
562
|
+
const purpose = frontmatterString(frontmatter, "purpose");
|
|
563
|
+
const description = purpose ?? firstParagraph(raw, 400);
|
|
564
|
+
const body = extractSearchBody(raw);
|
|
480
565
|
return {
|
|
481
566
|
id,
|
|
482
567
|
type: "agent-doc",
|
|
@@ -485,21 +570,35 @@ var scanAgentCorpus = (root, config) => {
|
|
|
485
570
|
absPath: abs,
|
|
486
571
|
relPath,
|
|
487
572
|
frontmatter,
|
|
488
|
-
...description ? { description } : {}
|
|
573
|
+
...description ? { description } : {},
|
|
574
|
+
...body ? { body } : {}
|
|
489
575
|
};
|
|
490
576
|
});
|
|
491
577
|
};
|
|
492
578
|
var guessAgentDocForPackage = (corpus, packageId) => {
|
|
493
|
-
const
|
|
494
|
-
(doc) => frontmatterString(doc.frontmatter, "package") === packageId
|
|
495
|
-
|
|
496
|
-
|
|
579
|
+
const candidates = [
|
|
580
|
+
(doc) => frontmatterString(doc.frontmatter, "package") === packageId,
|
|
581
|
+
(doc) => doc.id === packageId,
|
|
582
|
+
(doc) => doc.relPath.endsWith(`/packages/${packageId}.md`),
|
|
583
|
+
(doc) => doc.relPath.endsWith(`/packages/${packageId}.mdx`),
|
|
584
|
+
(doc) => doc.relPath.endsWith(`/packages/${packageId}/index.md`),
|
|
585
|
+
(doc) => doc.relPath.endsWith(`/packages/${packageId}/index.mdx`),
|
|
586
|
+
(doc) => doc.relPath.endsWith(`/${packageId}.md`),
|
|
587
|
+
(doc) => doc.relPath.endsWith(`/${packageId}.mdx`),
|
|
588
|
+
(doc) => doc.relPath.includes(`/packages/${packageId}/`)
|
|
589
|
+
];
|
|
590
|
+
for (const match of candidates) {
|
|
591
|
+
const hit = corpus.find(match);
|
|
592
|
+
if (hit) return hit.path;
|
|
593
|
+
}
|
|
594
|
+
return void 0;
|
|
497
595
|
};
|
|
498
596
|
var ownershipFromFrontmatter = (corpus) => {
|
|
499
597
|
const out = [];
|
|
500
598
|
for (const doc of corpus) {
|
|
501
|
-
const
|
|
502
|
-
const
|
|
599
|
+
const type = frontmatterString(doc.frontmatter, "type");
|
|
600
|
+
const id = frontmatterString(doc.frontmatter, "package") ?? (type === "package" || type === "module" || type === "pattern" ? frontmatterString(doc.frontmatter, "id") ?? doc.id : void 0);
|
|
601
|
+
const path = frontmatterString(doc.frontmatter, "editRoot") ?? frontmatterString(doc.frontmatter, "path") ?? (type === "package" || type === "module" ? `packages/${id}` : void 0);
|
|
503
602
|
if (!id || !path) continue;
|
|
504
603
|
const purpose = frontmatterString(doc.frontmatter, "purpose") ?? doc.description;
|
|
505
604
|
const checks = frontmatterStringList(doc.frontmatter, "checks");
|
|
@@ -515,13 +614,55 @@ var ownershipFromFrontmatter = (corpus) => {
|
|
|
515
614
|
}
|
|
516
615
|
return out;
|
|
517
616
|
};
|
|
617
|
+
var ownershipFromCorpus = (corpus) => {
|
|
618
|
+
const out = [];
|
|
619
|
+
const seen = /* @__PURE__ */ new Set();
|
|
620
|
+
for (const doc of corpus) {
|
|
621
|
+
if (frontmatterString(doc.frontmatter, "package") && frontmatterString(doc.frontmatter, "editRoot")) {
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
let id;
|
|
625
|
+
let path;
|
|
626
|
+
let purpose = frontmatterString(doc.frontmatter, "purpose") ?? doc.description;
|
|
627
|
+
const packagesFile = /(?:^|\/)packages\/([^/]+)\.(?:md|mdx)$/.exec(doc.relPath);
|
|
628
|
+
const packagesIndex = /(?:^|\/)packages\/([^/]+)\/index\.(?:md|mdx)$/.exec(doc.relPath);
|
|
629
|
+
const registryReadme = /(?:^|\/)registry\/([^/]+)\/README\.(?:md|mdx)$/i.exec(doc.relPath);
|
|
630
|
+
const patternFile = /(?:^|\/)pillars\/[^/]+\/([^/]+(?:-pattern)?)\.(?:md|mdx)$/.exec(doc.relPath);
|
|
631
|
+
const topLevelPkg = /(?:^|\/)for-agents\/([^/]+)\.(?:md|mdx)$/.exec(doc.relPath);
|
|
632
|
+
if (packagesFile?.[1] && packagesFile[1] !== "index") {
|
|
633
|
+
id = packagesFile[1];
|
|
634
|
+
path = `packages/${id}`;
|
|
635
|
+
} else if (packagesIndex?.[1]) {
|
|
636
|
+
id = packagesIndex[1];
|
|
637
|
+
path = `packages/${id}`;
|
|
638
|
+
} else if (registryReadme?.[1]) {
|
|
639
|
+
id = registryReadme[1];
|
|
640
|
+
path = `registry/${id}`;
|
|
641
|
+
} else if (patternFile?.[1] && patternFile[1] !== "index" && patternFile[1] !== "universal") {
|
|
642
|
+
id = patternFile[1];
|
|
643
|
+
path = doc.path;
|
|
644
|
+
purpose = purpose ?? `Playbook pattern: ${id}`;
|
|
645
|
+
} else if (topLevelPkg?.[1] && topLevelPkg[1] !== "index" && topLevelPkg[1] !== "INDEX") {
|
|
646
|
+
id = topLevelPkg[1];
|
|
647
|
+
path = `packages/${id}`;
|
|
648
|
+
}
|
|
649
|
+
if (!id || !path || seen.has(id)) continue;
|
|
650
|
+
seen.add(id);
|
|
651
|
+
const humanDoc = frontmatterString(doc.frontmatter, "humanDoc");
|
|
652
|
+
const checks = frontmatterStringList(doc.frontmatter, "checks");
|
|
653
|
+
out.push({
|
|
654
|
+
id,
|
|
655
|
+
path,
|
|
656
|
+
agentDoc: doc.path,
|
|
657
|
+
...purpose ? { purpose } : {},
|
|
658
|
+
...checks ? { checks } : {},
|
|
659
|
+
...humanDoc ? { humanDoc } : {}
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
return out;
|
|
663
|
+
};
|
|
518
664
|
|
|
519
665
|
// src/index-builder/build-handoffs.ts
|
|
520
|
-
var defaultChecks = (config) => {
|
|
521
|
-
const preset = config.gates?.preset ?? "minimal";
|
|
522
|
-
if (preset === "strict" || preset === "standard") return ["npm test", "npm run lint"];
|
|
523
|
-
return ["npm test"];
|
|
524
|
-
};
|
|
525
666
|
var collectPackages = (config, discovered, corpus) => {
|
|
526
667
|
const byId = /* @__PURE__ */ new Map();
|
|
527
668
|
for (const [id, entry] of Object.entries(config.routing?.options?.ownership ?? {})) {
|
|
@@ -539,7 +680,11 @@ var collectPackages = (config, discovered, corpus) => {
|
|
|
539
680
|
...pkg.name ? { name: pkg.name } : existing.name ? { name: existing.name } : {}
|
|
540
681
|
});
|
|
541
682
|
}
|
|
542
|
-
|
|
683
|
+
const seeds = [
|
|
684
|
+
...ownershipFromFrontmatter(corpus),
|
|
685
|
+
...config.routing?.options?.ownershipFromCorpus === false ? [] : ownershipFromCorpus(corpus)
|
|
686
|
+
];
|
|
687
|
+
for (const seed of seeds) {
|
|
543
688
|
const existing = byId.get(seed.id);
|
|
544
689
|
if (!existing) {
|
|
545
690
|
byId.set(seed.id, { id: seed.id, path: seed.path });
|
|
@@ -551,22 +696,59 @@ var collectPackages = (config, discovered, corpus) => {
|
|
|
551
696
|
}
|
|
552
697
|
return [...byId.values()].sort((a, b) => a.id.localeCompare(b.id));
|
|
553
698
|
};
|
|
554
|
-
var
|
|
699
|
+
var resolveHumanDoc = (packageId, override, fmHuman, humanDocs = {}) => {
|
|
700
|
+
if (override) return override;
|
|
701
|
+
if (fmHuman) return fmHuman;
|
|
702
|
+
if (humanDocs[packageId]) return humanDocs[packageId];
|
|
703
|
+
const aliases = [
|
|
704
|
+
packageId,
|
|
705
|
+
packageId.replace(/^@[^/]+\//, ""),
|
|
706
|
+
packageId.replace(/^os-/, ""),
|
|
707
|
+
packageId.replace(/-pattern$/, ""),
|
|
708
|
+
`packages/${packageId}`,
|
|
709
|
+
`reference/packages/${packageId}`,
|
|
710
|
+
`packages/${packageId}/index`
|
|
711
|
+
];
|
|
712
|
+
for (const alias of aliases) {
|
|
713
|
+
if (humanDocs[alias]) return humanDocs[alias];
|
|
714
|
+
}
|
|
715
|
+
for (const [key, url] of Object.entries(humanDocs)) {
|
|
716
|
+
if (key === packageId || key.endsWith(`/${packageId}`) || key.endsWith(`/${packageId}/index`) || key.endsWith(`-${packageId}`)) {
|
|
717
|
+
return url;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return void 0;
|
|
721
|
+
};
|
|
722
|
+
var buildLookup = (config, packages, corpus, indexOutFile, humanDocs = {}, root = process.cwd()) => {
|
|
555
723
|
const ownership = {};
|
|
556
724
|
const handoffs = {};
|
|
557
|
-
const
|
|
558
|
-
const fmSeeds = new Map(
|
|
725
|
+
const strict = (config.gates?.preset ?? "minimal") !== "minimal";
|
|
726
|
+
const fmSeeds = new Map(
|
|
727
|
+
[...ownershipFromFrontmatter(corpus), ...ownershipFromCorpus(corpus)].map((seed) => [
|
|
728
|
+
seed.id,
|
|
729
|
+
seed
|
|
730
|
+
])
|
|
731
|
+
);
|
|
559
732
|
for (const pkg of packages) {
|
|
560
733
|
const override = config.routing?.options?.ownership?.[pkg.id];
|
|
561
734
|
const fm = fmSeeds.get(pkg.id);
|
|
562
735
|
const agentDoc = override?.agentDoc ?? fm?.agentDoc ?? guessAgentDocForPackage(corpus, pkg.id) ?? config.corpus.agent.index;
|
|
563
736
|
const startHere = agentDoc ?? "";
|
|
564
737
|
const purpose = override?.purpose ?? fm?.purpose;
|
|
565
|
-
const
|
|
738
|
+
const path = override?.path ?? fm?.path ?? pkg.path;
|
|
739
|
+
const checks = [
|
|
740
|
+
...override?.checks ?? fm?.checks ?? defaultChecksForTarget(root, {
|
|
741
|
+
packageId: pkg.id,
|
|
742
|
+
packagePath: path,
|
|
743
|
+
...pkg.name ? { packageName: pkg.name } : {},
|
|
744
|
+
strict
|
|
745
|
+
})
|
|
746
|
+
];
|
|
747
|
+
const humanDoc = resolveHumanDoc(pkg.id, override?.humanDoc, fm?.humanDoc, humanDocs);
|
|
566
748
|
const record = {
|
|
567
749
|
id: pkg.id,
|
|
568
|
-
path
|
|
569
|
-
checks
|
|
750
|
+
path,
|
|
751
|
+
checks,
|
|
570
752
|
...override?.group ? { group: override.group } : {},
|
|
571
753
|
...override?.layer ? { layer: override.layer } : {},
|
|
572
754
|
...purpose ? { purpose } : {},
|
|
@@ -620,7 +802,7 @@ var buildLookup = (config, packages, corpus, indexOutFile, humanDocs = {}) => {
|
|
|
620
802
|
};
|
|
621
803
|
|
|
622
804
|
// src/version.ts
|
|
623
|
-
var PACKAGE_VERSION = "0.1.0-alpha.
|
|
805
|
+
var PACKAGE_VERSION = "0.1.0-alpha.3";
|
|
624
806
|
|
|
625
807
|
// src/index-builder/capabilities.ts
|
|
626
808
|
var renderCapabilitiesJson = (config, index, paths) => {
|
|
@@ -689,13 +871,13 @@ ${lines.join("\n")}
|
|
|
689
871
|
};
|
|
690
872
|
|
|
691
873
|
// src/index-builder/human-adapters/docusaurus.ts
|
|
692
|
-
import { existsSync as
|
|
693
|
-
import { join as
|
|
874
|
+
import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
|
|
875
|
+
import { join as join6 } from "path";
|
|
694
876
|
import vm2 from "vm";
|
|
695
877
|
|
|
696
878
|
// src/index-builder/human-adapters/core.ts
|
|
697
|
-
import { readFileSync as
|
|
698
|
-
import { join as
|
|
879
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
880
|
+
import { join as join5 } from "path";
|
|
699
881
|
var optionString = (options, keys) => {
|
|
700
882
|
for (const key of keys) {
|
|
701
883
|
const value = options?.[key];
|
|
@@ -726,10 +908,10 @@ var humanUrl = (slug, urlPrefix) => {
|
|
|
726
908
|
};
|
|
727
909
|
var scanMarkdownDocs = (root, humanRoot, options) => {
|
|
728
910
|
const out = [];
|
|
729
|
-
const absRoot =
|
|
911
|
+
const absRoot = join5(root, humanRoot);
|
|
730
912
|
for (const abs of walkFiles(absRoot, { extensions: [".md", ".mdx"] })) {
|
|
731
913
|
const relToHumanRoot = toPosix(abs.replace(`${toPosix(absRoot)}/`, ""));
|
|
732
|
-
const raw =
|
|
914
|
+
const raw = readFileSync4(abs, "utf8");
|
|
733
915
|
if (options?.includeRelPath && !options.includeRelPath(relToHumanRoot, raw)) continue;
|
|
734
916
|
out.push({
|
|
735
917
|
id: options?.idForDoc?.(relToHumanRoot, raw) ?? docId(relToHumanRoot, raw),
|
|
@@ -768,8 +950,8 @@ var docusaurusRecordId = (relPath, raw) => {
|
|
|
768
950
|
return frontmatter.package ?? frontmatter.module ?? docusaurusSidebarId(relPath, raw);
|
|
769
951
|
};
|
|
770
952
|
var sidebarsValue = (file) => {
|
|
771
|
-
if (!
|
|
772
|
-
const raw =
|
|
953
|
+
if (!existsSync3(file)) return void 0;
|
|
954
|
+
const raw = readFileSync5(file, "utf8").replace(/import\s+type\s+[\s\S]*?;?\n/g, "").replace(/:\s*[A-Za-z0-9_.$<>{}\[\],\s]+(?=\s*=)/g, "").replace(/\s+satisfies\s+[A-Za-z0-9_.$<>{}\[\],\s]+(?=\s*(?:;|\n|$))/g, "").replace(/export\s+default/, "module.exports =");
|
|
773
955
|
const sandbox = { module: { exports: {} }, exports: {} };
|
|
774
956
|
vm2.runInNewContext(raw, sandbox, { timeout: 250 });
|
|
775
957
|
return sandbox.module.exports;
|
|
@@ -799,7 +981,7 @@ var visitSidebar = (value, filter) => {
|
|
|
799
981
|
};
|
|
800
982
|
var readSidebars = (root, sidebarsFile) => {
|
|
801
983
|
if (!sidebarsFile) return { enabled: false, ids: /* @__PURE__ */ new Set(), autogenDirs: [] };
|
|
802
|
-
const value = sidebarsValue(
|
|
984
|
+
const value = sidebarsValue(join6(root, sidebarsFile));
|
|
803
985
|
const filter = { ids: /* @__PURE__ */ new Set(), autogenDirs: [] };
|
|
804
986
|
visitSidebar(value, filter);
|
|
805
987
|
return { enabled: true, ...filter };
|
|
@@ -828,13 +1010,13 @@ var docusaurusAdapter = {
|
|
|
828
1010
|
};
|
|
829
1011
|
|
|
830
1012
|
// src/index-builder/human-adapters/fumadocs.ts
|
|
831
|
-
import { existsSync as
|
|
832
|
-
import { join as
|
|
1013
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
|
|
1014
|
+
import { join as join7 } from "path";
|
|
833
1015
|
var readMetaPages = (dir) => {
|
|
834
|
-
const file =
|
|
835
|
-
if (!
|
|
1016
|
+
const file = join7(dir, "meta.json");
|
|
1017
|
+
if (!existsSync4(file)) return void 0;
|
|
836
1018
|
try {
|
|
837
|
-
const meta = JSON.parse(
|
|
1019
|
+
const meta = JSON.parse(readFileSync6(file, "utf8"));
|
|
838
1020
|
return Array.isArray(meta.pages) ? meta.pages.filter((page) => typeof page === "string") : void 0;
|
|
839
1021
|
} catch {
|
|
840
1022
|
return void 0;
|
|
@@ -849,7 +1031,7 @@ var isListedByMeta = (contentRoot, relPath) => {
|
|
|
849
1031
|
if (isDotFile(relPath)) return false;
|
|
850
1032
|
const parts = relPath.split("/");
|
|
851
1033
|
for (let i = 0; i < parts.length; i += 1) {
|
|
852
|
-
const dir =
|
|
1034
|
+
const dir = join7(contentRoot, ...parts.slice(0, i));
|
|
853
1035
|
const pages = readMetaPages(dir);
|
|
854
1036
|
if (!pages?.length || pages.includes("...")) continue;
|
|
855
1037
|
const key = pageKey(parts[i] ?? "");
|
|
@@ -862,9 +1044,16 @@ var fumadocsAdapter = {
|
|
|
862
1044
|
scan: ({ root, config }) => {
|
|
863
1045
|
const contentDir = optionString(config.options, ["contentDir", "root"]);
|
|
864
1046
|
if (!contentDir) return [];
|
|
865
|
-
const contentRoot =
|
|
1047
|
+
const contentRoot = join7(root, contentDir);
|
|
1048
|
+
const excludePrefixes = Array.isArray(config.options?.excludePrefixes) ? config.options.excludePrefixes.filter((v) => typeof v === "string") : typeof config.options?.excludePrefix === "string" ? [config.options.excludePrefix] : [];
|
|
1049
|
+
if (!excludePrefixes.includes("for-agents")) excludePrefixes.push("for-agents");
|
|
866
1050
|
return scanMarkdownDocs(root, contentDir, {
|
|
867
|
-
includeRelPath: (relPath) =>
|
|
1051
|
+
includeRelPath: (relPath) => {
|
|
1052
|
+
if (excludePrefixes.some((prefix) => relPath === prefix || relPath.startsWith(`${prefix}/`))) {
|
|
1053
|
+
return false;
|
|
1054
|
+
}
|
|
1055
|
+
return isListedByMeta(contentRoot, relPath);
|
|
1056
|
+
},
|
|
868
1057
|
urlPrefix: config.options?.urlPrefix,
|
|
869
1058
|
stripGroups: true
|
|
870
1059
|
});
|
|
@@ -875,7 +1064,7 @@ var fumadocsAdapter = {
|
|
|
875
1064
|
var plainMarkdownAdapter = {
|
|
876
1065
|
plugin: "plain-markdown",
|
|
877
1066
|
scan: ({ root, config }) => {
|
|
878
|
-
const humanRoot = optionString(config.options, ["root"]) ?? "docs";
|
|
1067
|
+
const humanRoot = optionString(config.options, ["contentDir", "root", "docsDir"]) ?? "docs";
|
|
879
1068
|
return scanMarkdownDocs(root, humanRoot, { urlPrefix: config.options?.urlPrefix });
|
|
880
1069
|
}
|
|
881
1070
|
};
|
|
@@ -894,10 +1083,14 @@ var humanConfigs = (config) => {
|
|
|
894
1083
|
var scanHumanDocRecords = (root, config) => {
|
|
895
1084
|
const out = [];
|
|
896
1085
|
const seen = /* @__PURE__ */ new Set();
|
|
1086
|
+
const agentRoot = config.corpus.agent.root.replace(/\/$/, "");
|
|
897
1087
|
for (const human of humanConfigs(config)) {
|
|
898
1088
|
const adapter = ADAPTERS.find((candidate) => candidate.plugin === human.plugin);
|
|
899
1089
|
if (!adapter) continue;
|
|
900
1090
|
for (const record of adapter.scan({ root, config: human })) {
|
|
1091
|
+
if (record.path === agentRoot || record.path.startsWith(`${agentRoot}/`) || record.path.includes("/for-agents/") || record.path.endsWith("/for-agents")) {
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
901
1094
|
if (seen.has(record.id)) continue;
|
|
902
1095
|
seen.add(record.id);
|
|
903
1096
|
out.push(record);
|
|
@@ -908,26 +1101,26 @@ var scanHumanDocRecords = (root, config) => {
|
|
|
908
1101
|
var scanHumanDocs = (root, config) => Object.fromEntries(scanHumanDocRecords(root, config).map((doc) => [doc.id, doc.url]));
|
|
909
1102
|
|
|
910
1103
|
// src/index-builder/plugins/pnpm-monorepo.ts
|
|
911
|
-
import { existsSync as
|
|
912
|
-
import { basename as basename2, join as
|
|
1104
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
1105
|
+
import { basename as basename2, join as join9 } from "path";
|
|
913
1106
|
|
|
914
1107
|
// src/lib/glob-expand.ts
|
|
915
|
-
import { existsSync as
|
|
916
|
-
import { join as
|
|
1108
|
+
import { existsSync as existsSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
1109
|
+
import { join as join8 } from "path";
|
|
917
1110
|
var expandWorkspaceGlobs = (root, patterns) => {
|
|
918
1111
|
const dirs = /* @__PURE__ */ new Set();
|
|
919
1112
|
for (const pattern of patterns) {
|
|
920
1113
|
const normalized = toPosix(pattern).replace(/\/$/, "");
|
|
921
1114
|
if (!normalized.includes("*")) {
|
|
922
|
-
const abs =
|
|
923
|
-
if (
|
|
1115
|
+
const abs = join8(root, normalized);
|
|
1116
|
+
if (existsSync5(abs)) dirs.add(toPosix(abs));
|
|
924
1117
|
continue;
|
|
925
1118
|
}
|
|
926
1119
|
const star = normalized.indexOf("*");
|
|
927
|
-
const base =
|
|
928
|
-
if (!
|
|
1120
|
+
const base = join8(root, normalized.slice(0, star).replace(/\/$/, ""));
|
|
1121
|
+
if (!existsSync5(base)) continue;
|
|
929
1122
|
for (const name of readdirSync2(base)) {
|
|
930
|
-
const abs =
|
|
1123
|
+
const abs = join8(base, name);
|
|
931
1124
|
try {
|
|
932
1125
|
if (statSync2(abs).isDirectory()) dirs.add(toPosix(abs));
|
|
933
1126
|
} catch {
|
|
@@ -959,10 +1152,10 @@ var parsePnpmWorkspace = (yaml) => {
|
|
|
959
1152
|
return patterns;
|
|
960
1153
|
};
|
|
961
1154
|
var readPackageJson = (dir) => {
|
|
962
|
-
const file =
|
|
963
|
-
if (!
|
|
1155
|
+
const file = join9(dir, "package.json");
|
|
1156
|
+
if (!existsSync6(file)) return null;
|
|
964
1157
|
try {
|
|
965
|
-
return JSON.parse(
|
|
1158
|
+
return JSON.parse(readFileSync7(file, "utf8"));
|
|
966
1159
|
} catch {
|
|
967
1160
|
return null;
|
|
968
1161
|
}
|
|
@@ -971,9 +1164,9 @@ var discoverPnpmPackages = (root, config) => {
|
|
|
971
1164
|
const explicit = config.routing?.options?.packages;
|
|
972
1165
|
let patterns = explicit;
|
|
973
1166
|
if (!patterns?.length) {
|
|
974
|
-
const workspaceFile =
|
|
975
|
-
if (
|
|
976
|
-
patterns = parsePnpmWorkspace(
|
|
1167
|
+
const workspaceFile = join9(root, "pnpm-workspace.yaml");
|
|
1168
|
+
if (existsSync6(workspaceFile)) {
|
|
1169
|
+
patterns = parsePnpmWorkspace(readFileSync7(workspaceFile, "utf8"));
|
|
977
1170
|
}
|
|
978
1171
|
}
|
|
979
1172
|
if (!patterns?.length) return [];
|
|
@@ -994,7 +1187,7 @@ var discoverPnpmPackages = (root, config) => {
|
|
|
994
1187
|
var projectName = (root, config) => {
|
|
995
1188
|
if (config.project?.name) return config.project.name;
|
|
996
1189
|
try {
|
|
997
|
-
const pkg = JSON.parse(
|
|
1190
|
+
const pkg = JSON.parse(readFileSync8(join10(root, "package.json"), "utf8"));
|
|
998
1191
|
if (pkg.name) return pkg.name;
|
|
999
1192
|
} catch {
|
|
1000
1193
|
}
|
|
@@ -1002,7 +1195,7 @@ var projectName = (root, config) => {
|
|
|
1002
1195
|
};
|
|
1003
1196
|
var existingGeneratedAt = (indexPath, contentHash) => {
|
|
1004
1197
|
try {
|
|
1005
|
-
const index = JSON.parse(
|
|
1198
|
+
const index = JSON.parse(readFileSync8(indexPath, "utf8"));
|
|
1006
1199
|
return index.contentHash === contentHash && typeof index.generatedAt === "string" ? index.generatedAt : void 0;
|
|
1007
1200
|
} catch {
|
|
1008
1201
|
return void 0;
|
|
@@ -1013,14 +1206,14 @@ var buildDocBridgeIndex = (opts) => {
|
|
|
1013
1206
|
const config = opts.config;
|
|
1014
1207
|
const write = opts.write ?? true;
|
|
1015
1208
|
const outFile = config.index?.outFile ?? ".doc-bridge/index.json";
|
|
1016
|
-
const indexPath =
|
|
1209
|
+
const indexPath = join10(root, outFile);
|
|
1017
1210
|
const corpus = scanAgentCorpus(root, config);
|
|
1018
1211
|
const knowledge = corpus.map(({ absPath: _a, relPath: _r, frontmatter: _f, ...entry }) => entry);
|
|
1019
1212
|
const shouldDiscover = config.routing?.plugin === "pnpm-monorepo" || Boolean(config.routing?.options?.packages?.length) || config.routing?.plugin === "npm-workspaces" || config.routing?.plugin === "yarn-workspaces";
|
|
1020
1213
|
const discovered = shouldDiscover ? discoverPnpmPackages(root, config) : [];
|
|
1021
1214
|
const packages = collectPackages(config, discovered, corpus);
|
|
1022
1215
|
const humanDocs = scanHumanDocs(root, config);
|
|
1023
|
-
const { lookup, handoffs } = buildLookup(config, packages, corpus, outFile, humanDocs);
|
|
1216
|
+
const { lookup, handoffs } = buildLookup(config, packages, corpus, outFile, humanDocs, root);
|
|
1024
1217
|
const hashPayload = {
|
|
1025
1218
|
schemaVersion: 1,
|
|
1026
1219
|
knowledge,
|
|
@@ -1048,7 +1241,7 @@ var buildDocBridgeIndex = (opts) => {
|
|
|
1048
1241
|
if (config.index?.llmsTxt?.enabled !== false) {
|
|
1049
1242
|
const llmsOut = config.index?.llmsTxt?.outFile ?? "llms.txt";
|
|
1050
1243
|
llmsTxtRelPath = toPosix(llmsOut);
|
|
1051
|
-
llmsTxtPath =
|
|
1244
|
+
llmsTxtPath = join10(root, llmsOut);
|
|
1052
1245
|
if (write) {
|
|
1053
1246
|
writeFileSync(
|
|
1054
1247
|
llmsTxtPath,
|
|
@@ -1060,7 +1253,7 @@ var buildDocBridgeIndex = (opts) => {
|
|
|
1060
1253
|
let capabilitiesPath;
|
|
1061
1254
|
if (config.index?.capabilities?.enabled !== false) {
|
|
1062
1255
|
const capabilitiesOut = config.index?.capabilities?.outFile ?? ".doc-bridge/capabilities.json";
|
|
1063
|
-
capabilitiesPath =
|
|
1256
|
+
capabilitiesPath = join10(root, capabilitiesOut);
|
|
1064
1257
|
if (write) {
|
|
1065
1258
|
mkdirSync(dirname3(capabilitiesPath), { recursive: true });
|
|
1066
1259
|
writeFileSync(
|
|
@@ -1082,23 +1275,62 @@ var buildDocBridgeIndex = (opts) => {
|
|
|
1082
1275
|
};
|
|
1083
1276
|
|
|
1084
1277
|
// src/federation/llms.ts
|
|
1085
|
-
import { existsSync as
|
|
1278
|
+
import { existsSync as existsSync7, readFileSync as readFileSync9 } from "fs";
|
|
1086
1279
|
import { resolve as resolve3 } from "path";
|
|
1087
1280
|
|
|
1088
1281
|
// src/query/search.ts
|
|
1089
|
-
var tokenize = (value) => value.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 2);
|
|
1282
|
+
var tokenize = (value) => value.toLowerCase().split(/[^a-z0-9@/_-]+/).filter((t) => t.length >= 2);
|
|
1283
|
+
var PACKAGE_INTENT = /\b(package|module|pkg|edit|change|where|owns?|ownership|handoff|start)\b/i;
|
|
1284
|
+
var scoreHay = (tokens, hay, weight = 1) => {
|
|
1285
|
+
let score = 0;
|
|
1286
|
+
for (const token of tokens) {
|
|
1287
|
+
if (!hay.includes(token)) continue;
|
|
1288
|
+
score += token.length * weight;
|
|
1289
|
+
if (new RegExp(`(?:^|[^a-z0-9])${token}(?:[^a-z0-9]|$)`).test(hay)) {
|
|
1290
|
+
score += token.length;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
return score;
|
|
1294
|
+
};
|
|
1295
|
+
var identityBoost = (id, path, tokens, term) => {
|
|
1296
|
+
const idLower = id.toLowerCase();
|
|
1297
|
+
const termLower = term.toLowerCase().trim();
|
|
1298
|
+
const base = path.split("/").pop()?.replace(/\.mdx?$/i, "").toLowerCase() ?? "";
|
|
1299
|
+
let boost = 0;
|
|
1300
|
+
if (idLower === termLower || base === termLower) boost += 200;
|
|
1301
|
+
if (tokens.length === 1 && (idLower === tokens[0] || base === tokens[0])) boost += 200;
|
|
1302
|
+
for (const token of tokens) {
|
|
1303
|
+
if (idLower === token) boost += 120;
|
|
1304
|
+
else if (idLower.startsWith(`${token}-`) || idLower.endsWith(`-${token}`)) boost += 40;
|
|
1305
|
+
else if (idLower.includes(token) && idLower.length <= token.length + 4) boost += 30;
|
|
1306
|
+
if (base === token) boost += 100;
|
|
1307
|
+
}
|
|
1308
|
+
if (tokens.includes(idLower)) boost += Math.max(0, 40 - idLower.length);
|
|
1309
|
+
return boost;
|
|
1310
|
+
};
|
|
1311
|
+
var preferOwnership = (term) => PACKAGE_INTENT.test(term) || /^(where|how).*(edit|change|package|module)/i.test(term);
|
|
1090
1312
|
var searchIndex = (index, term, limit = 20) => {
|
|
1091
1313
|
const tokens = tokenize(term);
|
|
1092
1314
|
if (!tokens.length) return [];
|
|
1093
|
-
const
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1315
|
+
const wantOwnership = preferOwnership(term);
|
|
1316
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
1317
|
+
const consider = (match) => {
|
|
1318
|
+
const key = match.path;
|
|
1319
|
+
const existing = byPath.get(key);
|
|
1320
|
+
if (!existing) {
|
|
1321
|
+
byPath.set(key, match);
|
|
1322
|
+
return;
|
|
1099
1323
|
}
|
|
1324
|
+
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;
|
|
1325
|
+
if (prefer) byPath.set(key, match);
|
|
1326
|
+
};
|
|
1327
|
+
for (const entry of index.knowledge) {
|
|
1328
|
+
const body = entry.body ?? "";
|
|
1329
|
+
const hay = `${entry.id} ${entry.title} ${entry.description ?? ""} ${entry.path} ${body}`.toLowerCase();
|
|
1330
|
+
let score = scoreHay(tokens, hay, 1);
|
|
1331
|
+
score += identityBoost(entry.id, entry.path, tokens, term);
|
|
1100
1332
|
if (score > 0) {
|
|
1101
|
-
|
|
1333
|
+
consider({
|
|
1102
1334
|
type: "knowledge",
|
|
1103
1335
|
id: entry.id,
|
|
1104
1336
|
path: entry.path,
|
|
@@ -1108,22 +1340,31 @@ var searchIndex = (index, term, limit = 20) => {
|
|
|
1108
1340
|
}
|
|
1109
1341
|
}
|
|
1110
1342
|
for (const [id, owner] of Object.entries(index.lookup?.ownership ?? {})) {
|
|
1111
|
-
const
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1343
|
+
const path = owner.agentDoc ?? owner.path;
|
|
1344
|
+
const hay = `${id} ${owner.path} ${owner.purpose ?? ""} ${owner.group ?? ""} ${owner.agentDoc ?? ""} ${owner.humanDoc ?? ""}`.toLowerCase();
|
|
1345
|
+
let score = scoreHay(tokens, hay, 2);
|
|
1346
|
+
score += identityBoost(id, path, tokens, term);
|
|
1347
|
+
if (wantOwnership) score += 25;
|
|
1348
|
+
score += 15;
|
|
1116
1349
|
if (score > 0) {
|
|
1117
|
-
|
|
1350
|
+
consider({
|
|
1118
1351
|
type: "ownership",
|
|
1119
1352
|
id,
|
|
1120
|
-
path
|
|
1353
|
+
path,
|
|
1121
1354
|
...owner.purpose ? { summary: owner.purpose } : {},
|
|
1122
1355
|
score
|
|
1123
1356
|
});
|
|
1124
1357
|
}
|
|
1125
1358
|
}
|
|
1126
|
-
return
|
|
1359
|
+
return [...byPath.values()].sort((a, b) => {
|
|
1360
|
+
if (b.score !== a.score) return b.score - a.score;
|
|
1361
|
+
const aExact = tokens.includes(a.id.toLowerCase()) ? 1 : 0;
|
|
1362
|
+
const bExact = tokens.includes(b.id.toLowerCase()) ? 1 : 0;
|
|
1363
|
+
if (bExact !== aExact) return bExact - aExact;
|
|
1364
|
+
if (a.type === "ownership" && b.type !== "ownership") return -1;
|
|
1365
|
+
if (b.type === "ownership" && a.type !== "ownership") return 1;
|
|
1366
|
+
return a.id.localeCompare(b.id);
|
|
1367
|
+
}).slice(0, limit);
|
|
1127
1368
|
};
|
|
1128
1369
|
|
|
1129
1370
|
// src/retriever/doc-bridge-retriever.ts
|
|
@@ -1162,10 +1403,14 @@ var defaultFetchText = async (url) => {
|
|
|
1162
1403
|
return res.text();
|
|
1163
1404
|
};
|
|
1164
1405
|
var sourceText = async (root, source, fetchText) => {
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1406
|
+
try {
|
|
1407
|
+
if (/^https?:\/\//.test(source)) return await fetchText(source);
|
|
1408
|
+
const path = resolve3(root, source);
|
|
1409
|
+
if (!existsSync7(path)) return null;
|
|
1410
|
+
return readFileSync9(path, "utf8");
|
|
1411
|
+
} catch {
|
|
1412
|
+
return null;
|
|
1413
|
+
}
|
|
1169
1414
|
};
|
|
1170
1415
|
var sameOrigin = (base, target) => {
|
|
1171
1416
|
if (!/^https?:\/\//.test(base) || !/^https?:\/\//.test(target)) return true;
|
|
@@ -1204,22 +1449,28 @@ var chunksFromMarkdown = (property, raw, sourceUrl) => {
|
|
|
1204
1449
|
var loadFederatedChunks = async (root, config, options = {}) => {
|
|
1205
1450
|
const fetchText = options.fetchText ?? defaultFetchText;
|
|
1206
1451
|
const chunks = [];
|
|
1452
|
+
const warnings = [];
|
|
1207
1453
|
for (const source of config.federation?.sources ?? []) {
|
|
1208
1454
|
if (source.includeInRetriever === false || !source.llmsTxt) continue;
|
|
1209
1455
|
const llms = await sourceText(root, source.llmsTxt, fetchText);
|
|
1456
|
+
if (!llms) {
|
|
1457
|
+
warnings.push(`federation source skipped (unavailable): ${source.id} \u2192 ${source.llmsTxt}`);
|
|
1458
|
+
continue;
|
|
1459
|
+
}
|
|
1210
1460
|
chunks.push(...chunksFromMarkdown(source.id, llms, source.llmsTxt));
|
|
1211
1461
|
const links = parseLlmsTxtLinks(llms);
|
|
1212
1462
|
for (const link of links) {
|
|
1213
1463
|
const url = !/^https?:\/\//.test(link.url) && source.rawBaseUrl ? `${source.rawBaseUrl.replace(/\/$/, "")}/${link.url.replace(/^\//, "")}` : link.url;
|
|
1214
1464
|
if (!/\.(md|txt)(?:$|\?)/.test(url)) continue;
|
|
1215
1465
|
if (!sameOrigin(source.llmsTxt, url)) continue;
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
chunks.push(...chunksFromMarkdown(source.id, raw, url));
|
|
1219
|
-
} catch {
|
|
1220
|
-
}
|
|
1466
|
+
const raw = await sourceText(root, url, fetchText);
|
|
1467
|
+
if (raw) chunks.push(...chunksFromMarkdown(source.id, raw, url));
|
|
1221
1468
|
}
|
|
1222
1469
|
}
|
|
1470
|
+
if (warnings.length && process.stderr.isTTY) {
|
|
1471
|
+
for (const w of warnings) process.stderr.write(`${w}
|
|
1472
|
+
`);
|
|
1473
|
+
}
|
|
1223
1474
|
return chunks;
|
|
1224
1475
|
};
|
|
1225
1476
|
var retrieveHybridChunks = async (root, config, index, query, options = {}) => {
|
|
@@ -1241,11 +1492,11 @@ var retrieveHybridChunks = async (root, config, index, query, options = {}) => {
|
|
|
1241
1492
|
};
|
|
1242
1493
|
|
|
1243
1494
|
// src/gates/run-gates.ts
|
|
1244
|
-
import { readFileSync as
|
|
1495
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
1245
1496
|
|
|
1246
1497
|
// src/query/load-index.ts
|
|
1247
|
-
import { existsSync as
|
|
1248
|
-
import { join as
|
|
1498
|
+
import { existsSync as existsSync8, readFileSync as readFileSync10 } from "fs";
|
|
1499
|
+
import { join as join11, resolve as resolve4 } from "path";
|
|
1249
1500
|
|
|
1250
1501
|
// src/schemas/agent-handoff.ts
|
|
1251
1502
|
import { z as z2 } from "zod";
|
|
@@ -1319,7 +1570,9 @@ var KnowledgeEntrySchema = z3.object({
|
|
|
1319
1570
|
type: z3.string().min(1).max(128),
|
|
1320
1571
|
title: z3.string().min(1).max(256),
|
|
1321
1572
|
path: z3.string().min(1).max(512),
|
|
1322
|
-
description: z3.string().max(
|
|
1573
|
+
description: z3.string().max(2048).optional(),
|
|
1574
|
+
/** Flattened body excerpt for full-text search (not for display). */
|
|
1575
|
+
body: z3.string().max(8e3).optional(),
|
|
1323
1576
|
links: z3.array(z3.string().min(1).max(512)).max(64).optional(),
|
|
1324
1577
|
tags: z3.array(z3.string().min(1).max(64)).max(32).optional()
|
|
1325
1578
|
}).strict();
|
|
@@ -1450,11 +1703,11 @@ var IndexNotFoundError = class extends Error {
|
|
|
1450
1703
|
}
|
|
1451
1704
|
path;
|
|
1452
1705
|
};
|
|
1453
|
-
var indexFilePath = (root, config) =>
|
|
1706
|
+
var indexFilePath = (root, config) => join11(root, config.index?.outFile ?? ".doc-bridge/index.json");
|
|
1454
1707
|
var loadDocBridgeIndex = (root, config) => {
|
|
1455
1708
|
const path = indexFilePath(root, config);
|
|
1456
|
-
if (!
|
|
1457
|
-
const raw = JSON.parse(
|
|
1709
|
+
if (!existsSync8(path)) throw new IndexNotFoundError(path);
|
|
1710
|
+
const raw = JSON.parse(readFileSync10(path, "utf8"));
|
|
1458
1711
|
return parseDocBridgeIndex(raw);
|
|
1459
1712
|
};
|
|
1460
1713
|
|
|
@@ -1518,7 +1771,7 @@ var runOkfTypeGate = (root, config) => {
|
|
|
1518
1771
|
const required = config.corpus.agent.okf?.requireType ?? config.gates?.preset === "strict";
|
|
1519
1772
|
if (!required) return { id: "okf-type", ok: true, message: "OKF type frontmatter not required" };
|
|
1520
1773
|
const allowed = config.corpus.agent.okf?.allowedTypes;
|
|
1521
|
-
const bad = scanAgentCorpus(root, config).filter((doc) => doc.path !== config.corpus.agent.index).map((doc) => ({ path: doc.path, type: frontmatterType(
|
|
1774
|
+
const bad = scanAgentCorpus(root, config).filter((doc) => doc.path !== config.corpus.agent.index).map((doc) => ({ path: doc.path, type: frontmatterType(readFileSync11(doc.absPath, "utf8")) })).filter((doc) => !doc.type || allowed && !allowed.includes(doc.type));
|
|
1522
1775
|
if (bad.length) {
|
|
1523
1776
|
return {
|
|
1524
1777
|
id: "okf-type",
|
|
@@ -1539,13 +1792,22 @@ var DOCS_STYLE_RULES = {
|
|
|
1539
1792
|
"examples",
|
|
1540
1793
|
"no-stale-wording"
|
|
1541
1794
|
],
|
|
1542
|
-
|
|
1795
|
+
/** Full playbook OKF style (strict). */
|
|
1796
|
+
"playbook-okf": ["title", "purpose", "owner-source", "no-stale-wording"],
|
|
1797
|
+
/** Soft profile for large existing OKF corpora (title + no stale placeholders). */
|
|
1798
|
+
"playbook-okf-soft": ["title", "no-stale-wording"],
|
|
1799
|
+
"title-only": ["title"]
|
|
1543
1800
|
};
|
|
1544
1801
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1545
1802
|
var docsStyleOptions = (config) => {
|
|
1546
1803
|
const raw = config.gates?.options?.["docs-style"];
|
|
1547
|
-
if (!isRecord(raw))
|
|
1548
|
-
|
|
1804
|
+
if (!isRecord(raw)) {
|
|
1805
|
+
if (config.gates?.preset === "playbook") {
|
|
1806
|
+
return { profile: "playbook-okf-soft", required: DOCS_STYLE_RULES["playbook-okf-soft"] };
|
|
1807
|
+
}
|
|
1808
|
+
return { profile: "playbook-okf", required: DOCS_STYLE_RULES["playbook-okf"] };
|
|
1809
|
+
}
|
|
1810
|
+
const profile = raw.profile === "google-dev-docs" || raw.profile === "playbook-okf" || raw.profile === "playbook-okf-soft" || raw.profile === "title-only" || raw.profile === "custom" ? raw.profile : "playbook-okf";
|
|
1549
1811
|
const customRequired = Array.isArray(raw.required) ? raw.required.filter(
|
|
1550
1812
|
(rule) => [
|
|
1551
1813
|
"title",
|
|
@@ -1583,7 +1845,7 @@ var runDocsStyleGate = (root, config) => {
|
|
|
1583
1845
|
}
|
|
1584
1846
|
const bad = scanAgentCorpus(root, config).filter((doc) => doc.path !== config.corpus.agent.index).map((doc) => ({
|
|
1585
1847
|
path: doc.path,
|
|
1586
|
-
missing: missingStyleRules(
|
|
1848
|
+
missing: missingStyleRules(readFileSync11(doc.absPath, "utf8"), required)
|
|
1587
1849
|
})).filter((doc) => doc.missing.length > 0);
|
|
1588
1850
|
if (bad.length) {
|
|
1589
1851
|
return {
|
|
@@ -1607,7 +1869,10 @@ var runGates = (root, config, ids) => {
|
|
|
1607
1869
|
var resolveGateIds = (config) => {
|
|
1608
1870
|
const preset = config.gates?.preset ?? "minimal";
|
|
1609
1871
|
const ids = new Set(
|
|
1610
|
-
preset === "minimal" ? ["index-freshness"] : preset === "strict" ? ["index-freshness", "human-guide-links", "okf-type"] :
|
|
1872
|
+
preset === "minimal" ? ["index-freshness"] : preset === "strict" ? ["index-freshness", "human-guide-links", "okf-type", "docs-style"] : preset === "playbook" ? (
|
|
1873
|
+
// okf-type only — docs-style soft is opt-in via include (large corpora vary)
|
|
1874
|
+
["index-freshness", "okf-type"]
|
|
1875
|
+
) : ["index-freshness", "human-guide-links"]
|
|
1611
1876
|
);
|
|
1612
1877
|
for (const id of config.gates?.include ?? []) {
|
|
1613
1878
|
if (SUPPORTED_GATES.includes(id)) ids.add(id);
|
|
@@ -1720,7 +1985,7 @@ var runQuery = (index, config, req) => {
|
|
|
1720
1985
|
};
|
|
1721
1986
|
|
|
1722
1987
|
// src/intelligence/adapter.ts
|
|
1723
|
-
import { join as
|
|
1988
|
+
import { join as join12 } from "path";
|
|
1724
1989
|
|
|
1725
1990
|
// src/intelligence/peers.ts
|
|
1726
1991
|
var PeerMissingError = class extends Error {
|
|
@@ -1835,20 +2100,20 @@ var resolveIntelligenceRuntime = async (config) => {
|
|
|
1835
2100
|
}
|
|
1836
2101
|
return { adapter, embed, provider, ...model ? { model } : {} };
|
|
1837
2102
|
};
|
|
1838
|
-
var defaultVectorStorePath = (root) =>
|
|
2103
|
+
var defaultVectorStorePath = (root) => join12(root, ".doc-bridge", "vectors");
|
|
1839
2104
|
|
|
1840
2105
|
// src/intelligence/rag.ts
|
|
1841
|
-
import { readFileSync as
|
|
1842
|
-
import { join as
|
|
2106
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
2107
|
+
import { join as join13 } from "path";
|
|
1843
2108
|
var loadDocuments = (root, index, sources) => {
|
|
1844
2109
|
const includeAgent = sources.includes("agent") || sources.length === 0;
|
|
1845
2110
|
const docs = [];
|
|
1846
2111
|
if (includeAgent) {
|
|
1847
2112
|
for (const entry of index.knowledge) {
|
|
1848
|
-
const abs =
|
|
2113
|
+
const abs = join13(root, entry.path);
|
|
1849
2114
|
let content = "";
|
|
1850
2115
|
try {
|
|
1851
|
-
content =
|
|
2116
|
+
content = readFileSync12(abs, "utf8");
|
|
1852
2117
|
} catch {
|
|
1853
2118
|
content = [entry.title, entry.description].filter(Boolean).join("\n\n");
|
|
1854
2119
|
}
|
|
@@ -1866,7 +2131,7 @@ var createDocBridgeRag = async (root, config, index) => {
|
|
|
1866
2131
|
const { embed } = await resolveIntelligenceRuntime(config);
|
|
1867
2132
|
const ragMod = await importPeer("@agentskit/rag");
|
|
1868
2133
|
const memoryMod = await importPeer("@agentskit/memory");
|
|
1869
|
-
const storePath = typeof config.intelligence?.retriever?.options?.storePath === "string" ?
|
|
2134
|
+
const storePath = typeof config.intelligence?.retriever?.options?.storePath === "string" ? join13(root, config.intelligence.retriever.options.storePath) : defaultVectorStorePath(root);
|
|
1870
2135
|
const store = memoryMod.fileVectorMemory({ path: storePath });
|
|
1871
2136
|
const rag = ragMod.createRAG({
|
|
1872
2137
|
embed,
|
|
@@ -2001,15 +2266,15 @@ var startInkChat = async (root, config, index) => {
|
|
|
2001
2266
|
};
|
|
2002
2267
|
|
|
2003
2268
|
// src/memory/ingest.ts
|
|
2004
|
-
import { existsSync as
|
|
2005
|
-
import { join as
|
|
2269
|
+
import { existsSync as existsSync9, readFileSync as readFileSync13 } from "fs";
|
|
2270
|
+
import { join as join14 } from "path";
|
|
2006
2271
|
var memoryFact = (raw, id) => firstParagraph(raw) ?? firstHeading(raw) ?? id;
|
|
2007
2272
|
var relativePath = (root, abs) => toPosix(abs).replace(`${toPosix(root)}/`, "");
|
|
2008
2273
|
var ingestMarkdownDir = (root, dir, source, confidence) => {
|
|
2009
|
-
if (!
|
|
2274
|
+
if (!existsSync9(dir)) return [];
|
|
2010
2275
|
return walkFiles(dir, { extensions: [".md", ".mdc"] }).map((abs) => {
|
|
2011
2276
|
const rel = relativePath(root, abs);
|
|
2012
|
-
const raw =
|
|
2277
|
+
const raw = readFileSync13(abs, "utf8");
|
|
2013
2278
|
const id = slugFromPath(rel);
|
|
2014
2279
|
return {
|
|
2015
2280
|
schemaVersion: 1,
|
|
@@ -2024,10 +2289,10 @@ var ingestMarkdownDir = (root, dir, source, confidence) => {
|
|
|
2024
2289
|
});
|
|
2025
2290
|
};
|
|
2026
2291
|
var ingestCursorRules = (root) => {
|
|
2027
|
-
const dir =
|
|
2292
|
+
const dir = join14(root, ".cursor", "rules");
|
|
2028
2293
|
return ingestMarkdownDir(root, dir, "cursor", 0.6);
|
|
2029
2294
|
};
|
|
2030
|
-
var ingestAgentMemory = (root) => ingestMarkdownDir(root,
|
|
2295
|
+
var ingestAgentMemory = (root) => ingestMarkdownDir(root, join14(root, ".agent-memory"), "agent-memory", 0.7);
|
|
2031
2296
|
var ingestMemoryCandidates = (root) => [
|
|
2032
2297
|
...ingestAgentMemory(root),
|
|
2033
2298
|
...ingestCursorRules(root)
|
|
@@ -2113,7 +2378,7 @@ var draftMemoryPromotion = (classifications) => {
|
|
|
2113
2378
|
};
|
|
2114
2379
|
|
|
2115
2380
|
// src/mcp/server.ts
|
|
2116
|
-
import { readFileSync as
|
|
2381
|
+
import { readFileSync as readFileSync14, realpathSync } from "fs";
|
|
2117
2382
|
import { relative, resolve as resolve5 } from "path";
|
|
2118
2383
|
import { z as z5, ZodError } from "zod";
|
|
2119
2384
|
var MCP_TOOLS = [
|
|
@@ -2234,7 +2499,7 @@ var handleMcpRequest = (ctx, request) => {
|
|
|
2234
2499
|
return {
|
|
2235
2500
|
protocolVersion: "2024-11-05",
|
|
2236
2501
|
capabilities: { tools: {} },
|
|
2237
|
-
serverInfo: { name: "ak-docs", version:
|
|
2502
|
+
serverInfo: { name: "ak-docs", version: PACKAGE_VERSION }
|
|
2238
2503
|
};
|
|
2239
2504
|
}
|
|
2240
2505
|
if (request.method === "tools/list") return { tools: MCP_TOOLS };
|
|
@@ -2259,7 +2524,7 @@ var handleMcpRequest = (ctx, request) => {
|
|
|
2259
2524
|
}
|
|
2260
2525
|
if (name === "doc.get") {
|
|
2261
2526
|
const relPath = findDocPath(index(), parseToolArgs("doc.get", DocGetArgsSchema, args));
|
|
2262
|
-
return textResult(
|
|
2527
|
+
return textResult(readFileSync14(resolveDocPath(ctx.root, relPath), "utf8"));
|
|
2263
2528
|
}
|
|
2264
2529
|
if (name === "gate.status") return textResult(runGates(ctx.root, ctx.config));
|
|
2265
2530
|
if (name === "retriever.query") {
|
|
@@ -2436,35 +2701,38 @@ var writeTextQuery = (payload) => {
|
|
|
2436
2701
|
writeLines([
|
|
2437
2702
|
`Search: ${String(data.term ?? "")}`,
|
|
2438
2703
|
`Matches: ${String(data.count ?? matches.length)}`,
|
|
2439
|
-
...matches.map(
|
|
2440
|
-
(match) =>
|
|
2441
|
-
)
|
|
2704
|
+
...matches.length ? matches.map(
|
|
2705
|
+
(match) => formatSearchMatch(match)
|
|
2706
|
+
) : [" (none)"]
|
|
2442
2707
|
]);
|
|
2443
2708
|
return;
|
|
2444
2709
|
}
|
|
2445
2710
|
writeLines([textValue(result.data)]);
|
|
2446
2711
|
};
|
|
2712
|
+
var formatSearchMatch = (match) => {
|
|
2713
|
+
const summary = match.summary ? match.summary.replace(/\s+/g, " ").slice(0, 100) : "";
|
|
2714
|
+
const score = typeof match.score === "number" ? ` score=${match.score}` : "";
|
|
2715
|
+
return ` [${match.type}] ${match.id}${score}
|
|
2716
|
+
${match.path}${summary ? `
|
|
2717
|
+
${summary}` : ""}`;
|
|
2718
|
+
};
|
|
2447
2719
|
var writeTextSearch = (term, matches) => {
|
|
2448
2720
|
writeLines([
|
|
2449
2721
|
`Search: ${term}`,
|
|
2450
2722
|
`Matches: ${matches.length}`,
|
|
2451
|
-
...matches.map(
|
|
2452
|
-
(match) => [match.type, match.id, match.path, match.summary].filter(Boolean).join(" ")
|
|
2453
|
-
)
|
|
2723
|
+
...matches.length ? matches.map(formatSearchMatch) : [" (none)"]
|
|
2454
2724
|
]);
|
|
2455
2725
|
};
|
|
2456
2726
|
var writeAsk = (question, matches, index) => {
|
|
2457
|
-
const
|
|
2458
|
-
const
|
|
2459
|
-
const bestQuery =
|
|
2727
|
+
const owner = matches.find((match) => match.type === "ownership") ?? matches.find((match) => Boolean(index.lookup?.ownership?.[match.id]));
|
|
2728
|
+
const best = owner ?? matches[0];
|
|
2729
|
+
const bestQuery = best && (best.type === "ownership" || index.lookup?.ownership?.[best.id]) ? `ak-docs query ownership ${best.id} --agent` : "ak-docs list knowledge --text";
|
|
2460
2730
|
writeLines([
|
|
2461
2731
|
`Question: ${question}`,
|
|
2462
2732
|
best ? `Best match: ${best.type} ${best.id} (${best.path})` : "Best match: none",
|
|
2463
2733
|
"",
|
|
2464
2734
|
"Matches:",
|
|
2465
|
-
...matches.length ? matches.slice(0, 5).map(
|
|
2466
|
-
(match) => [match.type, match.id, match.path, match.summary].filter(Boolean).join(" ")
|
|
2467
|
-
) : ["No local matches. Try: ak-docs search <term>"],
|
|
2735
|
+
...matches.length ? matches.slice(0, 5).map(formatSearchMatch) : [" No local matches. Try: ak-docs search <term>"],
|
|
2468
2736
|
"",
|
|
2469
2737
|
"Next commands:",
|
|
2470
2738
|
...best ? [
|
|
@@ -2482,7 +2750,7 @@ var readIndexedDoc = (root, config, idOrPath) => {
|
|
|
2482
2750
|
if (abs !== rootAbs && !abs.startsWith(`${rootAbs}/`)) {
|
|
2483
2751
|
throw new Error(`Indexed doc escapes project root: ${entry.path}`);
|
|
2484
2752
|
}
|
|
2485
|
-
return
|
|
2753
|
+
return readFileSync15(abs, "utf8");
|
|
2486
2754
|
};
|
|
2487
2755
|
var runAskRepl = async (root, config) => {
|
|
2488
2756
|
const index = loadDocBridgeIndex(root, config);
|
|
@@ -2558,7 +2826,7 @@ var diagnosticNextCommands = (config, result) => {
|
|
|
2558
2826
|
];
|
|
2559
2827
|
};
|
|
2560
2828
|
var writeIfMissing = (path, contents) => {
|
|
2561
|
-
if (
|
|
2829
|
+
if (existsSync10(path)) return false;
|
|
2562
2830
|
mkdirSync2(dirname4(path), { recursive: true });
|
|
2563
2831
|
writeFileSync2(path, contents, "utf8");
|
|
2564
2832
|
return true;
|
|
@@ -2673,7 +2941,7 @@ var bootstrapAgentDocs = (root, config) => {
|
|
|
2673
2941
|
const created = [];
|
|
2674
2942
|
const skipped = [];
|
|
2675
2943
|
for (const doc of scanHumanDocRecords(root, config)) {
|
|
2676
|
-
const raw =
|
|
2944
|
+
const raw = readFileSync15(doc.path, "utf8");
|
|
2677
2945
|
const body = raw.replace(/^---\n[\s\S]*?\n---\n?/, "");
|
|
2678
2946
|
const title = firstHeading(body) ?? doc.id;
|
|
2679
2947
|
const description = firstParagraph(body);
|
|
@@ -2742,7 +3010,7 @@ var runCli = (argv) => {
|
|
|
2742
3010
|
}
|
|
2743
3011
|
try {
|
|
2744
3012
|
const abs = resolve6(file);
|
|
2745
|
-
const raw =
|
|
3013
|
+
const raw = readFileSync15(abs, "utf8");
|
|
2746
3014
|
const handoff = parseAgentHandoff(JSON.parse(raw));
|
|
2747
3015
|
writeJson({ ok: true, handoff });
|
|
2748
3016
|
return 0;
|