@agentskit/doc-bridge 1.0.2 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/CONTRIBUTING.md +8 -0
  3. package/README.md +114 -17
  4. package/SECURITY.md +1 -1
  5. package/action.yml +23 -26
  6. package/dist/cli/program.js +1241 -309
  7. package/dist/cli/program.js.map +1 -1
  8. package/dist/config/index.d.ts +1 -1
  9. package/dist/config/index.js +338 -13
  10. package/dist/config/index.js.map +1 -1
  11. package/dist/{index-CPUJbTbg.d.ts → index-DGI9TBLE.d.ts} +906 -11
  12. package/dist/index.d.ts +65 -11
  13. package/dist/index.js +1084 -171
  14. package/dist/index.js.map +1 -1
  15. package/docs/DOGFOOD-ROUND2.md +5 -0
  16. package/docs/DOGFOOD-ROUND3.md +5 -0
  17. package/docs/DOGFOOD-V1.md +5 -0
  18. package/docs/DOGFOOD.md +5 -0
  19. package/docs/MARKETPLACE-ECOSYSTEM-PLAN.md +16 -0
  20. package/docs/MARKETPLACE.md +39 -0
  21. package/docs/POSITIONING.md +5 -0
  22. package/docs/RELEASE.md +26 -19
  23. package/docs/agent-corpus/INDEX.md +10 -0
  24. package/docs/agent-corpus/OVERVIEW.md +9 -0
  25. package/docs/agent-corpus/chat.md +10 -0
  26. package/docs/agent-corpus/cli.md +10 -0
  27. package/docs/agent-corpus/conformance.md +10 -0
  28. package/docs/agent-corpus/doc-bridge.md +10 -0
  29. package/docs/agent-corpus/doctor.md +10 -0
  30. package/docs/agent-corpus/gates.md +10 -0
  31. package/docs/agent-corpus/mcp.md +10 -0
  32. package/docs/agent-corpus/memory.md +10 -0
  33. package/docs/agent-corpus/query.md +10 -0
  34. package/docs/chat-and-rag.md +34 -0
  35. package/docs/examples.md +5 -0
  36. package/docs/for-agents.md +31 -0
  37. package/docs/getting-started.md +32 -2
  38. package/docs/index.md +23 -0
  39. package/docs/landing/assets/doc-bridge-hero.webp +0 -0
  40. package/docs/landing/assets/doc-bridge-surfaces.webp +0 -0
  41. package/docs/landing/assets/doc-bridge-two-way.webp +0 -0
  42. package/docs/landing/index.html +70 -10
  43. package/docs/mcp.md +5 -0
  44. package/docs/meta.json +20 -0
  45. package/docs/ollama-demo.md +6 -1
  46. package/docs/playbook/doc-bridge-pattern.md +4 -2
  47. package/docs/query.md +34 -0
  48. package/docs/recipes/index-pipeline.md +7 -2
  49. package/docs/schemas/agent-handoff-v1.md +5 -0
  50. package/docs/schemas/doc-bridge-index-v1.md +5 -0
  51. package/docs/schemas/memory-candidate-v1.md +15 -1
  52. package/docs/skills/doc-bridge.md +6 -1
  53. package/docs/spec/cli.md +6 -0
  54. package/docs/spec/config-v1.md +56 -6
  55. package/docs/spec/documentation-standard-v1.md +136 -0
  56. package/docs/spec/playbook-feedback.md +5 -0
  57. package/docs/spec/registry-agents.md +5 -0
  58. package/ecosystem-claims.json +187 -0
  59. package/ecosystem-upstream.json +9 -0
  60. package/ecosystem.json +235 -0
  61. package/examples/verify-handoff.mjs +5 -0
  62. package/package.json +46 -4
  63. package/scripts/check-ecosystem-upstream.mjs +50 -0
  64. package/src/cli/program.ts +36 -3
  65. package/src/config/index.ts +7 -1
  66. package/src/config/load-config.ts +4 -14
  67. package/src/config/schema.ts +91 -0
  68. package/src/conformance/documentation-standard-v1.ts +502 -0
  69. package/src/conformance/ecosystem-contract.ts +175 -0
  70. package/src/gates/run-gates.ts +33 -4
  71. package/src/index-builder/human-adapters/core.ts +12 -5
  72. package/src/index-builder/human-adapters/docusaurus.ts +29 -44
  73. package/src/index-builder/human-adapters/index.ts +15 -3
  74. package/src/index-builder/scan-corpus.ts +6 -6
  75. package/src/index.ts +17 -0
  76. package/src/lib/bounded-text.ts +25 -0
  77. package/src/lib/paths.ts +20 -2
  78. package/src/lib/static-js-literal.ts +261 -0
  79. package/src/lib/walk.ts +23 -4
  80. package/src/version.ts +1 -1
package/dist/index.js CHANGED
@@ -137,7 +137,8 @@ var GatesConfigSchema = z.object({
137
137
  "okf-type",
138
138
  "docs-style",
139
139
  "routing-currency",
140
- "bootstrap-size"
140
+ "bootstrap-size",
141
+ "documentation-standard-v1"
141
142
  ])
142
143
  ).max(16).optional(),
143
144
  exclude: z.array(
@@ -148,7 +149,8 @@ var GatesConfigSchema = z.object({
148
149
  "okf-type",
149
150
  "docs-style",
150
151
  "routing-currency",
151
- "bootstrap-size"
152
+ "bootstrap-size",
153
+ "documentation-standard-v1"
152
154
  ])
153
155
  ).max(16).optional(),
154
156
  options: z.record(z.string(), z.unknown()).optional()
@@ -227,6 +229,69 @@ var FederationConfigSchema = z.object({
227
229
  }).strict()
228
230
  ).max(16).optional()
229
231
  }).strict();
232
+ var DocumentationEvidenceFileSchema = z.object({
233
+ path: z.string().min(1).max(512),
234
+ contains: z.array(z.string().min(1).max(512)).min(1).max(32)
235
+ }).strict();
236
+ var DocumentationLinkEvidenceSchema = z.object({
237
+ url: z.string().url().max(512),
238
+ paths: z.array(z.string().min(1).max(512)).min(1).max(32)
239
+ }).strict();
240
+ var DocumentationQuickstartEvidenceSchema = z.object({
241
+ id: z.string().regex(/^[a-z][a-z0-9-]*$/).max(128),
242
+ doc: z.string().min(1).max(512),
243
+ test: z.string().min(1).max(512),
244
+ command: z.string().min(1).max(512),
245
+ testContains: z.array(z.string().min(1).max(256)).min(1).max(16)
246
+ }).strict();
247
+ var EcosystemContractEvidenceSchema = z.object({
248
+ manifest: z.string().min(1).max(512),
249
+ claims: z.string().min(1).max(512),
250
+ productId: z.string().regex(/^[a-z][a-z0-9-]*$/).max(128)
251
+ }).strict();
252
+ var DocumentationStandardRuleIdSchema = z.enum([
253
+ "human-docs",
254
+ "llms-and-raw-source",
255
+ "agent-handoffs",
256
+ "contribution",
257
+ "metadata",
258
+ "cross-links",
259
+ "tested-quickstarts",
260
+ "visual-explanations",
261
+ "structured-diagrams"
262
+ ]);
263
+ var DocumentationStandardExceptionSchema = z.object({
264
+ ruleId: DocumentationStandardRuleIdSchema,
265
+ reason: z.string().min(10).max(1024),
266
+ approvedBy: z.string().min(1).max(256),
267
+ trackingUrl: z.string().url().max(512)
268
+ }).strict();
269
+ var DocumentationStandardV1ConfigSchema = z.object({
270
+ rawSources: z.array(z.string().min(1).max(512)).max(64).optional(),
271
+ contributionPaths: z.array(z.string().min(1).max(512)).max(16).optional(),
272
+ metadata: z.array(DocumentationEvidenceFileSchema).max(32).optional(),
273
+ links: z.array(DocumentationLinkEvidenceSchema).max(64).optional(),
274
+ quickstarts: z.array(DocumentationQuickstartEvidenceSchema).max(32).optional(),
275
+ visuals: z.array(z.string().min(1).max(512)).max(64).optional(),
276
+ diagrams: z.array(DocumentationEvidenceFileSchema).max(32).optional(),
277
+ ecosystemContract: EcosystemContractEvidenceSchema.optional(),
278
+ exceptions: z.array(DocumentationStandardExceptionSchema).max(32).optional()
279
+ }).strict().superRefine((value, context) => {
280
+ const seen = /* @__PURE__ */ new Set();
281
+ for (const [index, exception] of (value.exceptions ?? []).entries()) {
282
+ if (seen.has(exception.ruleId)) {
283
+ context.addIssue({
284
+ code: "custom",
285
+ path: ["exceptions", index, "ruleId"],
286
+ message: `Duplicate exception for rule ${exception.ruleId}`
287
+ });
288
+ }
289
+ seen.add(exception.ruleId);
290
+ }
291
+ });
292
+ var ConformanceConfigSchema = z.object({
293
+ documentationStandardV1: DocumentationStandardV1ConfigSchema.optional()
294
+ }).strict();
230
295
  var DocBridgeConfigV1Schema = z.object({
231
296
  schemaVersion: z.literal(CONFIG_SCHEMA_VERSION),
232
297
  project: z.object({
@@ -242,7 +307,8 @@ var DocBridgeConfigV1Schema = z.object({
242
307
  gates: GatesConfigSchema.optional(),
243
308
  surfaces: SurfacesConfigSchema.optional(),
244
309
  intelligence: IntelligenceConfigSchema.optional(),
245
- federation: FederationConfigSchema.optional()
310
+ federation: FederationConfigSchema.optional(),
311
+ conformance: ConformanceConfigSchema.optional()
246
312
  }).strict();
247
313
 
248
314
  // src/config/define-config.ts
@@ -251,7 +317,268 @@ var defineConfig = (config) => applyConfigDefaults(DocBridgeConfigV1Schema.parse
251
317
  // src/config/load-config.ts
252
318
  import { existsSync, readFileSync } from "fs";
253
319
  import { basename, dirname, join, resolve } from "path";
254
- import vm from "vm";
320
+
321
+ // src/lib/static-js-literal.ts
322
+ var stripComments = (source) => {
323
+ let out = "";
324
+ let index = 0;
325
+ let quote;
326
+ while (index < source.length) {
327
+ const char = source[index] ?? "";
328
+ const next = source[index + 1] ?? "";
329
+ if (quote) {
330
+ out += char;
331
+ if (char === "\\") {
332
+ out += next;
333
+ index += 2;
334
+ continue;
335
+ }
336
+ if (char === quote) quote = void 0;
337
+ index += 1;
338
+ continue;
339
+ }
340
+ if (char === '"' || char === "'" || char === "`") {
341
+ quote = char;
342
+ out += char;
343
+ index += 1;
344
+ continue;
345
+ }
346
+ if (char === "/" && next === "/") {
347
+ while (index < source.length && source[index] !== "\n") index += 1;
348
+ out += "\n";
349
+ index += 1;
350
+ continue;
351
+ }
352
+ if (char === "/" && next === "*") {
353
+ index += 2;
354
+ while (index < source.length && !(source[index] === "*" && source[index + 1] === "/")) index += 1;
355
+ index += 2;
356
+ out += " ";
357
+ continue;
358
+ }
359
+ out += char;
360
+ index += 1;
361
+ }
362
+ if (quote) throw new Error("Unterminated string in static JavaScript literal.");
363
+ return out;
364
+ };
365
+ var LiteralParser = class {
366
+ constructor(source) {
367
+ this.source = source;
368
+ }
369
+ source;
370
+ index = 0;
371
+ parseAt(index) {
372
+ this.index = index;
373
+ const value = this.value();
374
+ this.space();
375
+ return value;
376
+ }
377
+ space() {
378
+ while (/\s/.test(this.source[this.index] ?? "")) this.index += 1;
379
+ }
380
+ value() {
381
+ this.space();
382
+ const char = this.source[this.index];
383
+ if (char === "{") return this.object();
384
+ if (char === "[") return this.array();
385
+ if (char === '"' || char === "'") return this.string();
386
+ const word = this.word();
387
+ if (word === "true") return true;
388
+ if (word === "false") return false;
389
+ if (word === "null") return null;
390
+ if (/^-?\d+(?:\.\d+)?$/.test(word)) return Number(word);
391
+ throw new Error(`Unsupported dynamic sidebar expression near "${word || char || "EOF"}".`);
392
+ }
393
+ object() {
394
+ const result = {};
395
+ this.index += 1;
396
+ this.space();
397
+ while (this.source[this.index] !== "}") {
398
+ const key = this.source[this.index] === '"' || this.source[this.index] === "'" ? this.string() : this.word();
399
+ if (!key) throw new Error("Static sidebar object key is required.");
400
+ this.space();
401
+ if (this.source[this.index] !== ":") throw new Error(`Static sidebar key "${key}" requires a literal value.`);
402
+ this.index += 1;
403
+ result[key] = this.value();
404
+ this.space();
405
+ if (this.source[this.index] === ",") {
406
+ this.index += 1;
407
+ this.space();
408
+ continue;
409
+ }
410
+ if (this.source[this.index] !== "}") throw new Error("Expected comma or closing brace in static sidebar.");
411
+ }
412
+ this.index += 1;
413
+ return result;
414
+ }
415
+ array() {
416
+ const result = [];
417
+ this.index += 1;
418
+ this.space();
419
+ while (this.source[this.index] !== "]") {
420
+ result.push(this.value());
421
+ this.space();
422
+ if (this.source[this.index] === ",") {
423
+ this.index += 1;
424
+ this.space();
425
+ continue;
426
+ }
427
+ if (this.source[this.index] !== "]") throw new Error("Expected comma or closing bracket in static sidebar.");
428
+ }
429
+ this.index += 1;
430
+ return result;
431
+ }
432
+ string() {
433
+ const quote = this.source[this.index] ?? "";
434
+ this.index += 1;
435
+ let result = "";
436
+ while (this.index < this.source.length) {
437
+ const char = this.source[this.index] ?? "";
438
+ if (char === quote) {
439
+ this.index += 1;
440
+ return result;
441
+ }
442
+ if (char === "\\") {
443
+ const escaped = this.source[this.index + 1];
444
+ if (escaped === void 0) break;
445
+ const escapes = { n: "\n", r: "\r", t: " " };
446
+ result += escapes[escaped] ?? escaped;
447
+ this.index += 2;
448
+ continue;
449
+ }
450
+ result += char;
451
+ this.index += 1;
452
+ }
453
+ throw new Error("Unterminated string in static sidebar.");
454
+ }
455
+ word() {
456
+ this.space();
457
+ const start = this.index;
458
+ while (/[A-Za-z0-9_$.-]/.test(this.source[this.index] ?? "")) this.index += 1;
459
+ return this.source.slice(start, this.index);
460
+ }
461
+ };
462
+ var maskStrings = (source) => {
463
+ const chars = [...source];
464
+ let quote;
465
+ let previousToken;
466
+ const regexPrefixKeywords = /* @__PURE__ */ new Set([
467
+ "await",
468
+ "case",
469
+ "delete",
470
+ "do",
471
+ "else",
472
+ "in",
473
+ "instanceof",
474
+ "new",
475
+ "of",
476
+ "return",
477
+ "throw",
478
+ "typeof",
479
+ "void",
480
+ "yield"
481
+ ]);
482
+ const canStartRegex = () => previousToken === void 0 || "=(:,[!&|?{};".includes(previousToken) || previousToken === "=>" || regexPrefixKeywords.has(previousToken);
483
+ for (let index = 0; index < chars.length; index += 1) {
484
+ const char = chars[index] ?? "";
485
+ if (quote) {
486
+ chars[index] = " ";
487
+ if (char === "\\") {
488
+ if (index + 1 < chars.length) chars[index + 1] = " ";
489
+ index += 1;
490
+ } else if (char === quote) {
491
+ quote = void 0;
492
+ previousToken = "literal";
493
+ }
494
+ continue;
495
+ }
496
+ if (char === '"' || char === "'" || char === "`") {
497
+ quote = char;
498
+ chars[index] = " ";
499
+ continue;
500
+ }
501
+ if (char === "/" && canStartRegex()) {
502
+ chars[index] = " ";
503
+ let inClass = false;
504
+ for (index += 1; index < chars.length; index += 1) {
505
+ const regexChar = chars[index] ?? "";
506
+ chars[index] = " ";
507
+ if (regexChar === "\\") {
508
+ if (index + 1 < chars.length) chars[index + 1] = " ";
509
+ index += 1;
510
+ } else if (regexChar === "[") {
511
+ inClass = true;
512
+ } else if (regexChar === "]") {
513
+ inClass = false;
514
+ } else if (regexChar === "/" && !inClass) {
515
+ while (/[A-Za-z]/.test(chars[index + 1] ?? "")) {
516
+ index += 1;
517
+ chars[index] = " ";
518
+ }
519
+ break;
520
+ }
521
+ }
522
+ previousToken = "literal";
523
+ continue;
524
+ }
525
+ if (/[A-Za-z_$]/.test(char)) {
526
+ const start = index;
527
+ while (/[A-Za-z0-9_$]/.test(chars[index + 1] ?? "")) index += 1;
528
+ previousToken = chars.slice(start, index + 1).join("");
529
+ continue;
530
+ }
531
+ if (char === "=" && chars[index + 1] === ">") {
532
+ previousToken = "=>";
533
+ index += 1;
534
+ continue;
535
+ }
536
+ if (!/\s/.test(char)) previousToken = char;
537
+ }
538
+ return chars.join("");
539
+ };
540
+ var nonSpace = (source, start) => {
541
+ let index = start;
542
+ while (/\s/.test(source[index] ?? "")) index += 1;
543
+ return index;
544
+ };
545
+ var escapedRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
546
+ var parseStaticJsObject = (source) => {
547
+ const clean = stripComments(source);
548
+ const mask = maskStrings(clean);
549
+ const parseBinding = (identifier) => {
550
+ const declaration = new RegExp(`\\b(?:const|let|var)\\s+${escapedRegex(identifier)}(?:\\s*:[^=;]+)?\\s*=`).exec(mask);
551
+ if (!declaration) throw new Error(`Exported binding "${identifier}" must reference a static object declaration.`);
552
+ const start = nonSpace(mask, declaration.index + declaration[0].length);
553
+ if (mask[start] !== "{") throw new Error(`Exported binding "${identifier}" must be a static object literal.`);
554
+ return new LiteralParser(clean).parseAt(start);
555
+ };
556
+ const commonJs = /\bmodule\.exports\s*=/.exec(mask);
557
+ if (commonJs) {
558
+ const start = nonSpace(mask, commonJs.index + commonJs[0].length);
559
+ if (mask[start] === "{") return new LiteralParser(clean).parseAt(start);
560
+ const identifier = /^[A-Za-z_$][\w$]*/.exec(mask.slice(start))?.[0];
561
+ if (identifier) return parseBinding(identifier);
562
+ throw new Error("module.exports must be assigned a static object literal or binding.");
563
+ }
564
+ const exported = /\bexport\s+default\b/.exec(mask);
565
+ if (exported) {
566
+ let start = nonSpace(mask, exported.index + exported[0].length);
567
+ if (mask.slice(start).startsWith("defineConfig")) {
568
+ start = nonSpace(mask, start + "defineConfig".length);
569
+ if (mask[start] !== "(") throw new Error("defineConfig must be called with a static object literal.");
570
+ start = nonSpace(mask, start + 1);
571
+ if (mask[start] !== "{") throw new Error("defineConfig must be called with a static object literal.");
572
+ return new LiteralParser(clean).parseAt(start);
573
+ }
574
+ if (mask[start] === "{") return new LiteralParser(clean).parseAt(start);
575
+ const identifier = /^[A-Za-z_$][\w$]*/.exec(mask.slice(start))?.[0];
576
+ if (identifier) return parseBinding(identifier);
577
+ }
578
+ throw new Error("Docusaurus sidebar must export a static object or assign one to a const.");
579
+ };
580
+
581
+ // src/config/load-config.ts
255
582
  var CONFIG_CANDIDATES = [
256
583
  "doc-bridge.config.ts",
257
584
  "doc-bridge.config.mts",
@@ -295,22 +622,16 @@ var parseJsonConfig = (raw, path) => {
295
622
  }
296
623
  };
297
624
  var parseCodeConfig = (raw, path) => {
298
- const code = raw.replace(/import\s+type\s+[\s\S]*?;?\n/g, "").replace(/import\s+\{\s*defineConfig\s*\}\s+from\s+['"]@agentskit\/doc-bridge(?:\/config)?['"];?\n?/g, "").replace(/\s+satisfies\s+[A-Za-z0-9_.$<>{}\[\],\s]+(?=\s*(?:;|\)|$))/g, "").replace(/export\s+default/, "module.exports.default =");
299
- if (/\bimport\b/.test(code)) {
625
+ const unsupportedImports = raw.replace(/import\s+type\s+[\s\S]*?;?\n/g, "").replace(/import\s+\{\s*defineConfig\s*\}\s+from\s+['"]@agentskit\/doc-bridge(?:\/config)?['"];?\n?/g, "");
626
+ if (/\bimport\b/.test(unsupportedImports)) {
300
627
  throw new Error(`Unsupported import in ${path}. Static config only supports defineConfig imports.`);
301
628
  }
302
- const sandbox = {
303
- module: { exports: {} },
304
- exports: {},
305
- defineConfig: (config) => config
306
- };
307
629
  try {
308
- vm.runInNewContext(code, sandbox, { timeout: 250, filename: path });
630
+ return parseStaticJsObject(raw);
309
631
  } catch (error) {
310
632
  const message = error instanceof Error ? error.message : String(error);
311
633
  throw new Error(`Failed to load config at ${path}: ${message}`);
312
634
  }
313
- return sandbox.module.exports.default;
314
635
  };
315
636
  var parseConfig = (input) => {
316
637
  const result = DocBridgeConfigV1Schema.safeParse(input);
@@ -707,23 +1028,33 @@ ${zodIssues(result.error).map((i) => ` - ${i.path}: ${i.message}`).join("\n")}`
707
1028
  };
708
1029
 
709
1030
  // src/index-builder/build-index.ts
710
- import { mkdirSync, readFileSync as readFileSync8, writeFileSync } from "fs";
711
- import { dirname as dirname3, join as join10 } from "path";
1031
+ import { mkdirSync, readFileSync as readFileSync6, writeFileSync } from "fs";
1032
+ import { dirname as dirname3, join as join7 } from "path";
712
1033
 
713
1034
  // src/lib/paths.ts
714
- import { resolve as resolve2 } from "path";
1035
+ import { existsSync as existsSync2, realpathSync } from "fs";
1036
+ import { isAbsolute, relative, resolve as resolve2, sep } from "path";
715
1037
  var toPosix = (value) => value.split("\\").join("/");
1038
+ var containedProjectPath = (root, path) => {
1039
+ const projectRoot = realpathSync.native(resolve2(root));
1040
+ const unresolved = resolve2(projectRoot, path);
1041
+ const unresolvedRelative = relative(projectRoot, unresolved);
1042
+ if (isAbsolute(unresolvedRelative) || unresolvedRelative === ".." || unresolvedRelative.startsWith(`..${sep}`)) return void 0;
1043
+ const canonical = existsSync2(unresolved) ? realpathSync.native(unresolved) : unresolved;
1044
+ const canonicalRelative = relative(projectRoot, canonical);
1045
+ return isAbsolute(canonicalRelative) || canonicalRelative === ".." || canonicalRelative.startsWith(`..${sep}`) ? void 0 : canonical;
1046
+ };
716
1047
 
717
1048
  // src/lib/package-manager.ts
718
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
1049
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
719
1050
  import { join as join2 } from "path";
720
1051
  var detectPackageManager = (root) => {
721
- if (existsSync2(join2(root, "pnpm-lock.yaml")) || existsSync2(join2(root, "pnpm-workspace.yaml"))) {
1052
+ if (existsSync3(join2(root, "pnpm-lock.yaml")) || existsSync3(join2(root, "pnpm-workspace.yaml"))) {
722
1053
  return "pnpm";
723
1054
  }
724
- if (existsSync2(join2(root, "yarn.lock"))) return "yarn";
725
- if (existsSync2(join2(root, "bun.lockb")) || existsSync2(join2(root, "bun.lock"))) return "bun";
726
- if (existsSync2(join2(root, "package-lock.json"))) return "npm";
1055
+ if (existsSync3(join2(root, "yarn.lock"))) return "yarn";
1056
+ if (existsSync3(join2(root, "bun.lockb")) || existsSync3(join2(root, "bun.lock"))) return "bun";
1057
+ if (existsSync3(join2(root, "package-lock.json"))) return "npm";
727
1058
  try {
728
1059
  const pkg = JSON.parse(readFileSync2(join2(root, "package.json"), "utf8"));
729
1060
  const pm = pkg.packageManager?.split("@")[0];
@@ -744,7 +1075,7 @@ var defaultChecksForTarget = (root, opts) => {
744
1075
  } catch {
745
1076
  }
746
1077
  }
747
- const isWorkspace = existsSync2(join2(root, "pnpm-workspace.yaml")) || existsSync2(join2(root, "lerna.json")) || Boolean(
1078
+ const isWorkspace = existsSync3(join2(root, "pnpm-workspace.yaml")) || existsSync3(join2(root, "lerna.json")) || Boolean(
748
1079
  (() => {
749
1080
  try {
750
1081
  const pkg = JSON.parse(readFileSync2(join2(root, "package.json"), "utf8"));
@@ -778,9 +1109,24 @@ var defaultChecksForTarget = (root, opts) => {
778
1109
  return opts.strict ? ["npm test", "npm run lint"] : ["npm test"];
779
1110
  };
780
1111
 
781
- // src/index-builder/scan-corpus.ts
782
- import { readFileSync as readFileSync3 } from "fs";
783
- import { join as join4 } from "path";
1112
+ // src/lib/bounded-text.ts
1113
+ import { readFileSync as readFileSync3, statSync } from "fs";
1114
+ var MAX_DOCUMENT_BYTES = 4 * 1024 * 1024;
1115
+ var MAX_CORPUS_BYTES = 64 * 1024 * 1024;
1116
+ var readBoundedText = (path, budget, limits) => {
1117
+ const maxFileBytes = limits?.maxFileBytes ?? MAX_DOCUMENT_BYTES;
1118
+ const maxCorpusBytes = limits?.maxCorpusBytes ?? MAX_CORPUS_BYTES;
1119
+ const stat = statSync(path);
1120
+ if (!stat.isFile()) throw new Error(`Documentation path is not a regular file: ${path}`);
1121
+ if (stat.size > maxFileBytes) {
1122
+ throw new Error(`Documentation file exceeds the ${maxFileBytes} byte limit: ${path}`);
1123
+ }
1124
+ if (budget.used + stat.size > maxCorpusBytes) {
1125
+ throw new Error(`Documentation corpus exceeds the ${maxCorpusBytes} byte read budget.`);
1126
+ }
1127
+ budget.used += stat.size;
1128
+ return readFileSync3(path, "utf8");
1129
+ };
784
1130
 
785
1131
  // src/lib/markdown.ts
786
1132
  var parseFrontmatter = (markdown) => {
@@ -871,14 +1217,24 @@ var slugFromPath = (relPath) => {
871
1217
  };
872
1218
 
873
1219
  // src/lib/walk.ts
874
- import { readdirSync, statSync } from "fs";
1220
+ import { lstatSync, readdirSync, realpathSync as realpathSync2 } from "fs";
875
1221
  import { join as join3 } from "path";
876
1222
  var DEFAULT_SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "coverage", ".doc-bridge"]);
1223
+ var DEFAULT_MAX_FILES = 1e4;
877
1224
  var walkFiles = (root, opts) => {
878
1225
  const extensions = opts?.extensions ?? [".md"];
879
1226
  const skip = opts?.skipDirs ?? DEFAULT_SKIP;
880
1227
  const out = [];
1228
+ const visited = /* @__PURE__ */ new Set();
881
1229
  const visit = (dir) => {
1230
+ let canonicalDir;
1231
+ try {
1232
+ canonicalDir = realpathSync2.native(dir);
1233
+ } catch {
1234
+ return;
1235
+ }
1236
+ if (visited.has(canonicalDir)) return;
1237
+ visited.add(canonicalDir);
882
1238
  let entries = [];
883
1239
  try {
884
1240
  entries = readdirSync(dir);
@@ -889,10 +1245,11 @@ var walkFiles = (root, opts) => {
889
1245
  const abs = join3(dir, name);
890
1246
  let st;
891
1247
  try {
892
- st = statSync(abs);
1248
+ st = lstatSync(abs);
893
1249
  } catch {
894
1250
  continue;
895
1251
  }
1252
+ if (st.isSymbolicLink()) continue;
896
1253
  if (st.isDirectory()) {
897
1254
  if (skip.has(name)) continue;
898
1255
  visit(abs);
@@ -900,6 +1257,9 @@ var walkFiles = (root, opts) => {
900
1257
  }
901
1258
  if (!st.isFile()) continue;
902
1259
  if (extensions.some((ext) => name.endsWith(ext))) {
1260
+ if (out.length >= (opts?.maxFiles ?? DEFAULT_MAX_FILES)) {
1261
+ throw new Error(`Documentation corpus exceeds the ${opts?.maxFiles ?? DEFAULT_MAX_FILES} file limit.`);
1262
+ }
903
1263
  out.push(toPosix(abs));
904
1264
  }
905
1265
  }
@@ -910,13 +1270,15 @@ var walkFiles = (root, opts) => {
910
1270
 
911
1271
  // src/index-builder/scan-corpus.ts
912
1272
  var scanAgentCorpus = (root, config) => {
913
- const agentRoot = join4(root, config.corpus.agent.root);
1273
+ const agentRoot = containedProjectPath(root, config.corpus.agent.root);
1274
+ if (!agentRoot) throw new Error("Agent corpus root escapes the project root.");
914
1275
  const files = walkFiles(agentRoot, { extensions: [".md", ".mdx"] });
915
1276
  const corpusRelRoot = toPosix(config.corpus.agent.root);
1277
+ const budget = { used: 0 };
916
1278
  return files.map((abs) => {
917
1279
  const relToCorpus = toPosix(abs.replace(`${toPosix(agentRoot)}/`, ""));
918
1280
  const relPath = `${corpusRelRoot}/${relToCorpus}`;
919
- const raw = readFileSync3(abs, "utf8");
1281
+ const raw = readBoundedText(abs, budget);
920
1282
  const { data: frontmatter } = parseFrontmatter(raw);
921
1283
  const id = frontmatterString(frontmatter, "id") ?? frontmatterString(frontmatter, "package") ?? slugFromPath(relToCorpus);
922
1284
  const title = firstHeading(raw) ?? id;
@@ -1172,7 +1534,7 @@ var buildLookup = (config, packages, corpus, indexOutFile, humanDocs = {}, root
1172
1534
  };
1173
1535
 
1174
1536
  // src/version.ts
1175
- var PACKAGE_VERSION = "1.0.2";
1537
+ var PACKAGE_VERSION = "1.2.1";
1176
1538
 
1177
1539
  // src/index-builder/capabilities.ts
1178
1540
  var renderCapabilitiesJson = (config, index, paths) => {
@@ -1240,14 +1602,16 @@ ${lines.join("\n")}
1240
1602
  `;
1241
1603
  };
1242
1604
 
1605
+ // src/index-builder/human-adapters/index.ts
1606
+ import { realpathSync as realpathSync4 } from "fs";
1607
+ import { resolve as resolve4, sep as sep3 } from "path";
1608
+
1243
1609
  // src/index-builder/human-adapters/docusaurus.ts
1244
- import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
1245
- import { join as join6 } from "path";
1246
- import vm2 from "vm";
1610
+ import { existsSync as existsSync4 } from "fs";
1247
1611
 
1248
1612
  // src/index-builder/human-adapters/core.ts
1249
- import { readFileSync as readFileSync4 } from "fs";
1250
- import { join as join5 } from "path";
1613
+ import { realpathSync as realpathSync3 } from "fs";
1614
+ import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
1251
1615
  var optionString = (options, keys) => {
1252
1616
  for (const key of keys) {
1253
1617
  const value = options?.[key];
@@ -1278,10 +1642,16 @@ var humanUrl = (slug2, urlPrefix) => {
1278
1642
  };
1279
1643
  var scanMarkdownDocs = (root, humanRoot, options) => {
1280
1644
  const out = [];
1281
- const absRoot = join5(root, humanRoot);
1645
+ const projectRoot = realpathSync3.native(resolve3(root));
1646
+ const absRoot = containedProjectPath(root, humanRoot);
1647
+ if (!absRoot) return out;
1648
+ const budget = { used: 0 };
1282
1649
  for (const abs of walkFiles(absRoot, { extensions: [".md", ".mdx"] })) {
1650
+ const canonical = realpathSync3.native(abs);
1651
+ const fileRelative = relative2(projectRoot, canonical);
1652
+ if (isAbsolute2(fileRelative) || fileRelative === ".." || fileRelative.startsWith(`..${sep2}`)) continue;
1283
1653
  const relToHumanRoot = toPosix(abs.replace(`${toPosix(absRoot)}/`, ""));
1284
- const raw = readFileSync4(abs, "utf8");
1654
+ const raw = readBoundedText(abs, budget);
1285
1655
  if (options?.includeRelPath && !options.includeRelPath(relToHumanRoot, raw)) continue;
1286
1656
  out.push({
1287
1657
  id: options?.idForDoc?.(relToHumanRoot, raw) ?? docId(relToHumanRoot, raw),
@@ -1319,41 +1689,31 @@ var docusaurusRecordId = (relPath, raw) => {
1319
1689
  const frontmatter = parseFrontmatter2(raw);
1320
1690
  return frontmatter.package ?? frontmatter.module ?? docusaurusSidebarId(relPath, raw);
1321
1691
  };
1322
- var sidebarsValue = (file) => {
1323
- if (!existsSync3(file)) return void 0;
1324
- 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 =");
1325
- const sandbox = { module: { exports: {} }, exports: {} };
1326
- vm2.runInNewContext(raw, sandbox, { timeout: 250 });
1327
- return sandbox.module.exports;
1328
- };
1329
- var visitSidebar = (value, filter) => {
1330
- if (typeof value === "string") {
1331
- filter.ids.add(value);
1332
- return;
1333
- }
1334
- if (Array.isArray(value)) {
1335
- for (const item2 of value) visitSidebar(item2, filter);
1336
- return;
1337
- }
1338
- if (!value || typeof value !== "object") return;
1339
- const item = value;
1340
- if ((item.type === "doc" || item.type === "ref") && typeof item.id === "string") {
1341
- filter.ids.add(item.id);
1342
- }
1343
- if (item.type === "autogenerated" && typeof item.dirName === "string") {
1344
- filter.autogenDirs.push(item.dirName);
1345
- }
1346
- if (Array.isArray(item.items)) visitSidebar(item.items, filter);
1347
- if (item.link && typeof item.link === "object") visitSidebar(item.link, filter);
1348
- for (const child of Object.values(item)) {
1349
- if (Array.isArray(child)) visitSidebar(child, filter);
1350
- }
1351
- };
1352
- var readSidebars = (root, sidebarsFile) => {
1692
+ var readSidebars = (sidebarsFile) => {
1353
1693
  if (!sidebarsFile) return { enabled: false, ids: /* @__PURE__ */ new Set(), autogenDirs: [] };
1354
- const value = sidebarsValue(join6(root, sidebarsFile));
1694
+ if (!existsSync4(sidebarsFile)) return { enabled: false, ids: /* @__PURE__ */ new Set(), autogenDirs: [] };
1695
+ const raw = readBoundedText(sidebarsFile, { used: 0 }, { maxFileBytes: 1048576, maxCorpusBytes: 1048576 });
1355
1696
  const filter = { ids: /* @__PURE__ */ new Set(), autogenDirs: [] };
1356
- visitSidebar(value, filter);
1697
+ const visit = (value) => {
1698
+ if (typeof value === "string") {
1699
+ filter.ids.add(value);
1700
+ return;
1701
+ }
1702
+ if (Array.isArray(value)) {
1703
+ for (const item2 of value) visit(item2);
1704
+ return;
1705
+ }
1706
+ if (!value || typeof value !== "object") return;
1707
+ const item = value;
1708
+ if ((item.type === "doc" || item.type === "ref") && typeof item.id === "string") filter.ids.add(item.id);
1709
+ if (item.type === "autogenerated" && typeof item.dirName === "string") filter.autogenDirs.push(item.dirName);
1710
+ if (Array.isArray(item.items)) visit(item.items);
1711
+ if (item.link && typeof item.link === "object") visit(item.link);
1712
+ for (const child of Object.values(item)) {
1713
+ if (Array.isArray(child)) visit(child);
1714
+ }
1715
+ };
1716
+ visit(parseStaticJsObject(raw));
1357
1717
  return { enabled: true, ...filter };
1358
1718
  };
1359
1719
  var isIncludedBySidebar = (filter, id) => {
@@ -1369,7 +1729,8 @@ var docusaurusAdapter = {
1369
1729
  scan: ({ root, config }) => {
1370
1730
  const docsDir = optionString(config.options, ["docsDir", "root"]);
1371
1731
  if (!docsDir) return [];
1372
- const sidebarFilter = readSidebars(root, optionString(config.options, ["sidebarsFile"]));
1732
+ const sidebarsFile = optionString(config.options, ["sidebarsFile"]);
1733
+ const sidebarFilter = readSidebars(sidebarsFile ? containedProjectPath(root, sidebarsFile) : void 0);
1373
1734
  return scanMarkdownDocs(root, docsDir, {
1374
1735
  includeRelPath: (relPath, raw) => isIncludedBySidebar(sidebarFilter, docusaurusSidebarId(relPath, raw)),
1375
1736
  idForDoc: docusaurusRecordId,
@@ -1380,13 +1741,13 @@ var docusaurusAdapter = {
1380
1741
  };
1381
1742
 
1382
1743
  // src/index-builder/human-adapters/fumadocs.ts
1383
- import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
1384
- import { join as join7 } from "path";
1744
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
1745
+ import { join as join4 } from "path";
1385
1746
  var readMetaPages = (dir) => {
1386
- const file = join7(dir, "meta.json");
1387
- if (!existsSync4(file)) return void 0;
1747
+ const file = join4(dir, "meta.json");
1748
+ if (!existsSync5(file)) return void 0;
1388
1749
  try {
1389
- const meta = JSON.parse(readFileSync6(file, "utf8"));
1750
+ const meta = JSON.parse(readFileSync4(file, "utf8"));
1390
1751
  return Array.isArray(meta.pages) ? meta.pages.filter((page) => typeof page === "string") : void 0;
1391
1752
  } catch {
1392
1753
  return void 0;
@@ -1401,7 +1762,7 @@ var isListedByMeta = (contentRoot, relPath) => {
1401
1762
  if (isDotFile(relPath)) return false;
1402
1763
  const parts = relPath.split("/");
1403
1764
  for (let i = 0; i < parts.length; i += 1) {
1404
- const dir = join7(contentRoot, ...parts.slice(0, i));
1765
+ const dir = join4(contentRoot, ...parts.slice(0, i));
1405
1766
  const pages = readMetaPages(dir);
1406
1767
  if (!pages?.length || pages.includes("...")) continue;
1407
1768
  const key = pageKey(parts[i] ?? "");
@@ -1414,7 +1775,7 @@ var fumadocsAdapter = {
1414
1775
  scan: ({ root, config }) => {
1415
1776
  const contentDir = optionString(config.options, ["contentDir", "root"]);
1416
1777
  if (!contentDir) return [];
1417
- const contentRoot = join7(root, contentDir);
1778
+ const contentRoot = join4(root, contentDir);
1418
1779
  const excludePrefixes = Array.isArray(config.options?.excludePrefixes) ? config.options.excludePrefixes.filter((v) => typeof v === "string") : typeof config.options?.excludePrefix === "string" ? [config.options.excludePrefix] : [];
1419
1780
  if (!excludePrefixes.includes("for-agents")) excludePrefixes.push("for-agents");
1420
1781
  return scanMarkdownDocs(root, contentDir, {
@@ -1450,15 +1811,23 @@ var humanConfigs = (config) => {
1450
1811
  if (!human) return [];
1451
1812
  return Array.isArray(human) ? human : [human];
1452
1813
  };
1814
+ var canonicalPath = (path) => {
1815
+ try {
1816
+ return realpathSync4.native(path);
1817
+ } catch {
1818
+ return resolve4(path);
1819
+ }
1820
+ };
1453
1821
  var scanHumanDocRecords = (root, config) => {
1454
1822
  const out = [];
1455
1823
  const seen = /* @__PURE__ */ new Set();
1456
- const agentRoot = config.corpus.agent.root.replace(/\/$/, "");
1824
+ const agentRoot = canonicalPath(resolve4(root, config.corpus.agent.root));
1457
1825
  for (const human of humanConfigs(config)) {
1458
1826
  const adapter = ADAPTERS.find((candidate) => candidate.plugin === human.plugin);
1459
1827
  if (!adapter) continue;
1460
1828
  for (const record of adapter.scan({ root, config: human })) {
1461
- if (record.path === agentRoot || record.path.startsWith(`${agentRoot}/`) || record.path.includes("/for-agents/") || record.path.endsWith("/for-agents")) {
1829
+ const recordPath = canonicalPath(record.path);
1830
+ if (recordPath === agentRoot || recordPath.startsWith(`${agentRoot}${sep3}`) || record.path.includes("/for-agents/") || record.path.endsWith("/for-agents")) {
1462
1831
  continue;
1463
1832
  }
1464
1833
  if (seen.has(record.id)) continue;
@@ -1471,26 +1840,26 @@ var scanHumanDocRecords = (root, config) => {
1471
1840
  var scanHumanDocs = (root, config) => Object.fromEntries(scanHumanDocRecords(root, config).map((doc) => [doc.id, doc.url]));
1472
1841
 
1473
1842
  // src/index-builder/plugins/pnpm-monorepo.ts
1474
- import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
1475
- import { basename as basename2, join as join9 } from "path";
1843
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
1844
+ import { basename as basename2, join as join6 } from "path";
1476
1845
 
1477
1846
  // src/lib/glob-expand.ts
1478
- import { existsSync as existsSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
1479
- import { join as join8 } from "path";
1847
+ import { existsSync as existsSync6, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
1848
+ import { join as join5 } from "path";
1480
1849
  var expandWorkspaceGlobs = (root, patterns) => {
1481
1850
  const dirs = /* @__PURE__ */ new Set();
1482
1851
  for (const pattern of patterns) {
1483
1852
  const normalized = toPosix(pattern).replace(/\/$/, "");
1484
1853
  if (!normalized.includes("*")) {
1485
- const abs = join8(root, normalized);
1486
- if (existsSync5(abs)) dirs.add(toPosix(abs));
1854
+ const abs = join5(root, normalized);
1855
+ if (existsSync6(abs)) dirs.add(toPosix(abs));
1487
1856
  continue;
1488
1857
  }
1489
1858
  const star = normalized.indexOf("*");
1490
- const base = join8(root, normalized.slice(0, star).replace(/\/$/, ""));
1491
- if (!existsSync5(base)) continue;
1859
+ const base = join5(root, normalized.slice(0, star).replace(/\/$/, ""));
1860
+ if (!existsSync6(base)) continue;
1492
1861
  for (const name of readdirSync2(base)) {
1493
- const abs = join8(base, name);
1862
+ const abs = join5(base, name);
1494
1863
  try {
1495
1864
  if (statSync2(abs).isDirectory()) dirs.add(toPosix(abs));
1496
1865
  } catch {
@@ -1522,10 +1891,10 @@ var parsePnpmWorkspace = (yaml) => {
1522
1891
  return patterns;
1523
1892
  };
1524
1893
  var readPackageJson = (dir) => {
1525
- const file = join9(dir, "package.json");
1526
- if (!existsSync6(file)) return null;
1894
+ const file = join6(dir, "package.json");
1895
+ if (!existsSync7(file)) return null;
1527
1896
  try {
1528
- return JSON.parse(readFileSync7(file, "utf8"));
1897
+ return JSON.parse(readFileSync5(file, "utf8"));
1529
1898
  } catch {
1530
1899
  return null;
1531
1900
  }
@@ -1534,9 +1903,9 @@ var discoverPnpmPackages = (root, config) => {
1534
1903
  const explicit = config.routing?.options?.packages;
1535
1904
  let patterns = explicit;
1536
1905
  if (!patterns?.length) {
1537
- const workspaceFile = join9(root, "pnpm-workspace.yaml");
1538
- if (existsSync6(workspaceFile)) {
1539
- patterns = parsePnpmWorkspace(readFileSync7(workspaceFile, "utf8"));
1906
+ const workspaceFile = join6(root, "pnpm-workspace.yaml");
1907
+ if (existsSync7(workspaceFile)) {
1908
+ patterns = parsePnpmWorkspace(readFileSync5(workspaceFile, "utf8"));
1540
1909
  }
1541
1910
  }
1542
1911
  if (!patterns?.length) return [];
@@ -1557,7 +1926,7 @@ var discoverPnpmPackages = (root, config) => {
1557
1926
  var projectName = (root, config) => {
1558
1927
  if (config.project?.name) return config.project.name;
1559
1928
  try {
1560
- const pkg = JSON.parse(readFileSync8(join10(root, "package.json"), "utf8"));
1929
+ const pkg = JSON.parse(readFileSync6(join7(root, "package.json"), "utf8"));
1561
1930
  if (pkg.name) return pkg.name;
1562
1931
  } catch {
1563
1932
  }
@@ -1565,7 +1934,7 @@ var projectName = (root, config) => {
1565
1934
  };
1566
1935
  var existingGeneratedAt = (indexPath, contentHash) => {
1567
1936
  try {
1568
- const index = JSON.parse(readFileSync8(indexPath, "utf8"));
1937
+ const index = JSON.parse(readFileSync6(indexPath, "utf8"));
1569
1938
  return index.contentHash === contentHash && typeof index.generatedAt === "string" ? index.generatedAt : void 0;
1570
1939
  } catch {
1571
1940
  return void 0;
@@ -1576,7 +1945,7 @@ var buildDocBridgeIndex = (opts) => {
1576
1945
  const config = opts.config;
1577
1946
  const write = opts.write ?? true;
1578
1947
  const outFile = config.index?.outFile ?? ".doc-bridge/index.json";
1579
- const indexPath = join10(root, outFile);
1948
+ const indexPath = join7(root, outFile);
1580
1949
  const corpus = scanAgentCorpus(root, config);
1581
1950
  const knowledge = corpus.map(({ absPath: _a, relPath: _r, frontmatter: _f, ...entry }) => entry);
1582
1951
  const shouldDiscover = config.routing?.plugin === "pnpm-monorepo" || Boolean(config.routing?.options?.packages?.length) || config.routing?.plugin === "npm-workspaces" || config.routing?.plugin === "yarn-workspaces";
@@ -1611,7 +1980,7 @@ var buildDocBridgeIndex = (opts) => {
1611
1980
  if (config.index?.llmsTxt?.enabled !== false) {
1612
1981
  const llmsOut = config.index?.llmsTxt?.outFile ?? "llms.txt";
1613
1982
  llmsTxtRelPath = toPosix(llmsOut);
1614
- llmsTxtPath = join10(root, llmsOut);
1983
+ llmsTxtPath = join7(root, llmsOut);
1615
1984
  if (write) {
1616
1985
  writeFileSync(
1617
1986
  llmsTxtPath,
@@ -1623,7 +1992,7 @@ var buildDocBridgeIndex = (opts) => {
1623
1992
  let capabilitiesPath;
1624
1993
  if (config.index?.capabilities?.enabled !== false) {
1625
1994
  const capabilitiesOut = config.index?.capabilities?.outFile ?? ".doc-bridge/capabilities.json";
1626
- capabilitiesPath = join10(root, capabilitiesOut);
1995
+ capabilitiesPath = join7(root, capabilitiesOut);
1627
1996
  if (write) {
1628
1997
  mkdirSync(dirname3(capabilitiesPath), { recursive: true });
1629
1998
  writeFileSync(
@@ -1645,11 +2014,531 @@ var buildDocBridgeIndex = (opts) => {
1645
2014
  };
1646
2015
 
1647
2016
  // src/gates/run-gates.ts
1648
- import { readFileSync as readFileSync10 } from "fs";
2017
+ import { readFileSync as readFileSync9 } from "fs";
2018
+
2019
+ // src/conformance/documentation-standard-v1.ts
2020
+ import { existsSync as existsSync8, readFileSync as readFileSync7, realpathSync as realpathSync5, statSync as statSync3 } from "fs";
2021
+ import { isAbsolute as isAbsolute3, relative as relative3, resolve as resolve5, sep as sep4 } from "path";
2022
+
2023
+ // src/conformance/ecosystem-contract.ts
2024
+ import { z as z5 } from "zod";
2025
+ var NonEmptyStringSchema = z5.string().refine((value) => value.trim().length > 0, "must be non-empty");
2026
+ var HttpsUrlSchema = z5.string().url().refine((value) => value.startsWith("https://"), "must use https");
2027
+ var RepoSchema = z5.string().regex(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/);
2028
+ var SlugSchema = z5.string().regex(/^[a-z][a-z0-9-]*$/);
2029
+ var SurfaceSchema = z5.object({
2030
+ home: HttpsUrlSchema.optional(),
2031
+ docs: HttpsUrlSchema.optional(),
2032
+ llms: HttpsUrlSchema.optional(),
2033
+ stats: HttpsUrlSchema.optional(),
2034
+ documentation: z5.enum(["fumadocs", "repository"]),
2035
+ chat: z5.enum(["agentschat", "custom", "none"])
2036
+ }).passthrough();
2037
+ var ProductSchema = z5.object({
2038
+ id: SlugSchema,
2039
+ name: NonEmptyStringSchema,
2040
+ shortName: NonEmptyStringSchema,
2041
+ kind: NonEmptyStringSchema,
2042
+ role: NonEmptyStringSchema,
2043
+ promise: NonEmptyStringSchema,
2044
+ maturity: z5.enum(["planning", "alpha", "beta", "stable", "deprecated"]),
2045
+ repo: RepoSchema,
2046
+ accent: z5.string().regex(/^#[0-9A-Fa-f]{6}$/),
2047
+ surfaces: SurfaceSchema,
2048
+ navigation: z5.object({
2049
+ showInBar: z5.boolean(),
2050
+ order: z5.number().int().nonnegative().optional(),
2051
+ next: z5.array(SlugSchema)
2052
+ }).passthrough()
2053
+ }).passthrough();
2054
+ var LegacyPropertySchema = z5.object({
2055
+ id: SlugSchema,
2056
+ name: NonEmptyStringSchema,
2057
+ barLabel: NonEmptyStringSchema,
2058
+ domain: NonEmptyStringSchema,
2059
+ url: HttpsUrlSchema,
2060
+ repo: RepoSchema,
2061
+ tagline: NonEmptyStringSchema,
2062
+ kind: NonEmptyStringSchema,
2063
+ accent: z5.string().regex(/^#[0-9A-Fa-f]{6}$/),
2064
+ llms: HttpsUrlSchema.optional(),
2065
+ stats: HttpsUrlSchema.optional()
2066
+ }).passthrough();
2067
+ var ManifestSchema = z5.object({
2068
+ schemaVersion: z5.literal(2),
2069
+ parentBrand: z5.object({ id: NonEmptyStringSchema, name: NonEmptyStringSchema }).passthrough(),
2070
+ products: z5.array(ProductSchema).min(1),
2071
+ properties: z5.array(LegacyPropertySchema).length(4),
2072
+ builder: z5.object({ id: NonEmptyStringSchema, name: NonEmptyStringSchema, url: HttpsUrlSchema }).passthrough().optional()
2073
+ }).passthrough();
2074
+ var EvidenceSchema = z5.discriminatedUnion("type", [
2075
+ z5.object({
2076
+ type: z5.literal("repository-derivation"),
2077
+ repo: RepoSchema,
2078
+ path: NonEmptyStringSchema,
2079
+ summary: NonEmptyStringSchema
2080
+ }).passthrough(),
2081
+ z5.object({ type: z5.literal("endpoint"), url: HttpsUrlSchema, summary: NonEmptyStringSchema }).passthrough()
2082
+ ]);
2083
+ var ClaimSchema = z5.object({
2084
+ id: NonEmptyStringSchema,
2085
+ value: z5.number().finite().nonnegative(),
2086
+ noun: NonEmptyStringSchema,
2087
+ conservativeFloor: z5.number().int().nonnegative().optional(),
2088
+ evidence: EvidenceSchema
2089
+ }).passthrough();
2090
+ var ClaimProductSchema = z5.object({
2091
+ productId: SlugSchema,
2092
+ source: z5.discriminatedUnion("type", [
2093
+ z5.object({ type: z5.literal("endpoint"), url: HttpsUrlSchema }).passthrough(),
2094
+ z5.object({ type: z5.literal("repository"), repo: RepoSchema }).passthrough()
2095
+ ]),
2096
+ verification: z5.enum(["verified", "declared"]),
2097
+ claims: z5.array(ClaimSchema)
2098
+ }).passthrough();
2099
+ var ClaimsSchema = z5.object({
2100
+ schemaVersion: z5.literal(1),
2101
+ manifestSchemaVersion: z5.literal(2),
2102
+ products: z5.array(ClaimProductSchema)
2103
+ }).passthrough();
2104
+ var LEGACY_PRODUCT_IDS = ["agentskit", "akos", "playbook", "registry"];
2105
+ var parseCanonicalEcosystemContract = (manifestInput, claimsInput) => {
2106
+ const manifest = ManifestSchema.parse(manifestInput);
2107
+ const claims = ClaimsSchema.parse(claimsInput);
2108
+ const products = new Map(manifest.products.map((product) => [product.id, product]));
2109
+ if (products.size !== manifest.products.length) throw new Error("Manifest product IDs must be unique.");
2110
+ const navigationOrders = /* @__PURE__ */ new Set();
2111
+ for (const product of manifest.products) {
2112
+ if (product.surfaces.documentation === "fumadocs" && !product.surfaces.docs) {
2113
+ throw new Error(`Product ${product.id} requires a docs surface for Fumadocs.`);
2114
+ }
2115
+ if (product.navigation.showInBar) {
2116
+ if (!product.surfaces.home || product.navigation.order === void 0) {
2117
+ throw new Error(`Product ${product.id} requires home and order for shared navigation.`);
2118
+ }
2119
+ if (navigationOrders.has(product.navigation.order)) throw new Error("Navigation orders must be unique.");
2120
+ navigationOrders.add(product.navigation.order);
2121
+ }
2122
+ const next = new Set(product.navigation.next);
2123
+ if (next.size !== product.navigation.next.length || next.has(product.id)) {
2124
+ throw new Error(`Product ${product.id} has duplicate or self-referential navigation.`);
2125
+ }
2126
+ for (const nextId of next) {
2127
+ if (!products.has(nextId)) throw new Error(`Product ${product.id} references unknown product ${nextId}.`);
2128
+ }
2129
+ }
2130
+ for (const [index, id] of LEGACY_PRODUCT_IDS.entries()) {
2131
+ const legacy = manifest.properties[index];
2132
+ const product = products.get(id);
2133
+ if (!legacy || !product || legacy.id !== id || !product.surfaces.home) {
2134
+ throw new Error(`Legacy property ${index} must project product ${id}.`);
2135
+ }
2136
+ const expected = {
2137
+ name: product.name,
2138
+ barLabel: product.shortName,
2139
+ domain: new URL(product.surfaces.home).host,
2140
+ url: product.surfaces.home,
2141
+ repo: product.repo,
2142
+ tagline: product.promise,
2143
+ kind: product.kind,
2144
+ accent: product.accent,
2145
+ llms: product.surfaces.llms,
2146
+ stats: product.surfaces.stats
2147
+ };
2148
+ for (const [key, value] of Object.entries(expected)) {
2149
+ if (legacy[key] !== value) throw new Error(`Legacy ${id}.${key} must match v2.`);
2150
+ }
2151
+ }
2152
+ const claimProducts = new Map(claims.products.map((product) => [product.productId, product]));
2153
+ if (claimProducts.size !== claims.products.length || claimProducts.size !== products.size) {
2154
+ throw new Error("Claims must include every manifest product exactly once.");
2155
+ }
2156
+ for (const [productId, product] of products) {
2157
+ const claimProduct = claimProducts.get(productId);
2158
+ if (!claimProduct) throw new Error(`Claims are missing product ${productId}.`);
2159
+ if (claimProduct.source.type === "endpoint") {
2160
+ if (claimProduct.source.url !== product.surfaces.stats) throw new Error(`Claims source for ${productId} must match stats.`);
2161
+ } else if (claimProduct.source.repo !== product.repo) {
2162
+ throw new Error(`Claims source for ${productId} must match repo.`);
2163
+ }
2164
+ if (claimProduct.verification === "declared" && claimProduct.claims.length > 0) {
2165
+ throw new Error(`Declared product ${productId} cannot publish claims.`);
2166
+ }
2167
+ const claimIds = /* @__PURE__ */ new Set();
2168
+ for (const claim of claimProduct.claims) {
2169
+ if (claimIds.has(claim.id)) throw new Error(`Product ${productId} has duplicate claim ${claim.id}.`);
2170
+ claimIds.add(claim.id);
2171
+ if (claim.conservativeFloor !== void 0 && claim.conservativeFloor > claim.value) {
2172
+ throw new Error(`Claim ${productId}:${claim.id} has a floor above its value.`);
2173
+ }
2174
+ if (claim.evidence.type === "repository-derivation" && claim.evidence.repo !== product.repo) {
2175
+ throw new Error(`Claim ${productId}:${claim.id} evidence must match the product repo.`);
2176
+ }
2177
+ }
2178
+ }
2179
+ return { manifest, claims };
2180
+ };
2181
+
2182
+ // src/conformance/documentation-standard-v1.ts
2183
+ var DOCUMENTATION_STANDARD_V1_ID = "documentation-standard-v1";
2184
+ var DOCUMENTATION_STANDARD_V1_STATUS = "stable";
2185
+ var MAX_TEXT_EVIDENCE_BYTES = 4 * 1024 * 1024;
2186
+ var safePath = (root, path) => {
2187
+ const rootAbs = realpathSync5.native(resolve5(root));
2188
+ const unresolved = resolve5(rootAbs, path);
2189
+ const unresolvedRel = relative3(rootAbs, unresolved);
2190
+ if (isAbsolute3(unresolvedRel) || unresolvedRel === ".." || unresolvedRel.startsWith(`..${sep4}`)) return void 0;
2191
+ if (!existsSync8(unresolved)) return unresolved;
2192
+ try {
2193
+ const abs = realpathSync5.native(unresolved);
2194
+ const rel = relative3(rootAbs, abs);
2195
+ return !isAbsolute3(rel) && rel !== ".." && !rel.startsWith(`..${sep4}`) ? abs : void 0;
2196
+ } catch {
2197
+ return void 0;
2198
+ }
2199
+ };
2200
+ var fileEvidence = (root, path, options) => {
2201
+ const abs = safePath(root, path);
2202
+ if (!abs) {
2203
+ return {
2204
+ exists: false,
2205
+ content: "",
2206
+ evidence: { path, detail: "Path escapes the project root." }
2207
+ };
2208
+ }
2209
+ if (!existsSync8(abs)) {
2210
+ return { exists: false, content: "", evidence: { path, detail: "File does not exist." } };
2211
+ }
2212
+ try {
2213
+ const stat = statSync3(abs);
2214
+ if (!stat.isFile()) {
2215
+ return { exists: false, content: "", evidence: { path, detail: "Path is not a regular file." } };
2216
+ }
2217
+ if (stat.size === 0) {
2218
+ return { exists: false, content: "", evidence: { path, detail: "File is empty." } };
2219
+ }
2220
+ if (options?.readContent === false) {
2221
+ return {
2222
+ exists: true,
2223
+ content: "",
2224
+ evidence: { path: toPosix(relative3(resolve5(root), abs)) || ".", detail: "File exists and is non-empty." }
2225
+ };
2226
+ }
2227
+ if (stat.size > MAX_TEXT_EVIDENCE_BYTES) {
2228
+ return {
2229
+ exists: false,
2230
+ content: "",
2231
+ evidence: { path, detail: `Text evidence exceeds ${MAX_TEXT_EVIDENCE_BYTES} bytes.` }
2232
+ };
2233
+ }
2234
+ const content = readFileSync7(abs, "utf8");
2235
+ return {
2236
+ exists: content.trim().length > 0,
2237
+ content,
2238
+ evidence: {
2239
+ path: toPosix(relative3(resolve5(root), abs)) || ".",
2240
+ detail: content.trim().length > 0 ? "File exists and is non-empty." : "File is empty."
2241
+ }
2242
+ };
2243
+ } catch {
2244
+ return { exists: false, content: "", evidence: { path, detail: "File is not readable text." } };
2245
+ }
2246
+ };
2247
+ var resultWithException = (draft, options) => {
2248
+ if (draft.passed) {
2249
+ const { passed: _passed2, ...result2 } = draft;
2250
+ return { ...result2, status: "pass", ok: true };
2251
+ }
2252
+ const exception = options.exceptions?.find((candidate) => candidate.ruleId === draft.id);
2253
+ const { passed: _passed, ...result } = draft;
2254
+ if (!exception) return { ...result, status: "fail", ok: false };
2255
+ return {
2256
+ ...result,
2257
+ status: "excepted",
2258
+ ok: true,
2259
+ exception: {
2260
+ reason: exception.reason,
2261
+ approvedBy: exception.approvedBy,
2262
+ trackingUrl: exception.trackingUrl
2263
+ }
2264
+ };
2265
+ };
2266
+ var humanDocsRule = (root, config) => {
2267
+ const docs = scanHumanDocRecords(root, config);
2268
+ return {
2269
+ id: "human-docs",
2270
+ level: "required",
2271
+ passed: docs.length > 0,
2272
+ message: docs.length > 0 ? `Found ${docs.length} human document(s).` : "No human documentation was discovered.",
2273
+ evidence: docs.slice(0, 10).map((doc) => ({
2274
+ path: toPosix(relative3(resolve5(root), doc.path)),
2275
+ detail: `Human route: ${doc.url}`
2276
+ })),
2277
+ remediation: {
2278
+ command: "edit doc-bridge.config.json",
2279
+ detail: "Configure corpus.human with a supported adapter and a non-agent documentation root."
2280
+ }
2281
+ };
2282
+ };
2283
+ var llmsRule = (root, config, options) => {
2284
+ const llmsPath = config.index?.llmsTxt?.outFile ?? "llms.txt";
2285
+ const llmsKey = safePath(root, llmsPath) ?? resolve5(root, llmsPath);
2286
+ const rawSources = /* @__PURE__ */ new Map();
2287
+ for (const path of options.rawSources ?? []) {
2288
+ const key = safePath(root, path) ?? resolve5(root, path);
2289
+ if (key !== llmsKey && !rawSources.has(key)) rawSources.set(key, path);
2290
+ }
2291
+ const paths = [llmsPath, ...rawSources.values()];
2292
+ const evidence = paths.map((path) => fileEvidence(root, path));
2293
+ const generated = buildDocBridgeIndex({ root, config, write: false }).index;
2294
+ const expectedLlms = renderLlmsTxt(config, generated.knowledge, generated.project?.name ?? "project");
2295
+ const llmsIsFresh = evidence[0]?.content === expectedLlms;
2296
+ if (evidence[0]?.exists) {
2297
+ evidence[0] = {
2298
+ ...evidence[0],
2299
+ evidence: {
2300
+ ...evidence[0].evidence,
2301
+ detail: llmsIsFresh ? "File matches the deterministic ak-docs output." : "File is stale or was not generated by the current ak-docs inputs."
2302
+ }
2303
+ };
2304
+ }
2305
+ const passed = config.index?.llmsTxt?.enabled !== false && paths.length > 1 && llmsIsFresh && evidence.every((item) => item.exists);
2306
+ return {
2307
+ id: "llms-and-raw-source",
2308
+ level: "required",
2309
+ passed,
2310
+ message: passed ? `Resolved llms.txt and ${paths.length - 1} raw source(s).` : "llms.txt must be enabled, current, and accompanied by at least one readable raw source.",
2311
+ evidence: evidence.map((item) => item.evidence),
2312
+ remediation: {
2313
+ command: "ak-docs index",
2314
+ detail: "Generate llms.txt and configure conformance.documentationStandardV1.rawSources."
2315
+ }
2316
+ };
2317
+ };
2318
+ var normalizedUrl = (value) => value.replace(/\/$/, "");
2319
+ var ecosystemContract = (root, options) => {
2320
+ const declaration = options.ecosystemContract;
2321
+ if (!declaration) {
2322
+ return {
2323
+ passed: false,
2324
+ urls: /* @__PURE__ */ new Set(),
2325
+ evidence: [{ path: "doc-bridge.config.json", detail: "Canonical ecosystem contract evidence is not declared." }]
2326
+ };
2327
+ }
2328
+ const manifestFile = fileEvidence(root, declaration.manifest);
2329
+ const claimsFile = fileEvidence(root, declaration.claims);
2330
+ const evidence = [manifestFile.evidence, claimsFile.evidence];
2331
+ if (!manifestFile.exists || !claimsFile.exists) return { passed: false, urls: /* @__PURE__ */ new Set(), evidence };
2332
+ try {
2333
+ const manifest = JSON.parse(manifestFile.content);
2334
+ const claims = JSON.parse(claimsFile.content);
2335
+ const contract = parseCanonicalEcosystemContract(manifest, claims);
2336
+ const productIds = contract.manifest.products.map((product) => product.id);
2337
+ if (!productIds.includes(declaration.productId)) throw new Error(`Manifest is missing product ${declaration.productId}.`);
2338
+ const urls = /* @__PURE__ */ new Set();
2339
+ for (const product of contract.manifest.products) {
2340
+ for (const value of [
2341
+ product.surfaces.home,
2342
+ product.surfaces.docs,
2343
+ product.surfaces.llms,
2344
+ product.surfaces.stats
2345
+ ]) {
2346
+ if (typeof value === "string" && /^https:\/\//.test(value)) urls.add(normalizedUrl(value));
2347
+ }
2348
+ }
2349
+ evidence[0] = { path: declaration.manifest, detail: `Validated ${productIds.length} canonical product(s), including ${declaration.productId}.` };
2350
+ evidence[1] = { path: declaration.claims, detail: `Validated claim-ledger identity for ${contract.claims.products.length} product(s).` };
2351
+ return { passed: urls.size > 0, urls, evidence };
2352
+ } catch (error) {
2353
+ evidence.push({
2354
+ path: `${declaration.manifest}, ${declaration.claims}`,
2355
+ detail: error instanceof Error ? error.message : "Canonical ecosystem contract is invalid."
2356
+ });
2357
+ return { passed: false, urls: /* @__PURE__ */ new Set(), evidence };
2358
+ }
2359
+ };
2360
+ var handoffsRule = (root, config) => {
2361
+ const index = buildDocBridgeIndex({ root, config, write: false }).index;
2362
+ const handoffs = Object.values(index.handoffs ?? {});
2363
+ const ready = handoffs.filter(
2364
+ (handoff) => handoff.startHere.length > 0 && handoff.editRoots.length > 0 && handoff.checks.length > 0 && (handoff.bridge?.humanDoc === "linked" || handoff.bridge?.humanDoc === "external")
2365
+ );
2366
+ return {
2367
+ id: "agent-handoffs",
2368
+ level: "required",
2369
+ passed: ready.length > 0 && ready.length === handoffs.length,
2370
+ message: ready.length > 0 && ready.length === handoffs.length ? `${ready.length} handoff(s) are action-ready and human-linked.` : `${ready.length}/${handoffs.length} handoff(s) are action-ready and human-linked.`,
2371
+ evidence: handoffs.map((handoff) => ({
2372
+ path: handoff.startHere,
2373
+ detail: `${handoff.target.id}: ${handoff.editRoots.length} edit root(s), ${handoff.checks.length} check(s), bridge=${handoff.bridge?.humanDoc ?? "none"}`
2374
+ })),
2375
+ remediation: {
2376
+ command: "ak-docs bootstrap agent-docs && ak-docs index",
2377
+ detail: "Add ownership checks and a resolvable humanDoc for every handoff."
2378
+ }
2379
+ };
2380
+ };
2381
+ var contributionRule = (root, options) => {
2382
+ const paths = options.contributionPaths?.length ? options.contributionPaths : ["CONTRIBUTING.md"];
2383
+ const evidence = paths.map((path) => fileEvidence(root, path));
2384
+ return {
2385
+ id: "contribution",
2386
+ level: "required",
2387
+ passed: evidence.some((item) => item.exists),
2388
+ message: evidence.some((item) => item.exists) ? "Contribution guidance is available." : "Contribution guidance is missing.",
2389
+ evidence: evidence.map((item) => item.evidence),
2390
+ remediation: {
2391
+ command: "edit CONTRIBUTING.md",
2392
+ detail: "Document setup, validation commands, and the pull-request workflow."
2393
+ }
2394
+ };
2395
+ };
2396
+ var markersRule = (root, options, kind, level) => {
2397
+ const declarations = options[kind === "metadata" ? "metadata" : "diagrams"] ?? [];
2398
+ const evidence = [];
2399
+ let passed = declarations.length > 0;
2400
+ for (const declaration of declarations) {
2401
+ const file = fileEvidence(root, declaration.path);
2402
+ const missing = declaration.contains.filter((marker) => !file.content.includes(marker));
2403
+ if (!file.exists || missing.length > 0) passed = false;
2404
+ evidence.push({
2405
+ path: declaration.path,
2406
+ detail: !file.exists ? file.evidence.detail : missing.length ? `Missing marker(s): ${missing.join(", ")}` : `Found marker(s): ${declaration.contains.join(", ")}`
2407
+ });
2408
+ }
2409
+ return {
2410
+ id: kind,
2411
+ level,
2412
+ passed,
2413
+ message: passed ? `${kind} evidence is complete.` : `${kind} evidence is incomplete.`,
2414
+ evidence,
2415
+ remediation: {
2416
+ command: "edit doc-bridge.config.json",
2417
+ detail: `Declare ${kind} evidence paths and markers that exist in the repository.`
2418
+ }
2419
+ };
2420
+ };
2421
+ var linksRule = (root, options) => {
2422
+ const links = options.links ?? [];
2423
+ const contract = ecosystemContract(root, options);
2424
+ const evidence = [...contract.evidence];
2425
+ let passed = links.length > 0 && contract.passed;
2426
+ for (const link of links) {
2427
+ const sources = link.paths.map((path) => ({ path, file: fileEvidence(root, path) }));
2428
+ const matches = sources.filter(({ file }) => file.exists && file.content.includes(link.url));
2429
+ const canonical = contract.urls.has(normalizedUrl(link.url));
2430
+ if (matches.length === 0 || !canonical) passed = false;
2431
+ evidence.push({
2432
+ path: sources.map((source) => source.path).join(", "),
2433
+ detail: matches.length === 0 ? `Missing ${link.url}` : canonical ? `Found canonical ecosystem URL ${link.url}` : `Found ${link.url}, but it is absent from the canonical ecosystem manifest.`
2434
+ });
2435
+ }
2436
+ return {
2437
+ id: "cross-links",
2438
+ level: "required",
2439
+ passed,
2440
+ message: passed ? `${links.length} required ecosystem link(s) resolve in source.` : "One or more required ecosystem links are missing from source.",
2441
+ evidence,
2442
+ remediation: {
2443
+ command: "edit README.md",
2444
+ detail: "Sync the canonical ecosystem snapshots and add each configured canonical URL to a declared documentation source."
2445
+ }
2446
+ };
2447
+ };
2448
+ var quickstartsRule = (root, options) => {
2449
+ const quickstarts = options.quickstarts ?? [];
2450
+ const evidence = [];
2451
+ let passed = quickstarts.length > 0;
2452
+ for (const quickstart of quickstarts) {
2453
+ const doc = fileEvidence(root, quickstart.doc);
2454
+ const test = fileEvidence(root, quickstart.test);
2455
+ const missingMarkers = quickstart.testContains.filter((marker) => !test.content.includes(marker));
2456
+ if (!doc.exists || !test.exists || missingMarkers.length > 0 || !quickstart.command.trim()) passed = false;
2457
+ evidence.push(
2458
+ { path: quickstart.doc, detail: `${quickstart.id}: ${doc.evidence.detail}` },
2459
+ {
2460
+ path: quickstart.test,
2461
+ detail: missingMarkers.length ? `${quickstart.id}: missing test marker(s): ${missingMarkers.join(", ")}` : `${quickstart.id}: test evidence; CI command: ${quickstart.command}`
2462
+ }
2463
+ );
2464
+ }
2465
+ return {
2466
+ id: "tested-quickstarts",
2467
+ level: "required",
2468
+ passed,
2469
+ message: passed ? `${quickstarts.length} quickstart(s) have executable test evidence.` : "Quickstart test evidence is incomplete.",
2470
+ evidence,
2471
+ remediation: {
2472
+ command: "pnpm test",
2473
+ detail: "Map every quickstart to a documentation path, test file, identifying marker, and CI command."
2474
+ }
2475
+ };
2476
+ };
2477
+ var visualsRule = (root, options) => {
2478
+ const visuals = options.visuals ?? [];
2479
+ const evidence = visuals.map((path) => fileEvidence(root, path, { readContent: false }));
2480
+ return {
2481
+ id: "visual-explanations",
2482
+ level: "recommended",
2483
+ passed: visuals.length > 0 && evidence.every((item) => item.exists),
2484
+ message: visuals.length > 0 && evidence.every((item) => item.exists) ? `${visuals.length} visual asset(s) found.` : "Visual explanation evidence is incomplete.",
2485
+ evidence: evidence.map((item) => item.evidence),
2486
+ remediation: {
2487
+ command: "edit doc-bridge.config.json",
2488
+ detail: "Declare the images or animations that explain the product workflow."
2489
+ }
2490
+ };
2491
+ };
2492
+ var count = (results, level, status) => results.filter((result) => result.level === level && result.status === status).length;
2493
+ var runDocumentationStandardV1 = (root, config) => {
2494
+ const options = config.conformance?.documentationStandardV1 ?? {};
2495
+ const drafts = [
2496
+ humanDocsRule(root, config),
2497
+ llmsRule(root, config, options),
2498
+ handoffsRule(root, config),
2499
+ contributionRule(root, options),
2500
+ markersRule(root, options, "metadata", "required"),
2501
+ linksRule(root, options),
2502
+ quickstartsRule(root, options),
2503
+ visualsRule(root, options),
2504
+ markersRule(root, options, "structured-diagrams", "recommended")
2505
+ ];
2506
+ const results = drafts.map((draft) => resultWithException(draft, options));
2507
+ return {
2508
+ schemaVersion: 1,
2509
+ profile: { id: DOCUMENTATION_STANDARD_V1_ID, version: 1, status: DOCUMENTATION_STANDARD_V1_STATUS },
2510
+ ok: results.filter((result) => result.level === "required").every((result) => result.ok),
2511
+ recommendedOk: results.filter((result) => result.level === "recommended").every((result) => result.ok),
2512
+ summary: {
2513
+ required: {
2514
+ passed: count(results, "required", "pass"),
2515
+ failed: count(results, "required", "fail"),
2516
+ excepted: count(results, "required", "excepted")
2517
+ },
2518
+ recommended: {
2519
+ passed: count(results, "recommended", "pass"),
2520
+ failed: count(results, "recommended", "fail"),
2521
+ excepted: count(results, "recommended", "excepted")
2522
+ }
2523
+ },
2524
+ results
2525
+ };
2526
+ };
2527
+ var formatDocumentationStandardText = (report) => [
2528
+ `Documentation Standard v1 (${report.profile.status})`,
2529
+ `Required: ${report.summary.required.passed} passed \xB7 ${report.summary.required.failed} failed \xB7 ${report.summary.required.excepted} excepted`,
2530
+ `Recommended: ${report.summary.recommended.passed} passed \xB7 ${report.summary.recommended.failed} failed \xB7 ${report.summary.recommended.excepted} excepted`,
2531
+ "",
2532
+ ...report.results.flatMap((result) => [
2533
+ `${result.status === "pass" ? "PASS" : result.status === "excepted" ? "EXCEPTED" : "FAIL"} [${result.level}] ${result.id}: ${result.message}`,
2534
+ ...result.evidence.map((evidence) => ` evidence: ${evidence.path} \u2014 ${evidence.detail}`),
2535
+ ...result.exception ? [` exception: ${result.exception.reason} \u2014 ${result.exception.approvedBy} (${result.exception.trackingUrl})`] : result.ok ? [] : [` fix: ${result.remediation.command} \u2014 ${result.remediation.detail}`]
2536
+ ])
2537
+ ];
1649
2538
 
1650
2539
  // src/query/load-index.ts
1651
- import { existsSync as existsSync7, readFileSync as readFileSync9 } from "fs";
1652
- import { join as join11, resolve as resolve3 } from "path";
2540
+ import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
2541
+ import { join as join8, resolve as resolve6 } from "path";
1653
2542
  var IndexNotFoundError = class extends Error {
1654
2543
  constructor(path) {
1655
2544
  super(`Missing index at ${path}. Run: ak-docs index`);
@@ -1658,18 +2547,29 @@ var IndexNotFoundError = class extends Error {
1658
2547
  }
1659
2548
  path;
1660
2549
  };
1661
- var indexFilePath = (root, config) => join11(root, config.index?.outFile ?? ".doc-bridge/index.json");
2550
+ var indexFilePath = (root, config) => join8(root, config.index?.outFile ?? ".doc-bridge/index.json");
1662
2551
  var loadDocBridgeIndex = (root, config) => {
1663
2552
  const path = indexFilePath(root, config);
1664
- if (!existsSync7(path)) throw new IndexNotFoundError(path);
1665
- const raw = JSON.parse(readFileSync9(path, "utf8"));
2553
+ if (!existsSync9(path)) throw new IndexNotFoundError(path);
2554
+ const raw = JSON.parse(readFileSync8(path, "utf8"));
1666
2555
  return parseDocBridgeIndex(raw);
1667
2556
  };
1668
- var resolveRoot = (cwd) => resolve3(cwd ?? process.cwd());
2557
+ var resolveRoot = (cwd) => resolve6(cwd ?? process.cwd());
1669
2558
 
1670
2559
  // src/gates/run-gates.ts
1671
- var SUPPORTED_GATES = ["index-freshness", "human-guide-links", "okf-type", "docs-style"];
2560
+ var RESERVED_GATE_IDS = /* @__PURE__ */ new Set(["link-rot", "routing-currency", "bootstrap-size"]);
1672
2561
  var runGate = (root, config, id) => {
2562
+ if (id === "documentation-standard-v1") {
2563
+ const details = runDocumentationStandardV1(root, config);
2564
+ return {
2565
+ id,
2566
+ ok: details.ok,
2567
+ message: details.ok ? "Documentation Standard v1 required rules pass" : `${details.summary.required.failed} Documentation Standard v1 required rule(s) failed`,
2568
+ expected: "all required rules pass or have approved exceptions",
2569
+ actual: `${details.summary.required.passed} passed, ${details.summary.required.failed} failed, ${details.summary.required.excepted} excepted`,
2570
+ details
2571
+ };
2572
+ }
1673
2573
  if (id === "human-guide-links") return runHumanGuideLinksGate(root, config);
1674
2574
  if (id === "okf-type") return runOkfTypeGate(root, config);
1675
2575
  if (id === "docs-style") return runDocsStyleGate(root, config);
@@ -1727,7 +2627,7 @@ var runOkfTypeGate = (root, config) => {
1727
2627
  const required = config.corpus.agent.okf?.requireType ?? config.gates?.preset === "strict";
1728
2628
  if (!required) return { id: "okf-type", ok: true, message: "OKF type frontmatter not required" };
1729
2629
  const allowed = config.corpus.agent.okf?.allowedTypes;
1730
- const bad = scanAgentCorpus(root, config).filter((doc) => doc.path !== config.corpus.agent.index).map((doc) => ({ path: doc.path, type: frontmatterType(readFileSync10(doc.absPath, "utf8")) })).filter((doc) => !doc.type || allowed && !allowed.includes(doc.type));
2630
+ const bad = scanAgentCorpus(root, config).filter((doc) => doc.path !== config.corpus.agent.index).map((doc) => ({ path: doc.path, type: frontmatterType(readFileSync9(doc.absPath, "utf8")) })).filter((doc) => !doc.type || allowed && !allowed.includes(doc.type));
1731
2631
  if (bad.length) {
1732
2632
  return {
1733
2633
  id: "okf-type",
@@ -1801,7 +2701,7 @@ var runDocsStyleGate = (root, config) => {
1801
2701
  }
1802
2702
  const bad = scanAgentCorpus(root, config).filter((doc) => doc.path !== config.corpus.agent.index).map((doc) => ({
1803
2703
  path: doc.path,
1804
- missing: missingStyleRules(readFileSync10(doc.absPath, "utf8"), required)
2704
+ missing: missingStyleRules(readFileSync9(doc.absPath, "utf8"), required)
1805
2705
  })).filter((doc) => doc.missing.length > 0);
1806
2706
  if (bad.length) {
1807
2707
  return {
@@ -1831,18 +2731,24 @@ var resolveGateIds = (config) => {
1831
2731
  ) : ["index-freshness", "human-guide-links"]
1832
2732
  );
1833
2733
  for (const id of config.gates?.include ?? []) {
1834
- if (SUPPORTED_GATES.includes(id)) ids.add(id);
2734
+ if (RESERVED_GATE_IDS.has(id)) {
2735
+ process.emitWarning(`Gate "${id}" is reserved and has no runtime implementation; it was not executed.`, {
2736
+ code: "AK_DOCS_RESERVED_GATE"
2737
+ });
2738
+ continue;
2739
+ }
2740
+ ids.add(id);
1835
2741
  }
1836
2742
  for (const id of config.gates?.exclude ?? []) {
1837
- if (SUPPORTED_GATES.includes(id)) ids.delete(id);
2743
+ if (!RESERVED_GATE_IDS.has(id)) ids.delete(id);
1838
2744
  }
1839
2745
  return [...ids];
1840
2746
  };
1841
2747
 
1842
2748
  // src/mcp/server.ts
1843
- import { readFileSync as readFileSync12, realpathSync } from "fs";
1844
- import { relative, resolve as resolve4 } from "path";
1845
- import { z as z5, ZodError } from "zod";
2749
+ import { readFileSync as readFileSync11, realpathSync as realpathSync6 } from "fs";
2750
+ import { relative as relative4, resolve as resolve7 } from "path";
2751
+ import { z as z6, ZodError } from "zod";
1846
2752
 
1847
2753
  // src/query/search.ts
1848
2754
  var tokenize = (value) => value.toLowerCase().split(/[^a-z0-9@/_-]+/).filter((t) => t.length >= 2);
@@ -1960,15 +2866,15 @@ var createDocBridgeRetriever = (index, options = {}) => ({
1960
2866
  });
1961
2867
 
1962
2868
  // src/memory/ingest.ts
1963
- import { existsSync as existsSync8, readFileSync as readFileSync11 } from "fs";
1964
- import { join as join12 } from "path";
2869
+ import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
2870
+ import { join as join9 } from "path";
1965
2871
  var memoryFact = (raw, id) => firstParagraph(raw) ?? firstHeading(raw) ?? id;
1966
2872
  var relativePath = (root, abs) => toPosix(abs).replace(`${toPosix(root)}/`, "");
1967
2873
  var ingestMarkdownDir = (root, dir, source, confidence) => {
1968
- if (!existsSync8(dir)) return [];
2874
+ if (!existsSync10(dir)) return [];
1969
2875
  return walkFiles(dir, { extensions: [".md", ".mdc"] }).map((abs) => {
1970
2876
  const rel = relativePath(root, abs);
1971
- const raw = readFileSync11(abs, "utf8");
2877
+ const raw = readFileSync10(abs, "utf8");
1972
2878
  const id = slugFromPath(rel);
1973
2879
  return {
1974
2880
  schemaVersion: 1,
@@ -1983,10 +2889,10 @@ var ingestMarkdownDir = (root, dir, source, confidence) => {
1983
2889
  });
1984
2890
  };
1985
2891
  var ingestCursorRules = (root) => {
1986
- const dir = join12(root, ".cursor", "rules");
2892
+ const dir = join9(root, ".cursor", "rules");
1987
2893
  return ingestMarkdownDir(root, dir, "cursor", 0.6);
1988
2894
  };
1989
- var ingestAgentMemory = (root) => ingestMarkdownDir(root, join12(root, ".agent-memory"), "agent-memory", 0.7);
2895
+ var ingestAgentMemory = (root) => ingestMarkdownDir(root, join9(root, ".agent-memory"), "agent-memory", 0.7);
1990
2896
  var ingestMemoryCandidates = (root) => [
1991
2897
  ...ingestAgentMemory(root),
1992
2898
  ...ingestCursorRules(root)
@@ -2240,21 +3146,21 @@ var MCP_TOOLS = [
2240
3146
  }
2241
3147
  ];
2242
3148
  var asRecord = (value) => value && typeof value === "object" ? value : {};
2243
- var HandoffResolveArgsSchema = z5.object({
2244
- id: z5.string().min(1),
2245
- kind: z5.enum(["package", "ownership"]).optional()
3149
+ var HandoffResolveArgsSchema = z6.object({
3150
+ id: z6.string().min(1),
3151
+ kind: z6.enum(["package", "ownership"]).optional()
2246
3152
  });
2247
- var DocSearchArgsSchema = z5.object({
2248
- term: z5.string().min(1),
2249
- limit: z5.number().int().positive().max(100).optional()
3153
+ var DocSearchArgsSchema = z6.object({
3154
+ term: z6.string().min(1),
3155
+ limit: z6.number().int().positive().max(100).optional()
2250
3156
  });
2251
- var RetrieverQueryArgsSchema = z5.object({
2252
- query: z5.string().min(1),
2253
- limit: z5.number().int().positive().max(100).optional()
3157
+ var RetrieverQueryArgsSchema = z6.object({
3158
+ query: z6.string().min(1),
3159
+ limit: z6.number().int().positive().max(100).optional()
2254
3160
  });
2255
- var DocGetArgsSchema = z5.object({
2256
- id: z5.string().min(1).optional(),
2257
- path: z5.string().min(1).optional()
3161
+ var DocGetArgsSchema = z6.object({
3162
+ id: z6.string().min(1).optional(),
3163
+ path: z6.string().min(1).optional()
2258
3164
  }).refine((args) => args.id || args.path, "doc.get requires id or path");
2259
3165
  var parseToolArgs = (tool, schema, value) => {
2260
3166
  try {
@@ -2286,12 +3192,12 @@ var findDocPath = (index, args) => {
2286
3192
  return doc.path;
2287
3193
  };
2288
3194
  var resolveDocPath = (root, relPath) => {
2289
- const rootAbs = realpathSync.native(root);
2290
- const unresolved = resolve4(rootAbs, relPath);
2291
- const unresolvedRel = relative(rootAbs, unresolved);
3195
+ const rootAbs = realpathSync6.native(root);
3196
+ const unresolved = resolve7(rootAbs, relPath);
3197
+ const unresolvedRel = relative4(rootAbs, unresolved);
2292
3198
  if (unresolvedRel.startsWith("..")) throw new Error("doc.get path escapes project root");
2293
- const abs = realpathSync.native(unresolved);
2294
- const rel = relative(rootAbs, abs);
3199
+ const abs = realpathSync6.native(unresolved);
3200
+ const rel = relative4(rootAbs, abs);
2295
3201
  if (rel.startsWith("..")) throw new Error("doc.get path escapes project root");
2296
3202
  return abs;
2297
3203
  };
@@ -2325,7 +3231,7 @@ var handleMcpRequest = (ctx, request) => {
2325
3231
  }
2326
3232
  if (name === "doc.get") {
2327
3233
  const relPath = findDocPath(index(), parseToolArgs("doc.get", DocGetArgsSchema, args));
2328
- return textResult(readFileSync12(resolveDocPath(ctx.root, relPath), "utf8"));
3234
+ return textResult(readFileSync11(resolveDocPath(ctx.root, relPath), "utf8"));
2329
3235
  }
2330
3236
  if (name === "gate.status") return textResult(runGates(ctx.root, ctx.config));
2331
3237
  if (name === "retriever.query") {
@@ -2403,9 +3309,9 @@ var startMcpStdioServer = (ctx) => {
2403
3309
  };
2404
3310
 
2405
3311
  // src/mcp/install.ts
2406
- import { existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as readFileSync13, writeFileSync as writeFileSync2 } from "fs";
3312
+ import { existsSync as existsSync11, mkdirSync as mkdirSync2, readFileSync as readFileSync12, writeFileSync as writeFileSync2 } from "fs";
2407
3313
  import { homedir } from "os";
2408
- import { dirname as dirname4, join as join13, resolve as resolve5 } from "path";
3314
+ import { dirname as dirname4, join as join10, resolve as resolve8 } from "path";
2409
3315
  var SERVER_NAME = "ak-docs";
2410
3316
  var mcpServerEntry = (root) => ({
2411
3317
  command: "npx",
@@ -2413,9 +3319,9 @@ var mcpServerEntry = (root) => ({
2413
3319
  cwd: root
2414
3320
  });
2415
3321
  var readJson = (path) => {
2416
- if (!existsSync9(path)) return {};
3322
+ if (!existsSync11(path)) return {};
2417
3323
  try {
2418
- const parsed = JSON.parse(readFileSync13(path, "utf8"));
3324
+ const parsed = JSON.parse(readFileSync12(path, "utf8"));
2419
3325
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
2420
3326
  } catch {
2421
3327
  return {};
@@ -2427,12 +3333,12 @@ var writeJson = (path, value) => {
2427
3333
  `, "utf8");
2428
3334
  };
2429
3335
  var resolveTargetPath = (target, root) => {
2430
- if (target === "cursor") return resolve5(root, ".cursor", "mcp.json");
2431
- return join13(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
3336
+ if (target === "cursor") return resolve8(root, ".cursor", "mcp.json");
3337
+ return join10(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
2432
3338
  };
2433
3339
  var installMcpConfig = (root, target) => {
2434
3340
  const configPath = resolveTargetPath(target, root);
2435
- const created = !existsSync9(configPath);
3341
+ const created = !existsSync11(configPath);
2436
3342
  const existing = readJson(configPath);
2437
3343
  const servers = existing.mcpServers && typeof existing.mcpServers === "object" && !Array.isArray(existing.mcpServers) ? { ...existing.mcpServers } : {};
2438
3344
  servers[SERVER_NAME] = mcpServerEntry(root);
@@ -2698,22 +3604,22 @@ var formatDoctorText = (report) => {
2698
3604
  };
2699
3605
 
2700
3606
  // src/index-builder/watch-index.ts
2701
- import { existsSync as existsSync10, watch } from "fs";
2702
- import { dirname as dirname5, resolve as resolve6 } from "path";
3607
+ import { existsSync as existsSync12, watch } from "fs";
3608
+ import { dirname as dirname5, resolve as resolve9 } from "path";
2703
3609
  var WATCH_PATTERN = /\.(md|mdx|json|ya?ml|mdc)$/i;
2704
3610
  var collectWatchRoots = (root, config, configPath) => {
2705
3611
  const roots = /* @__PURE__ */ new Set();
2706
- roots.add(resolve6(root, config.corpus.agent.root));
3612
+ roots.add(resolve9(root, config.corpus.agent.root));
2707
3613
  const humanSources = config.corpus.human ? Array.isArray(config.corpus.human) ? config.corpus.human : [config.corpus.human] : [];
2708
3614
  for (const source of humanSources) {
2709
3615
  const humanOpts = source.options ?? {};
2710
3616
  for (const key of ["contentDir", "docsDir", "root"]) {
2711
3617
  const value = humanOpts[key];
2712
- if (typeof value === "string" && value.length) roots.add(resolve6(root, value));
3618
+ if (typeof value === "string" && value.length) roots.add(resolve9(root, value));
2713
3619
  }
2714
3620
  }
2715
- if (configPath) roots.add(dirname5(resolve6(configPath)));
2716
- return [...roots].filter((dir) => existsSync10(dir));
3621
+ if (configPath) roots.add(dirname5(resolve9(configPath)));
3622
+ return [...roots].filter((dir) => existsSync12(dir));
2717
3623
  };
2718
3624
  var watchDocBridgeIndex = (opts) => {
2719
3625
  const debounceMs = opts.debounceMs ?? 350;
@@ -2754,8 +3660,8 @@ var watchDocBridgeIndex = (opts) => {
2754
3660
  rebuild();
2755
3661
  });
2756
3662
  }
2757
- const configDir = resolve6(opts.root);
2758
- if (existsSync10(configDir)) {
3663
+ const configDir = resolve9(opts.root);
3664
+ if (existsSync12(configDir)) {
2759
3665
  watch(configDir, (_event, filename) => {
2760
3666
  if (!filename || !/doc-bridge\.config/.test(filename)) return;
2761
3667
  rebuild();
@@ -2774,8 +3680,8 @@ var watchDocBridgeIndex = (opts) => {
2774
3680
 
2775
3681
  // src/memory/github-pr.ts
2776
3682
  import { execFileSync, spawnSync } from "child_process";
2777
- import { existsSync as existsSync11, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
2778
- import { join as join15 } from "path";
3683
+ import { existsSync as existsSync13, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
3684
+ import { join as join12 } from "path";
2779
3685
  var run = (cmd, args, cwd) => {
2780
3686
  const result = spawnSync(cmd, [...args], { cwd, encoding: "utf8" });
2781
3687
  const out = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
@@ -2783,10 +3689,10 @@ var run = (cmd, args, cwd) => {
2783
3689
  };
2784
3690
  var hasGh = () => run("gh", ["--version"], process.cwd()).ok;
2785
3691
  var slug = () => (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
2786
- var defaultPromotionDraftPath = (root) => join15(root, ".doc-bridge", "drafts", `memory-promotion-${slug()}.md`);
3692
+ var defaultPromotionDraftPath = (root) => join12(root, ".doc-bridge", "drafts", `memory-promotion-${slug()}.md`);
2787
3693
  var writePromotionDraft = (root, draft, path) => {
2788
3694
  const draftPath = path ?? defaultPromotionDraftPath(root);
2789
- mkdirSync3(join15(root, ".doc-bridge", "drafts"), { recursive: true });
3695
+ mkdirSync3(join12(root, ".doc-bridge", "drafts"), { recursive: true });
2790
3696
  writeFileSync3(draftPath, `${draft.body}
2791
3697
  `, "utf8");
2792
3698
  return draftPath;
@@ -2822,7 +3728,7 @@ var promoteMemoryToGithubPr = (root, draft, options = {}) => {
2822
3728
  message: `Wrote draft to ${relDraft}. Run the printed git/gh commands to open a draft PR.`
2823
3729
  };
2824
3730
  }
2825
- if (!existsSync11(join15(root, ".git"))) {
3731
+ if (!existsSync13(join12(root, ".git"))) {
2826
3732
  return {
2827
3733
  ok: false,
2828
3734
  dryRun: false,
@@ -2925,8 +3831,8 @@ ${auth.out}`
2925
3831
  };
2926
3832
 
2927
3833
  // src/federation/llms.ts
2928
- import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
2929
- import { resolve as resolve7 } from "path";
3834
+ import { existsSync as existsSync14, readFileSync as readFileSync13 } from "fs";
3835
+ import { resolve as resolve10 } from "path";
2930
3836
  var tokenize2 = (value) => value.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length >= 2);
2931
3837
  var scoreText = (query, text) => {
2932
3838
  const hay = text.toLowerCase();
@@ -2941,9 +3847,9 @@ var defaultFetchText = async (url) => {
2941
3847
  var sourceText = async (root, source, fetchText) => {
2942
3848
  try {
2943
3849
  if (/^https?:\/\//.test(source)) return await fetchText(source);
2944
- const path = resolve7(root, source);
2945
- if (!existsSync12(path)) return null;
2946
- return readFileSync14(path, "utf8");
3850
+ const path = resolve10(root, source);
3851
+ if (!existsSync14(path)) return null;
3852
+ return readFileSync13(path, "utf8");
2947
3853
  } catch {
2948
3854
  return null;
2949
3855
  }
@@ -3028,11 +3934,11 @@ var retrieveHybridChunks = async (root, config, index, query, options = {}) => {
3028
3934
  };
3029
3935
 
3030
3936
  // src/intelligence/rag.ts
3031
- import { readFileSync as readFileSync15 } from "fs";
3032
- import { join as join17 } from "path";
3937
+ import { readFileSync as readFileSync14 } from "fs";
3938
+ import { join as join14 } from "path";
3033
3939
 
3034
3940
  // src/intelligence/adapter.ts
3035
- import { join as join16 } from "path";
3941
+ import { join as join13 } from "path";
3036
3942
 
3037
3943
  // src/intelligence/peers.ts
3038
3944
  var PeerMissingError = class extends Error {
@@ -3159,7 +4065,7 @@ var resolveIntelligenceRuntime = async (config) => {
3159
4065
  }
3160
4066
  return { adapter, embed, provider, ...model ? { model } : {} };
3161
4067
  };
3162
- var defaultVectorStorePath = (root) => join16(root, ".doc-bridge", "vectors");
4068
+ var defaultVectorStorePath = (root) => join13(root, ".doc-bridge", "vectors");
3163
4069
 
3164
4070
  // src/intelligence/rag.ts
3165
4071
  var loadDocuments = (root, index, sources) => {
@@ -3167,10 +4073,10 @@ var loadDocuments = (root, index, sources) => {
3167
4073
  const docs = [];
3168
4074
  if (includeAgent) {
3169
4075
  for (const entry of index.knowledge) {
3170
- const abs = join17(root, entry.path);
4076
+ const abs = join14(root, entry.path);
3171
4077
  let content = "";
3172
4078
  try {
3173
- content = readFileSync15(abs, "utf8");
4079
+ content = readFileSync14(abs, "utf8");
3174
4080
  } catch {
3175
4081
  content = [entry.title, entry.description].filter(Boolean).join("\n\n");
3176
4082
  }
@@ -3188,7 +4094,7 @@ var createDocBridgeRag = async (root, config, index) => {
3188
4094
  const { embed } = await resolveIntelligenceRuntime(config);
3189
4095
  const ragMod = await importPeer("@agentskit/rag");
3190
4096
  const memoryMod = await importPeer("@agentskit/memory");
3191
- const storePath = typeof config.intelligence?.retriever?.options?.storePath === "string" ? join17(root, config.intelligence.retriever.options.storePath) : defaultVectorStorePath(root);
4097
+ const storePath = typeof config.intelligence?.retriever?.options?.storePath === "string" ? join14(root, config.intelligence.retriever.options.storePath) : defaultVectorStorePath(root);
3192
4098
  const store = memoryMod.fileVectorMemory({ path: storePath });
3193
4099
  const rag = ragMod.createRAG({
3194
4100
  embed,
@@ -3447,12 +4353,17 @@ export {
3447
4353
  AgentHandoffV1Schema,
3448
4354
  AgentSearchV1Schema,
3449
4355
  ConfigNotFoundError,
4356
+ DOCUMENTATION_STANDARD_V1_ID,
4357
+ DOCUMENTATION_STANDARD_V1_STATUS,
3450
4358
  DOC_BRIDGE_PATTERN_ID,
3451
4359
  DOC_BRIDGE_PATTERN_META,
3452
4360
  DocBridgeConfigV1Schema,
3453
4361
  DocBridgeIndexV1JsonSchema,
3454
4362
  DocBridgeIndexV1Schema,
3455
4363
  DocBridgeJsonSchemas,
4364
+ DocumentationStandardRuleIdSchema,
4365
+ DocumentationStandardV1ConfigSchema,
4366
+ EcosystemContractEvidenceSchema,
3456
4367
  HANDOFF_SCHEMA_VERSION,
3457
4368
  HandoffBridgeSchema,
3458
4369
  HandoffTargetTypeSchema,
@@ -3482,6 +4393,7 @@ export {
3482
4393
  formatDoctorBadgeJson,
3483
4394
  formatDoctorBadgeMarkdown,
3484
4395
  formatDoctorText,
4396
+ formatDocumentationStandardText,
3485
4397
  handleMcpRequest,
3486
4398
  indexFilePath,
3487
4399
  ingestAgentMemory,
@@ -3509,6 +4421,7 @@ export {
3509
4421
  retrieveHybridChunks,
3510
4422
  runChatOnce,
3511
4423
  runDoctor,
4424
+ runDocumentationStandardV1,
3512
4425
  runGate,
3513
4426
  runGates,
3514
4427
  runQuery,