@agentskit/doc-bridge 1.0.1 → 1.1.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 (48) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/CONTRIBUTING.md +7 -0
  3. package/README.md +81 -15
  4. package/SECURITY.md +1 -1
  5. package/action.yml +2 -2
  6. package/dist/cli/program.js +1248 -316
  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/RELEASE.md +19 -21
  16. package/docs/getting-started.md +27 -2
  17. package/docs/landing/assets/doc-bridge-hero.webp +0 -0
  18. package/docs/landing/assets/doc-bridge-surfaces.webp +0 -0
  19. package/docs/landing/assets/doc-bridge-two-way.webp +0 -0
  20. package/docs/landing/index.html +70 -10
  21. package/docs/playbook/doc-bridge-pattern.md +2 -2
  22. package/docs/recipes/index-pipeline.md +2 -2
  23. package/docs/schemas/memory-candidate-v1.md +10 -1
  24. package/docs/spec/cli.md +1 -0
  25. package/docs/spec/config-v1.md +51 -6
  26. package/docs/spec/documentation-standard-v1.md +131 -0
  27. package/ecosystem-claims.json +187 -0
  28. package/ecosystem-upstream.json +9 -0
  29. package/ecosystem.json +231 -0
  30. package/package.json +14 -2
  31. package/scripts/check-ecosystem-upstream.mjs +50 -0
  32. package/src/cli/program.ts +43 -9
  33. package/src/config/index.ts +7 -1
  34. package/src/config/load-config.ts +4 -14
  35. package/src/config/schema.ts +91 -0
  36. package/src/conformance/documentation-standard-v1.ts +502 -0
  37. package/src/conformance/ecosystem-contract.ts +175 -0
  38. package/src/gates/run-gates.ts +33 -4
  39. package/src/index-builder/human-adapters/core.ts +12 -5
  40. package/src/index-builder/human-adapters/docusaurus.ts +29 -44
  41. package/src/index-builder/human-adapters/index.ts +15 -3
  42. package/src/index-builder/scan-corpus.ts +6 -6
  43. package/src/index.ts +17 -0
  44. package/src/lib/bounded-text.ts +25 -0
  45. package/src/lib/paths.ts +20 -2
  46. package/src/lib/static-js-literal.ts +261 -0
  47. package/src/lib/walk.ts +23 -4
  48. package/src/version.ts +1 -1
@@ -1,12 +1,271 @@
1
1
  // src/cli/program.ts
2
- import { existsSync as existsSync14, mkdirSync as mkdirSync5, readFileSync as readFileSync17, writeFileSync as writeFileSync4 } from "fs";
3
- import { dirname as dirname7, resolve as resolve9 } from "path";
2
+ import { existsSync as existsSync16, mkdirSync as mkdirSync5, readFileSync as readFileSync16, writeFileSync as writeFileSync4 } from "fs";
3
+ import { dirname as dirname7, resolve as resolve12 } from "path";
4
4
  import { createInterface } from "readline/promises";
5
5
 
6
6
  // src/config/load-config.ts
7
7
  import { existsSync, readFileSync } from "fs";
8
8
  import { basename, dirname, join, resolve } from "path";
9
- import vm from "vm";
9
+
10
+ // src/lib/static-js-literal.ts
11
+ var stripComments = (source) => {
12
+ let out = "";
13
+ let index = 0;
14
+ let quote;
15
+ while (index < source.length) {
16
+ const char = source[index] ?? "";
17
+ const next = source[index + 1] ?? "";
18
+ if (quote) {
19
+ out += char;
20
+ if (char === "\\") {
21
+ out += next;
22
+ index += 2;
23
+ continue;
24
+ }
25
+ if (char === quote) quote = void 0;
26
+ index += 1;
27
+ continue;
28
+ }
29
+ if (char === '"' || char === "'" || char === "`") {
30
+ quote = char;
31
+ out += char;
32
+ index += 1;
33
+ continue;
34
+ }
35
+ if (char === "/" && next === "/") {
36
+ while (index < source.length && source[index] !== "\n") index += 1;
37
+ out += "\n";
38
+ index += 1;
39
+ continue;
40
+ }
41
+ if (char === "/" && next === "*") {
42
+ index += 2;
43
+ while (index < source.length && !(source[index] === "*" && source[index + 1] === "/")) index += 1;
44
+ index += 2;
45
+ out += " ";
46
+ continue;
47
+ }
48
+ out += char;
49
+ index += 1;
50
+ }
51
+ if (quote) throw new Error("Unterminated string in static JavaScript literal.");
52
+ return out;
53
+ };
54
+ var LiteralParser = class {
55
+ constructor(source) {
56
+ this.source = source;
57
+ }
58
+ source;
59
+ index = 0;
60
+ parseAt(index) {
61
+ this.index = index;
62
+ const value = this.value();
63
+ this.space();
64
+ return value;
65
+ }
66
+ space() {
67
+ while (/\s/.test(this.source[this.index] ?? "")) this.index += 1;
68
+ }
69
+ value() {
70
+ this.space();
71
+ const char = this.source[this.index];
72
+ if (char === "{") return this.object();
73
+ if (char === "[") return this.array();
74
+ if (char === '"' || char === "'") return this.string();
75
+ const word = this.word();
76
+ if (word === "true") return true;
77
+ if (word === "false") return false;
78
+ if (word === "null") return null;
79
+ if (/^-?\d+(?:\.\d+)?$/.test(word)) return Number(word);
80
+ throw new Error(`Unsupported dynamic sidebar expression near "${word || char || "EOF"}".`);
81
+ }
82
+ object() {
83
+ const result = {};
84
+ this.index += 1;
85
+ this.space();
86
+ while (this.source[this.index] !== "}") {
87
+ const key = this.source[this.index] === '"' || this.source[this.index] === "'" ? this.string() : this.word();
88
+ if (!key) throw new Error("Static sidebar object key is required.");
89
+ this.space();
90
+ if (this.source[this.index] !== ":") throw new Error(`Static sidebar key "${key}" requires a literal value.`);
91
+ this.index += 1;
92
+ result[key] = this.value();
93
+ this.space();
94
+ if (this.source[this.index] === ",") {
95
+ this.index += 1;
96
+ this.space();
97
+ continue;
98
+ }
99
+ if (this.source[this.index] !== "}") throw new Error("Expected comma or closing brace in static sidebar.");
100
+ }
101
+ this.index += 1;
102
+ return result;
103
+ }
104
+ array() {
105
+ const result = [];
106
+ this.index += 1;
107
+ this.space();
108
+ while (this.source[this.index] !== "]") {
109
+ result.push(this.value());
110
+ this.space();
111
+ if (this.source[this.index] === ",") {
112
+ this.index += 1;
113
+ this.space();
114
+ continue;
115
+ }
116
+ if (this.source[this.index] !== "]") throw new Error("Expected comma or closing bracket in static sidebar.");
117
+ }
118
+ this.index += 1;
119
+ return result;
120
+ }
121
+ string() {
122
+ const quote = this.source[this.index] ?? "";
123
+ this.index += 1;
124
+ let result = "";
125
+ while (this.index < this.source.length) {
126
+ const char = this.source[this.index] ?? "";
127
+ if (char === quote) {
128
+ this.index += 1;
129
+ return result;
130
+ }
131
+ if (char === "\\") {
132
+ const escaped = this.source[this.index + 1];
133
+ if (escaped === void 0) break;
134
+ const escapes = { n: "\n", r: "\r", t: " " };
135
+ result += escapes[escaped] ?? escaped;
136
+ this.index += 2;
137
+ continue;
138
+ }
139
+ result += char;
140
+ this.index += 1;
141
+ }
142
+ throw new Error("Unterminated string in static sidebar.");
143
+ }
144
+ word() {
145
+ this.space();
146
+ const start = this.index;
147
+ while (/[A-Za-z0-9_$.-]/.test(this.source[this.index] ?? "")) this.index += 1;
148
+ return this.source.slice(start, this.index);
149
+ }
150
+ };
151
+ var maskStrings = (source) => {
152
+ const chars = [...source];
153
+ let quote;
154
+ let previousToken;
155
+ const regexPrefixKeywords = /* @__PURE__ */ new Set([
156
+ "await",
157
+ "case",
158
+ "delete",
159
+ "do",
160
+ "else",
161
+ "in",
162
+ "instanceof",
163
+ "new",
164
+ "of",
165
+ "return",
166
+ "throw",
167
+ "typeof",
168
+ "void",
169
+ "yield"
170
+ ]);
171
+ const canStartRegex = () => previousToken === void 0 || "=(:,[!&|?{};".includes(previousToken) || previousToken === "=>" || regexPrefixKeywords.has(previousToken);
172
+ for (let index = 0; index < chars.length; index += 1) {
173
+ const char = chars[index] ?? "";
174
+ if (quote) {
175
+ chars[index] = " ";
176
+ if (char === "\\") {
177
+ if (index + 1 < chars.length) chars[index + 1] = " ";
178
+ index += 1;
179
+ } else if (char === quote) {
180
+ quote = void 0;
181
+ previousToken = "literal";
182
+ }
183
+ continue;
184
+ }
185
+ if (char === '"' || char === "'" || char === "`") {
186
+ quote = char;
187
+ chars[index] = " ";
188
+ continue;
189
+ }
190
+ if (char === "/" && canStartRegex()) {
191
+ chars[index] = " ";
192
+ let inClass = false;
193
+ for (index += 1; index < chars.length; index += 1) {
194
+ const regexChar = chars[index] ?? "";
195
+ chars[index] = " ";
196
+ if (regexChar === "\\") {
197
+ if (index + 1 < chars.length) chars[index + 1] = " ";
198
+ index += 1;
199
+ } else if (regexChar === "[") {
200
+ inClass = true;
201
+ } else if (regexChar === "]") {
202
+ inClass = false;
203
+ } else if (regexChar === "/" && !inClass) {
204
+ while (/[A-Za-z]/.test(chars[index + 1] ?? "")) {
205
+ index += 1;
206
+ chars[index] = " ";
207
+ }
208
+ break;
209
+ }
210
+ }
211
+ previousToken = "literal";
212
+ continue;
213
+ }
214
+ if (/[A-Za-z_$]/.test(char)) {
215
+ const start = index;
216
+ while (/[A-Za-z0-9_$]/.test(chars[index + 1] ?? "")) index += 1;
217
+ previousToken = chars.slice(start, index + 1).join("");
218
+ continue;
219
+ }
220
+ if (char === "=" && chars[index + 1] === ">") {
221
+ previousToken = "=>";
222
+ index += 1;
223
+ continue;
224
+ }
225
+ if (!/\s/.test(char)) previousToken = char;
226
+ }
227
+ return chars.join("");
228
+ };
229
+ var nonSpace = (source, start) => {
230
+ let index = start;
231
+ while (/\s/.test(source[index] ?? "")) index += 1;
232
+ return index;
233
+ };
234
+ var escapedRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
235
+ var parseStaticJsObject = (source) => {
236
+ const clean = stripComments(source);
237
+ const mask = maskStrings(clean);
238
+ const parseBinding = (identifier) => {
239
+ const declaration = new RegExp(`\\b(?:const|let|var)\\s+${escapedRegex(identifier)}(?:\\s*:[^=;]+)?\\s*=`).exec(mask);
240
+ if (!declaration) throw new Error(`Exported binding "${identifier}" must reference a static object declaration.`);
241
+ const start = nonSpace(mask, declaration.index + declaration[0].length);
242
+ if (mask[start] !== "{") throw new Error(`Exported binding "${identifier}" must be a static object literal.`);
243
+ return new LiteralParser(clean).parseAt(start);
244
+ };
245
+ const commonJs = /\bmodule\.exports\s*=/.exec(mask);
246
+ if (commonJs) {
247
+ const start = nonSpace(mask, commonJs.index + commonJs[0].length);
248
+ if (mask[start] === "{") return new LiteralParser(clean).parseAt(start);
249
+ const identifier = /^[A-Za-z_$][\w$]*/.exec(mask.slice(start))?.[0];
250
+ if (identifier) return parseBinding(identifier);
251
+ throw new Error("module.exports must be assigned a static object literal or binding.");
252
+ }
253
+ const exported = /\bexport\s+default\b/.exec(mask);
254
+ if (exported) {
255
+ let start = nonSpace(mask, exported.index + exported[0].length);
256
+ if (mask.slice(start).startsWith("defineConfig")) {
257
+ start = nonSpace(mask, start + "defineConfig".length);
258
+ if (mask[start] !== "(") throw new Error("defineConfig must be called with a static object literal.");
259
+ start = nonSpace(mask, start + 1);
260
+ if (mask[start] !== "{") throw new Error("defineConfig must be called with a static object literal.");
261
+ return new LiteralParser(clean).parseAt(start);
262
+ }
263
+ if (mask[start] === "{") return new LiteralParser(clean).parseAt(start);
264
+ const identifier = /^[A-Za-z_$][\w$]*/.exec(mask.slice(start))?.[0];
265
+ if (identifier) return parseBinding(identifier);
266
+ }
267
+ throw new Error("Docusaurus sidebar must export a static object or assign one to a const.");
268
+ };
10
269
 
11
270
  // src/config/defaults.ts
12
271
  var DEFAULT_AGENT_EXCLUDE = ["**/node_modules/**", "**/.git/**"];
@@ -147,7 +406,8 @@ var GatesConfigSchema = z.object({
147
406
  "okf-type",
148
407
  "docs-style",
149
408
  "routing-currency",
150
- "bootstrap-size"
409
+ "bootstrap-size",
410
+ "documentation-standard-v1"
151
411
  ])
152
412
  ).max(16).optional(),
153
413
  exclude: z.array(
@@ -158,7 +418,8 @@ var GatesConfigSchema = z.object({
158
418
  "okf-type",
159
419
  "docs-style",
160
420
  "routing-currency",
161
- "bootstrap-size"
421
+ "bootstrap-size",
422
+ "documentation-standard-v1"
162
423
  ])
163
424
  ).max(16).optional(),
164
425
  options: z.record(z.string(), z.unknown()).optional()
@@ -237,6 +498,69 @@ var FederationConfigSchema = z.object({
237
498
  }).strict()
238
499
  ).max(16).optional()
239
500
  }).strict();
501
+ var DocumentationEvidenceFileSchema = z.object({
502
+ path: z.string().min(1).max(512),
503
+ contains: z.array(z.string().min(1).max(512)).min(1).max(32)
504
+ }).strict();
505
+ var DocumentationLinkEvidenceSchema = z.object({
506
+ url: z.string().url().max(512),
507
+ paths: z.array(z.string().min(1).max(512)).min(1).max(32)
508
+ }).strict();
509
+ var DocumentationQuickstartEvidenceSchema = z.object({
510
+ id: z.string().regex(/^[a-z][a-z0-9-]*$/).max(128),
511
+ doc: z.string().min(1).max(512),
512
+ test: z.string().min(1).max(512),
513
+ command: z.string().min(1).max(512),
514
+ testContains: z.array(z.string().min(1).max(256)).min(1).max(16)
515
+ }).strict();
516
+ var EcosystemContractEvidenceSchema = z.object({
517
+ manifest: z.string().min(1).max(512),
518
+ claims: z.string().min(1).max(512),
519
+ productId: z.string().regex(/^[a-z][a-z0-9-]*$/).max(128)
520
+ }).strict();
521
+ var DocumentationStandardRuleIdSchema = z.enum([
522
+ "human-docs",
523
+ "llms-and-raw-source",
524
+ "agent-handoffs",
525
+ "contribution",
526
+ "metadata",
527
+ "cross-links",
528
+ "tested-quickstarts",
529
+ "visual-explanations",
530
+ "structured-diagrams"
531
+ ]);
532
+ var DocumentationStandardExceptionSchema = z.object({
533
+ ruleId: DocumentationStandardRuleIdSchema,
534
+ reason: z.string().min(10).max(1024),
535
+ approvedBy: z.string().min(1).max(256),
536
+ trackingUrl: z.string().url().max(512)
537
+ }).strict();
538
+ var DocumentationStandardV1ConfigSchema = z.object({
539
+ rawSources: z.array(z.string().min(1).max(512)).max(64).optional(),
540
+ contributionPaths: z.array(z.string().min(1).max(512)).max(16).optional(),
541
+ metadata: z.array(DocumentationEvidenceFileSchema).max(32).optional(),
542
+ links: z.array(DocumentationLinkEvidenceSchema).max(64).optional(),
543
+ quickstarts: z.array(DocumentationQuickstartEvidenceSchema).max(32).optional(),
544
+ visuals: z.array(z.string().min(1).max(512)).max(64).optional(),
545
+ diagrams: z.array(DocumentationEvidenceFileSchema).max(32).optional(),
546
+ ecosystemContract: EcosystemContractEvidenceSchema.optional(),
547
+ exceptions: z.array(DocumentationStandardExceptionSchema).max(32).optional()
548
+ }).strict().superRefine((value, context) => {
549
+ const seen = /* @__PURE__ */ new Set();
550
+ for (const [index, exception] of (value.exceptions ?? []).entries()) {
551
+ if (seen.has(exception.ruleId)) {
552
+ context.addIssue({
553
+ code: "custom",
554
+ path: ["exceptions", index, "ruleId"],
555
+ message: `Duplicate exception for rule ${exception.ruleId}`
556
+ });
557
+ }
558
+ seen.add(exception.ruleId);
559
+ }
560
+ });
561
+ var ConformanceConfigSchema = z.object({
562
+ documentationStandardV1: DocumentationStandardV1ConfigSchema.optional()
563
+ }).strict();
240
564
  var DocBridgeConfigV1Schema = z.object({
241
565
  schemaVersion: z.literal(CONFIG_SCHEMA_VERSION),
242
566
  project: z.object({
@@ -252,7 +576,8 @@ var DocBridgeConfigV1Schema = z.object({
252
576
  gates: GatesConfigSchema.optional(),
253
577
  surfaces: SurfacesConfigSchema.optional(),
254
578
  intelligence: IntelligenceConfigSchema.optional(),
255
- federation: FederationConfigSchema.optional()
579
+ federation: FederationConfigSchema.optional(),
580
+ conformance: ConformanceConfigSchema.optional()
256
581
  }).strict();
257
582
 
258
583
  // src/config/load-config.ts
@@ -299,22 +624,16 @@ var parseJsonConfig = (raw, path) => {
299
624
  }
300
625
  };
301
626
  var parseCodeConfig = (raw, path) => {
302
- 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 =");
303
- if (/\bimport\b/.test(code)) {
627
+ 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, "");
628
+ if (/\bimport\b/.test(unsupportedImports)) {
304
629
  throw new Error(`Unsupported import in ${path}. Static config only supports defineConfig imports.`);
305
630
  }
306
- const sandbox = {
307
- module: { exports: {} },
308
- exports: {},
309
- defineConfig: (config) => config
310
- };
311
631
  try {
312
- vm.runInNewContext(code, sandbox, { timeout: 250, filename: path });
632
+ return parseStaticJsObject(raw);
313
633
  } catch (error) {
314
634
  const message = error instanceof Error ? error.message : String(error);
315
635
  throw new Error(`Failed to load config at ${path}: ${message}`);
316
636
  }
317
- return sandbox.module.exports.default;
318
637
  };
319
638
  var parseConfig = (input) => {
320
639
  const result = DocBridgeConfigV1Schema.safeParse(input);
@@ -345,24 +664,197 @@ var projectRootFromConfigPath = (configFilePath, projectRootField) => {
345
664
  return configDir;
346
665
  };
347
666
 
667
+ // src/conformance/documentation-standard-v1.ts
668
+ import { existsSync as existsSync8, readFileSync as readFileSync7, realpathSync as realpathSync5, statSync as statSync3 } from "fs";
669
+ import { isAbsolute as isAbsolute3, relative as relative3, resolve as resolve5, sep as sep4 } from "path";
670
+
671
+ // src/conformance/ecosystem-contract.ts
672
+ import { z as z2 } from "zod";
673
+ var NonEmptyStringSchema = z2.string().refine((value) => value.trim().length > 0, "must be non-empty");
674
+ var HttpsUrlSchema = z2.string().url().refine((value) => value.startsWith("https://"), "must use https");
675
+ var RepoSchema = z2.string().regex(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/);
676
+ var SlugSchema = z2.string().regex(/^[a-z][a-z0-9-]*$/);
677
+ var SurfaceSchema = z2.object({
678
+ home: HttpsUrlSchema.optional(),
679
+ docs: HttpsUrlSchema.optional(),
680
+ llms: HttpsUrlSchema.optional(),
681
+ stats: HttpsUrlSchema.optional(),
682
+ documentation: z2.enum(["fumadocs", "repository"]),
683
+ chat: z2.enum(["agentschat", "custom", "none"])
684
+ }).passthrough();
685
+ var ProductSchema = z2.object({
686
+ id: SlugSchema,
687
+ name: NonEmptyStringSchema,
688
+ shortName: NonEmptyStringSchema,
689
+ kind: NonEmptyStringSchema,
690
+ role: NonEmptyStringSchema,
691
+ promise: NonEmptyStringSchema,
692
+ maturity: z2.enum(["planning", "alpha", "beta", "stable", "deprecated"]),
693
+ repo: RepoSchema,
694
+ accent: z2.string().regex(/^#[0-9A-Fa-f]{6}$/),
695
+ surfaces: SurfaceSchema,
696
+ navigation: z2.object({
697
+ showInBar: z2.boolean(),
698
+ order: z2.number().int().nonnegative().optional(),
699
+ next: z2.array(SlugSchema)
700
+ }).passthrough()
701
+ }).passthrough();
702
+ var LegacyPropertySchema = z2.object({
703
+ id: SlugSchema,
704
+ name: NonEmptyStringSchema,
705
+ barLabel: NonEmptyStringSchema,
706
+ domain: NonEmptyStringSchema,
707
+ url: HttpsUrlSchema,
708
+ repo: RepoSchema,
709
+ tagline: NonEmptyStringSchema,
710
+ kind: NonEmptyStringSchema,
711
+ accent: z2.string().regex(/^#[0-9A-Fa-f]{6}$/),
712
+ llms: HttpsUrlSchema.optional(),
713
+ stats: HttpsUrlSchema.optional()
714
+ }).passthrough();
715
+ var ManifestSchema = z2.object({
716
+ schemaVersion: z2.literal(2),
717
+ parentBrand: z2.object({ id: NonEmptyStringSchema, name: NonEmptyStringSchema }).passthrough(),
718
+ products: z2.array(ProductSchema).min(1),
719
+ properties: z2.array(LegacyPropertySchema).length(4),
720
+ builder: z2.object({ id: NonEmptyStringSchema, name: NonEmptyStringSchema, url: HttpsUrlSchema }).passthrough().optional()
721
+ }).passthrough();
722
+ var EvidenceSchema = z2.discriminatedUnion("type", [
723
+ z2.object({
724
+ type: z2.literal("repository-derivation"),
725
+ repo: RepoSchema,
726
+ path: NonEmptyStringSchema,
727
+ summary: NonEmptyStringSchema
728
+ }).passthrough(),
729
+ z2.object({ type: z2.literal("endpoint"), url: HttpsUrlSchema, summary: NonEmptyStringSchema }).passthrough()
730
+ ]);
731
+ var ClaimSchema = z2.object({
732
+ id: NonEmptyStringSchema,
733
+ value: z2.number().finite().nonnegative(),
734
+ noun: NonEmptyStringSchema,
735
+ conservativeFloor: z2.number().int().nonnegative().optional(),
736
+ evidence: EvidenceSchema
737
+ }).passthrough();
738
+ var ClaimProductSchema = z2.object({
739
+ productId: SlugSchema,
740
+ source: z2.discriminatedUnion("type", [
741
+ z2.object({ type: z2.literal("endpoint"), url: HttpsUrlSchema }).passthrough(),
742
+ z2.object({ type: z2.literal("repository"), repo: RepoSchema }).passthrough()
743
+ ]),
744
+ verification: z2.enum(["verified", "declared"]),
745
+ claims: z2.array(ClaimSchema)
746
+ }).passthrough();
747
+ var ClaimsSchema = z2.object({
748
+ schemaVersion: z2.literal(1),
749
+ manifestSchemaVersion: z2.literal(2),
750
+ products: z2.array(ClaimProductSchema)
751
+ }).passthrough();
752
+ var LEGACY_PRODUCT_IDS = ["agentskit", "akos", "playbook", "registry"];
753
+ var parseCanonicalEcosystemContract = (manifestInput, claimsInput) => {
754
+ const manifest = ManifestSchema.parse(manifestInput);
755
+ const claims = ClaimsSchema.parse(claimsInput);
756
+ const products = new Map(manifest.products.map((product) => [product.id, product]));
757
+ if (products.size !== manifest.products.length) throw new Error("Manifest product IDs must be unique.");
758
+ const navigationOrders = /* @__PURE__ */ new Set();
759
+ for (const product of manifest.products) {
760
+ if (product.surfaces.documentation === "fumadocs" && !product.surfaces.docs) {
761
+ throw new Error(`Product ${product.id} requires a docs surface for Fumadocs.`);
762
+ }
763
+ if (product.navigation.showInBar) {
764
+ if (!product.surfaces.home || product.navigation.order === void 0) {
765
+ throw new Error(`Product ${product.id} requires home and order for shared navigation.`);
766
+ }
767
+ if (navigationOrders.has(product.navigation.order)) throw new Error("Navigation orders must be unique.");
768
+ navigationOrders.add(product.navigation.order);
769
+ }
770
+ const next = new Set(product.navigation.next);
771
+ if (next.size !== product.navigation.next.length || next.has(product.id)) {
772
+ throw new Error(`Product ${product.id} has duplicate or self-referential navigation.`);
773
+ }
774
+ for (const nextId of next) {
775
+ if (!products.has(nextId)) throw new Error(`Product ${product.id} references unknown product ${nextId}.`);
776
+ }
777
+ }
778
+ for (const [index, id] of LEGACY_PRODUCT_IDS.entries()) {
779
+ const legacy = manifest.properties[index];
780
+ const product = products.get(id);
781
+ if (!legacy || !product || legacy.id !== id || !product.surfaces.home) {
782
+ throw new Error(`Legacy property ${index} must project product ${id}.`);
783
+ }
784
+ const expected = {
785
+ name: product.name,
786
+ barLabel: product.shortName,
787
+ domain: new URL(product.surfaces.home).host,
788
+ url: product.surfaces.home,
789
+ repo: product.repo,
790
+ tagline: product.promise,
791
+ kind: product.kind,
792
+ accent: product.accent,
793
+ llms: product.surfaces.llms,
794
+ stats: product.surfaces.stats
795
+ };
796
+ for (const [key, value] of Object.entries(expected)) {
797
+ if (legacy[key] !== value) throw new Error(`Legacy ${id}.${key} must match v2.`);
798
+ }
799
+ }
800
+ const claimProducts = new Map(claims.products.map((product) => [product.productId, product]));
801
+ if (claimProducts.size !== claims.products.length || claimProducts.size !== products.size) {
802
+ throw new Error("Claims must include every manifest product exactly once.");
803
+ }
804
+ for (const [productId, product] of products) {
805
+ const claimProduct = claimProducts.get(productId);
806
+ if (!claimProduct) throw new Error(`Claims are missing product ${productId}.`);
807
+ if (claimProduct.source.type === "endpoint") {
808
+ if (claimProduct.source.url !== product.surfaces.stats) throw new Error(`Claims source for ${productId} must match stats.`);
809
+ } else if (claimProduct.source.repo !== product.repo) {
810
+ throw new Error(`Claims source for ${productId} must match repo.`);
811
+ }
812
+ if (claimProduct.verification === "declared" && claimProduct.claims.length > 0) {
813
+ throw new Error(`Declared product ${productId} cannot publish claims.`);
814
+ }
815
+ const claimIds = /* @__PURE__ */ new Set();
816
+ for (const claim of claimProduct.claims) {
817
+ if (claimIds.has(claim.id)) throw new Error(`Product ${productId} has duplicate claim ${claim.id}.`);
818
+ claimIds.add(claim.id);
819
+ if (claim.conservativeFloor !== void 0 && claim.conservativeFloor > claim.value) {
820
+ throw new Error(`Claim ${productId}:${claim.id} has a floor above its value.`);
821
+ }
822
+ if (claim.evidence.type === "repository-derivation" && claim.evidence.repo !== product.repo) {
823
+ throw new Error(`Claim ${productId}:${claim.id} evidence must match the product repo.`);
824
+ }
825
+ }
826
+ }
827
+ return { manifest, claims };
828
+ };
829
+
348
830
  // src/index-builder/build-index.ts
349
- import { mkdirSync, readFileSync as readFileSync8, writeFileSync } from "fs";
350
- import { dirname as dirname3, join as join10 } from "path";
831
+ import { mkdirSync, readFileSync as readFileSync6, writeFileSync } from "fs";
832
+ import { dirname as dirname3, join as join7 } from "path";
351
833
 
352
834
  // src/lib/paths.ts
353
- import { resolve as resolve2 } from "path";
835
+ import { existsSync as existsSync2, realpathSync } from "fs";
836
+ import { isAbsolute, relative, resolve as resolve2, sep } from "path";
354
837
  var toPosix = (value) => value.split("\\").join("/");
838
+ var containedProjectPath = (root, path) => {
839
+ const projectRoot = realpathSync.native(resolve2(root));
840
+ const unresolved = resolve2(projectRoot, path);
841
+ const unresolvedRelative = relative(projectRoot, unresolved);
842
+ if (isAbsolute(unresolvedRelative) || unresolvedRelative === ".." || unresolvedRelative.startsWith(`..${sep}`)) return void 0;
843
+ const canonical = existsSync2(unresolved) ? realpathSync.native(unresolved) : unresolved;
844
+ const canonicalRelative = relative(projectRoot, canonical);
845
+ return isAbsolute(canonicalRelative) || canonicalRelative === ".." || canonicalRelative.startsWith(`..${sep}`) ? void 0 : canonical;
846
+ };
355
847
 
356
848
  // src/lib/package-manager.ts
357
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
849
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
358
850
  import { join as join2 } from "path";
359
851
  var detectPackageManager = (root) => {
360
- if (existsSync2(join2(root, "pnpm-lock.yaml")) || existsSync2(join2(root, "pnpm-workspace.yaml"))) {
852
+ if (existsSync3(join2(root, "pnpm-lock.yaml")) || existsSync3(join2(root, "pnpm-workspace.yaml"))) {
361
853
  return "pnpm";
362
854
  }
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";
855
+ if (existsSync3(join2(root, "yarn.lock"))) return "yarn";
856
+ if (existsSync3(join2(root, "bun.lockb")) || existsSync3(join2(root, "bun.lock"))) return "bun";
857
+ if (existsSync3(join2(root, "package-lock.json"))) return "npm";
366
858
  try {
367
859
  const pkg = JSON.parse(readFileSync2(join2(root, "package.json"), "utf8"));
368
860
  const pm = pkg.packageManager?.split("@")[0];
@@ -383,7 +875,7 @@ var defaultChecksForTarget = (root, opts) => {
383
875
  } catch {
384
876
  }
385
877
  }
386
- const isWorkspace = existsSync2(join2(root, "pnpm-workspace.yaml")) || existsSync2(join2(root, "lerna.json")) || Boolean(
878
+ const isWorkspace = existsSync3(join2(root, "pnpm-workspace.yaml")) || existsSync3(join2(root, "lerna.json")) || Boolean(
387
879
  (() => {
388
880
  try {
389
881
  const pkg = JSON.parse(readFileSync2(join2(root, "package.json"), "utf8"));
@@ -417,9 +909,24 @@ var defaultChecksForTarget = (root, opts) => {
417
909
  return opts.strict ? ["npm test", "npm run lint"] : ["npm test"];
418
910
  };
419
911
 
420
- // src/index-builder/scan-corpus.ts
421
- import { readFileSync as readFileSync3 } from "fs";
422
- import { join as join4 } from "path";
912
+ // src/lib/bounded-text.ts
913
+ import { readFileSync as readFileSync3, statSync } from "fs";
914
+ var MAX_DOCUMENT_BYTES = 4 * 1024 * 1024;
915
+ var MAX_CORPUS_BYTES = 64 * 1024 * 1024;
916
+ var readBoundedText = (path, budget, limits) => {
917
+ const maxFileBytes = limits?.maxFileBytes ?? MAX_DOCUMENT_BYTES;
918
+ const maxCorpusBytes = limits?.maxCorpusBytes ?? MAX_CORPUS_BYTES;
919
+ const stat = statSync(path);
920
+ if (!stat.isFile()) throw new Error(`Documentation path is not a regular file: ${path}`);
921
+ if (stat.size > maxFileBytes) {
922
+ throw new Error(`Documentation file exceeds the ${maxFileBytes} byte limit: ${path}`);
923
+ }
924
+ if (budget.used + stat.size > maxCorpusBytes) {
925
+ throw new Error(`Documentation corpus exceeds the ${maxCorpusBytes} byte read budget.`);
926
+ }
927
+ budget.used += stat.size;
928
+ return readFileSync3(path, "utf8");
929
+ };
423
930
 
424
931
  // src/lib/markdown.ts
425
932
  var parseFrontmatter = (markdown) => {
@@ -510,14 +1017,24 @@ var slugFromPath = (relPath) => {
510
1017
  };
511
1018
 
512
1019
  // src/lib/walk.ts
513
- import { readdirSync, statSync } from "fs";
1020
+ import { lstatSync, readdirSync, realpathSync as realpathSync2 } from "fs";
514
1021
  import { join as join3 } from "path";
515
1022
  var DEFAULT_SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "coverage", ".doc-bridge"]);
1023
+ var DEFAULT_MAX_FILES = 1e4;
516
1024
  var walkFiles = (root, opts) => {
517
1025
  const extensions = opts?.extensions ?? [".md"];
518
1026
  const skip = opts?.skipDirs ?? DEFAULT_SKIP;
519
1027
  const out = [];
1028
+ const visited = /* @__PURE__ */ new Set();
520
1029
  const visit = (dir) => {
1030
+ let canonicalDir;
1031
+ try {
1032
+ canonicalDir = realpathSync2.native(dir);
1033
+ } catch {
1034
+ return;
1035
+ }
1036
+ if (visited.has(canonicalDir)) return;
1037
+ visited.add(canonicalDir);
521
1038
  let entries = [];
522
1039
  try {
523
1040
  entries = readdirSync(dir);
@@ -528,10 +1045,11 @@ var walkFiles = (root, opts) => {
528
1045
  const abs = join3(dir, name);
529
1046
  let st;
530
1047
  try {
531
- st = statSync(abs);
1048
+ st = lstatSync(abs);
532
1049
  } catch {
533
1050
  continue;
534
1051
  }
1052
+ if (st.isSymbolicLink()) continue;
535
1053
  if (st.isDirectory()) {
536
1054
  if (skip.has(name)) continue;
537
1055
  visit(abs);
@@ -539,6 +1057,9 @@ var walkFiles = (root, opts) => {
539
1057
  }
540
1058
  if (!st.isFile()) continue;
541
1059
  if (extensions.some((ext) => name.endsWith(ext))) {
1060
+ if (out.length >= (opts?.maxFiles ?? DEFAULT_MAX_FILES)) {
1061
+ throw new Error(`Documentation corpus exceeds the ${opts?.maxFiles ?? DEFAULT_MAX_FILES} file limit.`);
1062
+ }
542
1063
  out.push(toPosix(abs));
543
1064
  }
544
1065
  }
@@ -549,13 +1070,15 @@ var walkFiles = (root, opts) => {
549
1070
 
550
1071
  // src/index-builder/scan-corpus.ts
551
1072
  var scanAgentCorpus = (root, config) => {
552
- const agentRoot = join4(root, config.corpus.agent.root);
1073
+ const agentRoot = containedProjectPath(root, config.corpus.agent.root);
1074
+ if (!agentRoot) throw new Error("Agent corpus root escapes the project root.");
553
1075
  const files = walkFiles(agentRoot, { extensions: [".md", ".mdx"] });
554
1076
  const corpusRelRoot = toPosix(config.corpus.agent.root);
1077
+ const budget = { used: 0 };
555
1078
  return files.map((abs) => {
556
1079
  const relToCorpus = toPosix(abs.replace(`${toPosix(agentRoot)}/`, ""));
557
1080
  const relPath = `${corpusRelRoot}/${relToCorpus}`;
558
- const raw = readFileSync3(abs, "utf8");
1081
+ const raw = readBoundedText(abs, budget);
559
1082
  const { data: frontmatter } = parseFrontmatter(raw);
560
1083
  const id = frontmatterString(frontmatter, "id") ?? frontmatterString(frontmatter, "package") ?? slugFromPath(relToCorpus);
561
1084
  const title = firstHeading(raw) ?? id;
@@ -811,7 +1334,7 @@ var buildLookup = (config, packages, corpus, indexOutFile, humanDocs = {}, root
811
1334
  };
812
1335
 
813
1336
  // src/version.ts
814
- var PACKAGE_VERSION = "1.0.0";
1337
+ var PACKAGE_VERSION = "1.1.1";
815
1338
 
816
1339
  // src/index-builder/capabilities.ts
817
1340
  var renderCapabilitiesJson = (config, index, paths) => {
@@ -879,14 +1402,16 @@ ${lines.join("\n")}
879
1402
  `;
880
1403
  };
881
1404
 
1405
+ // src/index-builder/human-adapters/index.ts
1406
+ import { realpathSync as realpathSync4 } from "fs";
1407
+ import { resolve as resolve4, sep as sep3 } from "path";
1408
+
882
1409
  // src/index-builder/human-adapters/docusaurus.ts
883
- import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
884
- import { join as join6 } from "path";
885
- import vm2 from "vm";
1410
+ import { existsSync as existsSync4 } from "fs";
886
1411
 
887
1412
  // src/index-builder/human-adapters/core.ts
888
- import { readFileSync as readFileSync4 } from "fs";
889
- import { join as join5 } from "path";
1413
+ import { realpathSync as realpathSync3 } from "fs";
1414
+ import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
890
1415
  var optionString = (options, keys) => {
891
1416
  for (const key of keys) {
892
1417
  const value = options?.[key];
@@ -917,10 +1442,16 @@ var humanUrl = (slug2, urlPrefix) => {
917
1442
  };
918
1443
  var scanMarkdownDocs = (root, humanRoot, options) => {
919
1444
  const out = [];
920
- const absRoot = join5(root, humanRoot);
1445
+ const projectRoot = realpathSync3.native(resolve3(root));
1446
+ const absRoot = containedProjectPath(root, humanRoot);
1447
+ if (!absRoot) return out;
1448
+ const budget = { used: 0 };
921
1449
  for (const abs of walkFiles(absRoot, { extensions: [".md", ".mdx"] })) {
1450
+ const canonical = realpathSync3.native(abs);
1451
+ const fileRelative = relative2(projectRoot, canonical);
1452
+ if (isAbsolute2(fileRelative) || fileRelative === ".." || fileRelative.startsWith(`..${sep2}`)) continue;
922
1453
  const relToHumanRoot = toPosix(abs.replace(`${toPosix(absRoot)}/`, ""));
923
- const raw = readFileSync4(abs, "utf8");
1454
+ const raw = readBoundedText(abs, budget);
924
1455
  if (options?.includeRelPath && !options.includeRelPath(relToHumanRoot, raw)) continue;
925
1456
  out.push({
926
1457
  id: options?.idForDoc?.(relToHumanRoot, raw) ?? docId(relToHumanRoot, raw),
@@ -958,41 +1489,31 @@ var docusaurusRecordId = (relPath, raw) => {
958
1489
  const frontmatter = parseFrontmatter2(raw);
959
1490
  return frontmatter.package ?? frontmatter.module ?? docusaurusSidebarId(relPath, raw);
960
1491
  };
961
- var sidebarsValue = (file) => {
962
- if (!existsSync3(file)) return void 0;
963
- 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 =");
964
- const sandbox = { module: { exports: {} }, exports: {} };
965
- vm2.runInNewContext(raw, sandbox, { timeout: 250 });
966
- return sandbox.module.exports;
967
- };
968
- var visitSidebar = (value, filter) => {
969
- if (typeof value === "string") {
970
- filter.ids.add(value);
971
- return;
972
- }
973
- if (Array.isArray(value)) {
974
- for (const item2 of value) visitSidebar(item2, filter);
975
- return;
976
- }
977
- if (!value || typeof value !== "object") return;
978
- const item = value;
979
- if ((item.type === "doc" || item.type === "ref") && typeof item.id === "string") {
980
- filter.ids.add(item.id);
981
- }
982
- if (item.type === "autogenerated" && typeof item.dirName === "string") {
983
- filter.autogenDirs.push(item.dirName);
984
- }
985
- if (Array.isArray(item.items)) visitSidebar(item.items, filter);
986
- if (item.link && typeof item.link === "object") visitSidebar(item.link, filter);
987
- for (const child of Object.values(item)) {
988
- if (Array.isArray(child)) visitSidebar(child, filter);
989
- }
990
- };
991
- var readSidebars = (root, sidebarsFile) => {
1492
+ var readSidebars = (sidebarsFile) => {
992
1493
  if (!sidebarsFile) return { enabled: false, ids: /* @__PURE__ */ new Set(), autogenDirs: [] };
993
- const value = sidebarsValue(join6(root, sidebarsFile));
1494
+ if (!existsSync4(sidebarsFile)) return { enabled: false, ids: /* @__PURE__ */ new Set(), autogenDirs: [] };
1495
+ const raw = readBoundedText(sidebarsFile, { used: 0 }, { maxFileBytes: 1048576, maxCorpusBytes: 1048576 });
994
1496
  const filter = { ids: /* @__PURE__ */ new Set(), autogenDirs: [] };
995
- visitSidebar(value, filter);
1497
+ const visit = (value) => {
1498
+ if (typeof value === "string") {
1499
+ filter.ids.add(value);
1500
+ return;
1501
+ }
1502
+ if (Array.isArray(value)) {
1503
+ for (const item2 of value) visit(item2);
1504
+ return;
1505
+ }
1506
+ if (!value || typeof value !== "object") return;
1507
+ const item = value;
1508
+ if ((item.type === "doc" || item.type === "ref") && typeof item.id === "string") filter.ids.add(item.id);
1509
+ if (item.type === "autogenerated" && typeof item.dirName === "string") filter.autogenDirs.push(item.dirName);
1510
+ if (Array.isArray(item.items)) visit(item.items);
1511
+ if (item.link && typeof item.link === "object") visit(item.link);
1512
+ for (const child of Object.values(item)) {
1513
+ if (Array.isArray(child)) visit(child);
1514
+ }
1515
+ };
1516
+ visit(parseStaticJsObject(raw));
996
1517
  return { enabled: true, ...filter };
997
1518
  };
998
1519
  var isIncludedBySidebar = (filter, id) => {
@@ -1008,7 +1529,8 @@ var docusaurusAdapter = {
1008
1529
  scan: ({ root, config }) => {
1009
1530
  const docsDir = optionString(config.options, ["docsDir", "root"]);
1010
1531
  if (!docsDir) return [];
1011
- const sidebarFilter = readSidebars(root, optionString(config.options, ["sidebarsFile"]));
1532
+ const sidebarsFile = optionString(config.options, ["sidebarsFile"]);
1533
+ const sidebarFilter = readSidebars(sidebarsFile ? containedProjectPath(root, sidebarsFile) : void 0);
1012
1534
  return scanMarkdownDocs(root, docsDir, {
1013
1535
  includeRelPath: (relPath, raw) => isIncludedBySidebar(sidebarFilter, docusaurusSidebarId(relPath, raw)),
1014
1536
  idForDoc: docusaurusRecordId,
@@ -1019,13 +1541,13 @@ var docusaurusAdapter = {
1019
1541
  };
1020
1542
 
1021
1543
  // src/index-builder/human-adapters/fumadocs.ts
1022
- import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
1023
- import { join as join7 } from "path";
1544
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
1545
+ import { join as join4 } from "path";
1024
1546
  var readMetaPages = (dir) => {
1025
- const file = join7(dir, "meta.json");
1026
- if (!existsSync4(file)) return void 0;
1547
+ const file = join4(dir, "meta.json");
1548
+ if (!existsSync5(file)) return void 0;
1027
1549
  try {
1028
- const meta = JSON.parse(readFileSync6(file, "utf8"));
1550
+ const meta = JSON.parse(readFileSync4(file, "utf8"));
1029
1551
  return Array.isArray(meta.pages) ? meta.pages.filter((page) => typeof page === "string") : void 0;
1030
1552
  } catch {
1031
1553
  return void 0;
@@ -1040,7 +1562,7 @@ var isListedByMeta = (contentRoot, relPath) => {
1040
1562
  if (isDotFile(relPath)) return false;
1041
1563
  const parts = relPath.split("/");
1042
1564
  for (let i = 0; i < parts.length; i += 1) {
1043
- const dir = join7(contentRoot, ...parts.slice(0, i));
1565
+ const dir = join4(contentRoot, ...parts.slice(0, i));
1044
1566
  const pages = readMetaPages(dir);
1045
1567
  if (!pages?.length || pages.includes("...")) continue;
1046
1568
  const key = pageKey(parts[i] ?? "");
@@ -1053,7 +1575,7 @@ var fumadocsAdapter = {
1053
1575
  scan: ({ root, config }) => {
1054
1576
  const contentDir = optionString(config.options, ["contentDir", "root"]);
1055
1577
  if (!contentDir) return [];
1056
- const contentRoot = join7(root, contentDir);
1578
+ const contentRoot = join4(root, contentDir);
1057
1579
  const excludePrefixes = Array.isArray(config.options?.excludePrefixes) ? config.options.excludePrefixes.filter((v) => typeof v === "string") : typeof config.options?.excludePrefix === "string" ? [config.options.excludePrefix] : [];
1058
1580
  if (!excludePrefixes.includes("for-agents")) excludePrefixes.push("for-agents");
1059
1581
  return scanMarkdownDocs(root, contentDir, {
@@ -1089,15 +1611,23 @@ var humanConfigs = (config) => {
1089
1611
  if (!human) return [];
1090
1612
  return Array.isArray(human) ? human : [human];
1091
1613
  };
1614
+ var canonicalPath = (path) => {
1615
+ try {
1616
+ return realpathSync4.native(path);
1617
+ } catch {
1618
+ return resolve4(path);
1619
+ }
1620
+ };
1092
1621
  var scanHumanDocRecords = (root, config) => {
1093
1622
  const out = [];
1094
1623
  const seen = /* @__PURE__ */ new Set();
1095
- const agentRoot = config.corpus.agent.root.replace(/\/$/, "");
1624
+ const agentRoot = canonicalPath(resolve4(root, config.corpus.agent.root));
1096
1625
  for (const human of humanConfigs(config)) {
1097
1626
  const adapter = ADAPTERS.find((candidate) => candidate.plugin === human.plugin);
1098
1627
  if (!adapter) continue;
1099
1628
  for (const record of adapter.scan({ root, config: human })) {
1100
- if (record.path === agentRoot || record.path.startsWith(`${agentRoot}/`) || record.path.includes("/for-agents/") || record.path.endsWith("/for-agents")) {
1629
+ const recordPath = canonicalPath(record.path);
1630
+ if (recordPath === agentRoot || recordPath.startsWith(`${agentRoot}${sep3}`) || record.path.includes("/for-agents/") || record.path.endsWith("/for-agents")) {
1101
1631
  continue;
1102
1632
  }
1103
1633
  if (seen.has(record.id)) continue;
@@ -1110,26 +1640,26 @@ var scanHumanDocRecords = (root, config) => {
1110
1640
  var scanHumanDocs = (root, config) => Object.fromEntries(scanHumanDocRecords(root, config).map((doc) => [doc.id, doc.url]));
1111
1641
 
1112
1642
  // src/index-builder/plugins/pnpm-monorepo.ts
1113
- import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
1114
- import { basename as basename2, join as join9 } from "path";
1643
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
1644
+ import { basename as basename2, join as join6 } from "path";
1115
1645
 
1116
1646
  // src/lib/glob-expand.ts
1117
- import { existsSync as existsSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
1118
- import { join as join8 } from "path";
1647
+ import { existsSync as existsSync6, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
1648
+ import { join as join5 } from "path";
1119
1649
  var expandWorkspaceGlobs = (root, patterns) => {
1120
1650
  const dirs = /* @__PURE__ */ new Set();
1121
1651
  for (const pattern of patterns) {
1122
1652
  const normalized = toPosix(pattern).replace(/\/$/, "");
1123
1653
  if (!normalized.includes("*")) {
1124
- const abs = join8(root, normalized);
1125
- if (existsSync5(abs)) dirs.add(toPosix(abs));
1654
+ const abs = join5(root, normalized);
1655
+ if (existsSync6(abs)) dirs.add(toPosix(abs));
1126
1656
  continue;
1127
1657
  }
1128
1658
  const star = normalized.indexOf("*");
1129
- const base = join8(root, normalized.slice(0, star).replace(/\/$/, ""));
1130
- if (!existsSync5(base)) continue;
1659
+ const base = join5(root, normalized.slice(0, star).replace(/\/$/, ""));
1660
+ if (!existsSync6(base)) continue;
1131
1661
  for (const name of readdirSync2(base)) {
1132
- const abs = join8(base, name);
1662
+ const abs = join5(base, name);
1133
1663
  try {
1134
1664
  if (statSync2(abs).isDirectory()) dirs.add(toPosix(abs));
1135
1665
  } catch {
@@ -1161,10 +1691,10 @@ var parsePnpmWorkspace = (yaml) => {
1161
1691
  return patterns;
1162
1692
  };
1163
1693
  var readPackageJson = (dir) => {
1164
- const file = join9(dir, "package.json");
1165
- if (!existsSync6(file)) return null;
1694
+ const file = join6(dir, "package.json");
1695
+ if (!existsSync7(file)) return null;
1166
1696
  try {
1167
- return JSON.parse(readFileSync7(file, "utf8"));
1697
+ return JSON.parse(readFileSync5(file, "utf8"));
1168
1698
  } catch {
1169
1699
  return null;
1170
1700
  }
@@ -1173,9 +1703,9 @@ var discoverPnpmPackages = (root, config) => {
1173
1703
  const explicit = config.routing?.options?.packages;
1174
1704
  let patterns = explicit;
1175
1705
  if (!patterns?.length) {
1176
- const workspaceFile = join9(root, "pnpm-workspace.yaml");
1177
- if (existsSync6(workspaceFile)) {
1178
- patterns = parsePnpmWorkspace(readFileSync7(workspaceFile, "utf8"));
1706
+ const workspaceFile = join6(root, "pnpm-workspace.yaml");
1707
+ if (existsSync7(workspaceFile)) {
1708
+ patterns = parsePnpmWorkspace(readFileSync5(workspaceFile, "utf8"));
1179
1709
  }
1180
1710
  }
1181
1711
  if (!patterns?.length) return [];
@@ -1196,7 +1726,7 @@ var discoverPnpmPackages = (root, config) => {
1196
1726
  var projectName = (root, config) => {
1197
1727
  if (config.project?.name) return config.project.name;
1198
1728
  try {
1199
- const pkg = JSON.parse(readFileSync8(join10(root, "package.json"), "utf8"));
1729
+ const pkg = JSON.parse(readFileSync6(join7(root, "package.json"), "utf8"));
1200
1730
  if (pkg.name) return pkg.name;
1201
1731
  } catch {
1202
1732
  }
@@ -1204,7 +1734,7 @@ var projectName = (root, config) => {
1204
1734
  };
1205
1735
  var existingGeneratedAt = (indexPath, contentHash) => {
1206
1736
  try {
1207
- const index = JSON.parse(readFileSync8(indexPath, "utf8"));
1737
+ const index = JSON.parse(readFileSync6(indexPath, "utf8"));
1208
1738
  return index.contentHash === contentHash && typeof index.generatedAt === "string" ? index.generatedAt : void 0;
1209
1739
  } catch {
1210
1740
  return void 0;
@@ -1215,7 +1745,7 @@ var buildDocBridgeIndex = (opts) => {
1215
1745
  const config = opts.config;
1216
1746
  const write = opts.write ?? true;
1217
1747
  const outFile = config.index?.outFile ?? ".doc-bridge/index.json";
1218
- const indexPath = join10(root, outFile);
1748
+ const indexPath = join7(root, outFile);
1219
1749
  const corpus = scanAgentCorpus(root, config);
1220
1750
  const knowledge = corpus.map(({ absPath: _a, relPath: _r, frontmatter: _f, ...entry }) => entry);
1221
1751
  const shouldDiscover = config.routing?.plugin === "pnpm-monorepo" || Boolean(config.routing?.options?.packages?.length) || config.routing?.plugin === "npm-workspaces" || config.routing?.plugin === "yarn-workspaces";
@@ -1250,7 +1780,7 @@ var buildDocBridgeIndex = (opts) => {
1250
1780
  if (config.index?.llmsTxt?.enabled !== false) {
1251
1781
  const llmsOut = config.index?.llmsTxt?.outFile ?? "llms.txt";
1252
1782
  llmsTxtRelPath = toPosix(llmsOut);
1253
- llmsTxtPath = join10(root, llmsOut);
1783
+ llmsTxtPath = join7(root, llmsOut);
1254
1784
  if (write) {
1255
1785
  writeFileSync(
1256
1786
  llmsTxtPath,
@@ -1262,7 +1792,7 @@ var buildDocBridgeIndex = (opts) => {
1262
1792
  let capabilitiesPath;
1263
1793
  if (config.index?.capabilities?.enabled !== false) {
1264
1794
  const capabilitiesOut = config.index?.capabilities?.outFile ?? ".doc-bridge/capabilities.json";
1265
- capabilitiesPath = join10(root, capabilitiesOut);
1795
+ capabilitiesPath = join7(root, capabilitiesOut);
1266
1796
  if (write) {
1267
1797
  mkdirSync(dirname3(capabilitiesPath), { recursive: true });
1268
1798
  writeFileSync(
@@ -1283,9 +1813,366 @@ var buildDocBridgeIndex = (opts) => {
1283
1813
  };
1284
1814
  };
1285
1815
 
1816
+ // src/conformance/documentation-standard-v1.ts
1817
+ var DOCUMENTATION_STANDARD_V1_ID = "documentation-standard-v1";
1818
+ var DOCUMENTATION_STANDARD_V1_STATUS = "stable";
1819
+ var MAX_TEXT_EVIDENCE_BYTES = 4 * 1024 * 1024;
1820
+ var safePath = (root, path) => {
1821
+ const rootAbs = realpathSync5.native(resolve5(root));
1822
+ const unresolved = resolve5(rootAbs, path);
1823
+ const unresolvedRel = relative3(rootAbs, unresolved);
1824
+ if (isAbsolute3(unresolvedRel) || unresolvedRel === ".." || unresolvedRel.startsWith(`..${sep4}`)) return void 0;
1825
+ if (!existsSync8(unresolved)) return unresolved;
1826
+ try {
1827
+ const abs = realpathSync5.native(unresolved);
1828
+ const rel = relative3(rootAbs, abs);
1829
+ return !isAbsolute3(rel) && rel !== ".." && !rel.startsWith(`..${sep4}`) ? abs : void 0;
1830
+ } catch {
1831
+ return void 0;
1832
+ }
1833
+ };
1834
+ var fileEvidence = (root, path, options) => {
1835
+ const abs = safePath(root, path);
1836
+ if (!abs) {
1837
+ return {
1838
+ exists: false,
1839
+ content: "",
1840
+ evidence: { path, detail: "Path escapes the project root." }
1841
+ };
1842
+ }
1843
+ if (!existsSync8(abs)) {
1844
+ return { exists: false, content: "", evidence: { path, detail: "File does not exist." } };
1845
+ }
1846
+ try {
1847
+ const stat = statSync3(abs);
1848
+ if (!stat.isFile()) {
1849
+ return { exists: false, content: "", evidence: { path, detail: "Path is not a regular file." } };
1850
+ }
1851
+ if (stat.size === 0) {
1852
+ return { exists: false, content: "", evidence: { path, detail: "File is empty." } };
1853
+ }
1854
+ if (options?.readContent === false) {
1855
+ return {
1856
+ exists: true,
1857
+ content: "",
1858
+ evidence: { path: toPosix(relative3(resolve5(root), abs)) || ".", detail: "File exists and is non-empty." }
1859
+ };
1860
+ }
1861
+ if (stat.size > MAX_TEXT_EVIDENCE_BYTES) {
1862
+ return {
1863
+ exists: false,
1864
+ content: "",
1865
+ evidence: { path, detail: `Text evidence exceeds ${MAX_TEXT_EVIDENCE_BYTES} bytes.` }
1866
+ };
1867
+ }
1868
+ const content = readFileSync7(abs, "utf8");
1869
+ return {
1870
+ exists: content.trim().length > 0,
1871
+ content,
1872
+ evidence: {
1873
+ path: toPosix(relative3(resolve5(root), abs)) || ".",
1874
+ detail: content.trim().length > 0 ? "File exists and is non-empty." : "File is empty."
1875
+ }
1876
+ };
1877
+ } catch {
1878
+ return { exists: false, content: "", evidence: { path, detail: "File is not readable text." } };
1879
+ }
1880
+ };
1881
+ var resultWithException = (draft, options) => {
1882
+ if (draft.passed) {
1883
+ const { passed: _passed2, ...result2 } = draft;
1884
+ return { ...result2, status: "pass", ok: true };
1885
+ }
1886
+ const exception = options.exceptions?.find((candidate) => candidate.ruleId === draft.id);
1887
+ const { passed: _passed, ...result } = draft;
1888
+ if (!exception) return { ...result, status: "fail", ok: false };
1889
+ return {
1890
+ ...result,
1891
+ status: "excepted",
1892
+ ok: true,
1893
+ exception: {
1894
+ reason: exception.reason,
1895
+ approvedBy: exception.approvedBy,
1896
+ trackingUrl: exception.trackingUrl
1897
+ }
1898
+ };
1899
+ };
1900
+ var humanDocsRule = (root, config) => {
1901
+ const docs = scanHumanDocRecords(root, config);
1902
+ return {
1903
+ id: "human-docs",
1904
+ level: "required",
1905
+ passed: docs.length > 0,
1906
+ message: docs.length > 0 ? `Found ${docs.length} human document(s).` : "No human documentation was discovered.",
1907
+ evidence: docs.slice(0, 10).map((doc) => ({
1908
+ path: toPosix(relative3(resolve5(root), doc.path)),
1909
+ detail: `Human route: ${doc.url}`
1910
+ })),
1911
+ remediation: {
1912
+ command: "edit doc-bridge.config.json",
1913
+ detail: "Configure corpus.human with a supported adapter and a non-agent documentation root."
1914
+ }
1915
+ };
1916
+ };
1917
+ var llmsRule = (root, config, options) => {
1918
+ const llmsPath = config.index?.llmsTxt?.outFile ?? "llms.txt";
1919
+ const llmsKey = safePath(root, llmsPath) ?? resolve5(root, llmsPath);
1920
+ const rawSources = /* @__PURE__ */ new Map();
1921
+ for (const path of options.rawSources ?? []) {
1922
+ const key = safePath(root, path) ?? resolve5(root, path);
1923
+ if (key !== llmsKey && !rawSources.has(key)) rawSources.set(key, path);
1924
+ }
1925
+ const paths = [llmsPath, ...rawSources.values()];
1926
+ const evidence = paths.map((path) => fileEvidence(root, path));
1927
+ const generated = buildDocBridgeIndex({ root, config, write: false }).index;
1928
+ const expectedLlms = renderLlmsTxt(config, generated.knowledge, generated.project?.name ?? "project");
1929
+ const llmsIsFresh = evidence[0]?.content === expectedLlms;
1930
+ if (evidence[0]?.exists) {
1931
+ evidence[0] = {
1932
+ ...evidence[0],
1933
+ evidence: {
1934
+ ...evidence[0].evidence,
1935
+ detail: llmsIsFresh ? "File matches the deterministic ak-docs output." : "File is stale or was not generated by the current ak-docs inputs."
1936
+ }
1937
+ };
1938
+ }
1939
+ const passed = config.index?.llmsTxt?.enabled !== false && paths.length > 1 && llmsIsFresh && evidence.every((item) => item.exists);
1940
+ return {
1941
+ id: "llms-and-raw-source",
1942
+ level: "required",
1943
+ passed,
1944
+ 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.",
1945
+ evidence: evidence.map((item) => item.evidence),
1946
+ remediation: {
1947
+ command: "ak-docs index",
1948
+ detail: "Generate llms.txt and configure conformance.documentationStandardV1.rawSources."
1949
+ }
1950
+ };
1951
+ };
1952
+ var normalizedUrl = (value) => value.replace(/\/$/, "");
1953
+ var ecosystemContract = (root, options) => {
1954
+ const declaration = options.ecosystemContract;
1955
+ if (!declaration) {
1956
+ return {
1957
+ passed: false,
1958
+ urls: /* @__PURE__ */ new Set(),
1959
+ evidence: [{ path: "doc-bridge.config.json", detail: "Canonical ecosystem contract evidence is not declared." }]
1960
+ };
1961
+ }
1962
+ const manifestFile = fileEvidence(root, declaration.manifest);
1963
+ const claimsFile = fileEvidence(root, declaration.claims);
1964
+ const evidence = [manifestFile.evidence, claimsFile.evidence];
1965
+ if (!manifestFile.exists || !claimsFile.exists) return { passed: false, urls: /* @__PURE__ */ new Set(), evidence };
1966
+ try {
1967
+ const manifest = JSON.parse(manifestFile.content);
1968
+ const claims = JSON.parse(claimsFile.content);
1969
+ const contract = parseCanonicalEcosystemContract(manifest, claims);
1970
+ const productIds = contract.manifest.products.map((product) => product.id);
1971
+ if (!productIds.includes(declaration.productId)) throw new Error(`Manifest is missing product ${declaration.productId}.`);
1972
+ const urls = /* @__PURE__ */ new Set();
1973
+ for (const product of contract.manifest.products) {
1974
+ for (const value of [
1975
+ product.surfaces.home,
1976
+ product.surfaces.docs,
1977
+ product.surfaces.llms,
1978
+ product.surfaces.stats
1979
+ ]) {
1980
+ if (typeof value === "string" && /^https:\/\//.test(value)) urls.add(normalizedUrl(value));
1981
+ }
1982
+ }
1983
+ evidence[0] = { path: declaration.manifest, detail: `Validated ${productIds.length} canonical product(s), including ${declaration.productId}.` };
1984
+ evidence[1] = { path: declaration.claims, detail: `Validated claim-ledger identity for ${contract.claims.products.length} product(s).` };
1985
+ return { passed: urls.size > 0, urls, evidence };
1986
+ } catch (error) {
1987
+ evidence.push({
1988
+ path: `${declaration.manifest}, ${declaration.claims}`,
1989
+ detail: error instanceof Error ? error.message : "Canonical ecosystem contract is invalid."
1990
+ });
1991
+ return { passed: false, urls: /* @__PURE__ */ new Set(), evidence };
1992
+ }
1993
+ };
1994
+ var handoffsRule = (root, config) => {
1995
+ const index = buildDocBridgeIndex({ root, config, write: false }).index;
1996
+ const handoffs = Object.values(index.handoffs ?? {});
1997
+ const ready = handoffs.filter(
1998
+ (handoff) => handoff.startHere.length > 0 && handoff.editRoots.length > 0 && handoff.checks.length > 0 && (handoff.bridge?.humanDoc === "linked" || handoff.bridge?.humanDoc === "external")
1999
+ );
2000
+ return {
2001
+ id: "agent-handoffs",
2002
+ level: "required",
2003
+ passed: ready.length > 0 && ready.length === handoffs.length,
2004
+ 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.`,
2005
+ evidence: handoffs.map((handoff) => ({
2006
+ path: handoff.startHere,
2007
+ detail: `${handoff.target.id}: ${handoff.editRoots.length} edit root(s), ${handoff.checks.length} check(s), bridge=${handoff.bridge?.humanDoc ?? "none"}`
2008
+ })),
2009
+ remediation: {
2010
+ command: "ak-docs bootstrap agent-docs && ak-docs index",
2011
+ detail: "Add ownership checks and a resolvable humanDoc for every handoff."
2012
+ }
2013
+ };
2014
+ };
2015
+ var contributionRule = (root, options) => {
2016
+ const paths = options.contributionPaths?.length ? options.contributionPaths : ["CONTRIBUTING.md"];
2017
+ const evidence = paths.map((path) => fileEvidence(root, path));
2018
+ return {
2019
+ id: "contribution",
2020
+ level: "required",
2021
+ passed: evidence.some((item) => item.exists),
2022
+ message: evidence.some((item) => item.exists) ? "Contribution guidance is available." : "Contribution guidance is missing.",
2023
+ evidence: evidence.map((item) => item.evidence),
2024
+ remediation: {
2025
+ command: "edit CONTRIBUTING.md",
2026
+ detail: "Document setup, validation commands, and the pull-request workflow."
2027
+ }
2028
+ };
2029
+ };
2030
+ var markersRule = (root, options, kind, level) => {
2031
+ const declarations = options[kind === "metadata" ? "metadata" : "diagrams"] ?? [];
2032
+ const evidence = [];
2033
+ let passed = declarations.length > 0;
2034
+ for (const declaration of declarations) {
2035
+ const file = fileEvidence(root, declaration.path);
2036
+ const missing = declaration.contains.filter((marker) => !file.content.includes(marker));
2037
+ if (!file.exists || missing.length > 0) passed = false;
2038
+ evidence.push({
2039
+ path: declaration.path,
2040
+ detail: !file.exists ? file.evidence.detail : missing.length ? `Missing marker(s): ${missing.join(", ")}` : `Found marker(s): ${declaration.contains.join(", ")}`
2041
+ });
2042
+ }
2043
+ return {
2044
+ id: kind,
2045
+ level,
2046
+ passed,
2047
+ message: passed ? `${kind} evidence is complete.` : `${kind} evidence is incomplete.`,
2048
+ evidence,
2049
+ remediation: {
2050
+ command: "edit doc-bridge.config.json",
2051
+ detail: `Declare ${kind} evidence paths and markers that exist in the repository.`
2052
+ }
2053
+ };
2054
+ };
2055
+ var linksRule = (root, options) => {
2056
+ const links = options.links ?? [];
2057
+ const contract = ecosystemContract(root, options);
2058
+ const evidence = [...contract.evidence];
2059
+ let passed = links.length > 0 && contract.passed;
2060
+ for (const link of links) {
2061
+ const sources = link.paths.map((path) => ({ path, file: fileEvidence(root, path) }));
2062
+ const matches = sources.filter(({ file }) => file.exists && file.content.includes(link.url));
2063
+ const canonical = contract.urls.has(normalizedUrl(link.url));
2064
+ if (matches.length === 0 || !canonical) passed = false;
2065
+ evidence.push({
2066
+ path: sources.map((source) => source.path).join(", "),
2067
+ 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.`
2068
+ });
2069
+ }
2070
+ return {
2071
+ id: "cross-links",
2072
+ level: "required",
2073
+ passed,
2074
+ message: passed ? `${links.length} required ecosystem link(s) resolve in source.` : "One or more required ecosystem links are missing from source.",
2075
+ evidence,
2076
+ remediation: {
2077
+ command: "edit README.md",
2078
+ detail: "Sync the canonical ecosystem snapshots and add each configured canonical URL to a declared documentation source."
2079
+ }
2080
+ };
2081
+ };
2082
+ var quickstartsRule = (root, options) => {
2083
+ const quickstarts = options.quickstarts ?? [];
2084
+ const evidence = [];
2085
+ let passed = quickstarts.length > 0;
2086
+ for (const quickstart of quickstarts) {
2087
+ const doc = fileEvidence(root, quickstart.doc);
2088
+ const test = fileEvidence(root, quickstart.test);
2089
+ const missingMarkers = quickstart.testContains.filter((marker) => !test.content.includes(marker));
2090
+ if (!doc.exists || !test.exists || missingMarkers.length > 0 || !quickstart.command.trim()) passed = false;
2091
+ evidence.push(
2092
+ { path: quickstart.doc, detail: `${quickstart.id}: ${doc.evidence.detail}` },
2093
+ {
2094
+ path: quickstart.test,
2095
+ detail: missingMarkers.length ? `${quickstart.id}: missing test marker(s): ${missingMarkers.join(", ")}` : `${quickstart.id}: test evidence; CI command: ${quickstart.command}`
2096
+ }
2097
+ );
2098
+ }
2099
+ return {
2100
+ id: "tested-quickstarts",
2101
+ level: "required",
2102
+ passed,
2103
+ message: passed ? `${quickstarts.length} quickstart(s) have executable test evidence.` : "Quickstart test evidence is incomplete.",
2104
+ evidence,
2105
+ remediation: {
2106
+ command: "pnpm test",
2107
+ detail: "Map every quickstart to a documentation path, test file, identifying marker, and CI command."
2108
+ }
2109
+ };
2110
+ };
2111
+ var visualsRule = (root, options) => {
2112
+ const visuals = options.visuals ?? [];
2113
+ const evidence = visuals.map((path) => fileEvidence(root, path, { readContent: false }));
2114
+ return {
2115
+ id: "visual-explanations",
2116
+ level: "recommended",
2117
+ passed: visuals.length > 0 && evidence.every((item) => item.exists),
2118
+ message: visuals.length > 0 && evidence.every((item) => item.exists) ? `${visuals.length} visual asset(s) found.` : "Visual explanation evidence is incomplete.",
2119
+ evidence: evidence.map((item) => item.evidence),
2120
+ remediation: {
2121
+ command: "edit doc-bridge.config.json",
2122
+ detail: "Declare the images or animations that explain the product workflow."
2123
+ }
2124
+ };
2125
+ };
2126
+ var count = (results, level, status) => results.filter((result) => result.level === level && result.status === status).length;
2127
+ var runDocumentationStandardV1 = (root, config) => {
2128
+ const options = config.conformance?.documentationStandardV1 ?? {};
2129
+ const drafts = [
2130
+ humanDocsRule(root, config),
2131
+ llmsRule(root, config, options),
2132
+ handoffsRule(root, config),
2133
+ contributionRule(root, options),
2134
+ markersRule(root, options, "metadata", "required"),
2135
+ linksRule(root, options),
2136
+ quickstartsRule(root, options),
2137
+ visualsRule(root, options),
2138
+ markersRule(root, options, "structured-diagrams", "recommended")
2139
+ ];
2140
+ const results = drafts.map((draft) => resultWithException(draft, options));
2141
+ return {
2142
+ schemaVersion: 1,
2143
+ profile: { id: DOCUMENTATION_STANDARD_V1_ID, version: 1, status: DOCUMENTATION_STANDARD_V1_STATUS },
2144
+ ok: results.filter((result) => result.level === "required").every((result) => result.ok),
2145
+ recommendedOk: results.filter((result) => result.level === "recommended").every((result) => result.ok),
2146
+ summary: {
2147
+ required: {
2148
+ passed: count(results, "required", "pass"),
2149
+ failed: count(results, "required", "fail"),
2150
+ excepted: count(results, "required", "excepted")
2151
+ },
2152
+ recommended: {
2153
+ passed: count(results, "recommended", "pass"),
2154
+ failed: count(results, "recommended", "fail"),
2155
+ excepted: count(results, "recommended", "excepted")
2156
+ }
2157
+ },
2158
+ results
2159
+ };
2160
+ };
2161
+ var formatDocumentationStandardText = (report) => [
2162
+ `Documentation Standard v1 (${report.profile.status})`,
2163
+ `Required: ${report.summary.required.passed} passed \xB7 ${report.summary.required.failed} failed \xB7 ${report.summary.required.excepted} excepted`,
2164
+ `Recommended: ${report.summary.recommended.passed} passed \xB7 ${report.summary.recommended.failed} failed \xB7 ${report.summary.recommended.excepted} excepted`,
2165
+ "",
2166
+ ...report.results.flatMap((result) => [
2167
+ `${result.status === "pass" ? "PASS" : result.status === "excepted" ? "EXCEPTED" : "FAIL"} [${result.level}] ${result.id}: ${result.message}`,
2168
+ ...result.evidence.map((evidence) => ` evidence: ${evidence.path} \u2014 ${evidence.detail}`),
2169
+ ...result.exception ? [` exception: ${result.exception.reason} \u2014 ${result.exception.approvedBy} (${result.exception.trackingUrl})`] : result.ok ? [] : [` fix: ${result.remediation.command} \u2014 ${result.remediation.detail}`]
2170
+ ])
2171
+ ];
2172
+
1286
2173
  // src/federation/llms.ts
1287
- import { existsSync as existsSync7, readFileSync as readFileSync9 } from "fs";
1288
- import { resolve as resolve3 } from "path";
2174
+ import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
2175
+ import { resolve as resolve6 } from "path";
1289
2176
 
1290
2177
  // src/query/search.ts
1291
2178
  var tokenize = (value) => value.toLowerCase().split(/[^a-z0-9@/_-]+/).filter((t) => t.length >= 2);
@@ -1414,9 +2301,9 @@ var defaultFetchText = async (url) => {
1414
2301
  var sourceText = async (root, source, fetchText) => {
1415
2302
  try {
1416
2303
  if (/^https?:\/\//.test(source)) return await fetchText(source);
1417
- const path = resolve3(root, source);
1418
- if (!existsSync7(path)) return null;
1419
- return readFileSync9(path, "utf8");
2304
+ const path = resolve6(root, source);
2305
+ if (!existsSync9(path)) return null;
2306
+ return readFileSync8(path, "utf8");
1420
2307
  } catch {
1421
2308
  return null;
1422
2309
  }
@@ -1501,16 +2388,16 @@ var retrieveHybridChunks = async (root, config, index, query, options = {}) => {
1501
2388
  };
1502
2389
 
1503
2390
  // src/gates/run-gates.ts
1504
- import { readFileSync as readFileSync11 } from "fs";
2391
+ import { readFileSync as readFileSync10 } from "fs";
1505
2392
 
1506
2393
  // src/query/load-index.ts
1507
- import { existsSync as existsSync8, readFileSync as readFileSync10 } from "fs";
1508
- import { join as join11, resolve as resolve4 } from "path";
2394
+ import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
2395
+ import { join as join8, resolve as resolve7 } from "path";
1509
2396
 
1510
2397
  // src/schemas/agent-handoff.ts
1511
- import { z as z2 } from "zod";
2398
+ import { z as z3 } from "zod";
1512
2399
  var HANDOFF_SCHEMA_VERSION = 1;
1513
- var HandoffTargetTypeSchema = z2.enum([
2400
+ var HandoffTargetTypeSchema = z3.enum([
1514
2401
  "package",
1515
2402
  "module",
1516
2403
  "app",
@@ -1521,133 +2408,133 @@ var HandoffTargetTypeSchema = z2.enum([
1521
2408
  "change",
1522
2409
  "search"
1523
2410
  ]);
1524
- var HandoffTargetSchema = z2.object({
2411
+ var HandoffTargetSchema = z3.object({
1525
2412
  type: HandoffTargetTypeSchema,
1526
- id: z2.string().min(1).max(256),
1527
- path: z2.string().min(1).max(512).optional(),
1528
- group: z2.string().min(1).max(128).optional(),
1529
- layer: z2.string().min(1).max(32).optional()
2413
+ id: z3.string().min(1).max(256),
2414
+ path: z3.string().min(1).max(512).optional(),
2415
+ group: z3.string().min(1).max(128).optional(),
2416
+ layer: z3.string().min(1).max(32).optional()
1530
2417
  }).strict();
1531
- var HandoffBridgeSchema = z2.object({
1532
- humanDoc: z2.enum(["linked", "missing", "external"]),
1533
- action: z2.string().min(1).max(256).optional(),
1534
- bootstrap: z2.string().min(1).max(256).optional()
2418
+ var HandoffBridgeSchema = z3.object({
2419
+ humanDoc: z3.enum(["linked", "missing", "external"]),
2420
+ action: z3.string().min(1).max(256).optional(),
2421
+ bootstrap: z3.string().min(1).max(256).optional()
1535
2422
  }).strict();
1536
- var AgentHandoffV1Schema = z2.object({
1537
- type: z2.literal("agent-handoff"),
1538
- schemaVersion: z2.literal(HANDOFF_SCHEMA_VERSION).default(HANDOFF_SCHEMA_VERSION),
1539
- source: z2.string().min(1).max(512),
2423
+ var AgentHandoffV1Schema = z3.object({
2424
+ type: z3.literal("agent-handoff"),
2425
+ schemaVersion: z3.literal(HANDOFF_SCHEMA_VERSION).default(HANDOFF_SCHEMA_VERSION),
2426
+ source: z3.string().min(1).max(512),
1540
2427
  target: HandoffTargetSchema,
1541
- startHere: z2.string().min(1).max(512),
1542
- readBeforeEditing: z2.array(z2.string().min(1).max(512)).max(64),
1543
- editRoots: z2.array(z2.string().min(1).max(512)).max(32),
1544
- checks: z2.array(z2.string().min(1).max(256)).max(32),
1545
- humanDoc: z2.string().min(1).max(512).nullable().optional(),
2428
+ startHere: z3.string().min(1).max(512),
2429
+ readBeforeEditing: z3.array(z3.string().min(1).max(512)).max(64),
2430
+ editRoots: z3.array(z3.string().min(1).max(512)).max(32),
2431
+ checks: z3.array(z3.string().min(1).max(256)).max(32),
2432
+ humanDoc: z3.string().min(1).max(512).nullable().optional(),
1546
2433
  bridge: HandoffBridgeSchema.optional(),
1547
- playbookPatterns: z2.array(z2.string().url()).max(16).optional(),
1548
- notes: z2.array(z2.string().min(1).max(1024)).max(16)
2434
+ playbookPatterns: z3.array(z3.string().url()).max(16).optional(),
2435
+ notes: z3.array(z3.string().min(1).max(1024)).max(16)
1549
2436
  }).strict();
1550
2437
  var AgentHandoffLegacySchema = AgentHandoffV1Schema.omit({ schemaVersion: true }).extend({
1551
- schemaVersion: z2.literal(HANDOFF_SCHEMA_VERSION).optional()
2438
+ schemaVersion: z3.literal(HANDOFF_SCHEMA_VERSION).optional()
1552
2439
  });
1553
- var AgentSearchMatchSchema = z2.object({
1554
- type: z2.string().min(1).max(64),
1555
- id: z2.string().min(1).max(256),
1556
- path: z2.string().min(1).max(512),
1557
- summary: z2.string().max(2048).optional(),
1558
- score: z2.number().optional(),
1559
- refs: z2.number().int().nonnegative().optional()
2440
+ var AgentSearchMatchSchema = z3.object({
2441
+ type: z3.string().min(1).max(64),
2442
+ id: z3.string().min(1).max(256),
2443
+ path: z3.string().min(1).max(512),
2444
+ summary: z3.string().max(2048).optional(),
2445
+ score: z3.number().optional(),
2446
+ refs: z3.number().int().nonnegative().optional()
1560
2447
  }).strict();
1561
- var AgentSearchV1Schema = z2.object({
1562
- type: z2.literal("agent-search"),
1563
- schemaVersion: z2.literal(HANDOFF_SCHEMA_VERSION).default(HANDOFF_SCHEMA_VERSION),
1564
- source: z2.string().min(1).max(512),
1565
- term: z2.string().min(1).max(512),
1566
- count: z2.number().int().nonnegative(),
2448
+ var AgentSearchV1Schema = z3.object({
2449
+ type: z3.literal("agent-search"),
2450
+ schemaVersion: z3.literal(HANDOFF_SCHEMA_VERSION).default(HANDOFF_SCHEMA_VERSION),
2451
+ source: z3.string().min(1).max(512),
2452
+ term: z3.string().min(1).max(512),
2453
+ count: z3.number().int().nonnegative(),
1567
2454
  bestMatch: AgentSearchMatchSchema.nullable(),
1568
- matches: z2.array(AgentSearchMatchSchema).max(32),
1569
- nextCommands: z2.array(z2.string().min(1).max(512)).max(16)
2455
+ matches: z3.array(AgentSearchMatchSchema).max(32),
2456
+ nextCommands: z3.array(z3.string().min(1).max(512)).max(16)
1570
2457
  }).strict();
1571
2458
  var normalizeAgentHandoff = (input) => AgentHandoffV1Schema.parse(AgentHandoffLegacySchema.parse(input));
1572
2459
 
1573
2460
  // src/schemas/doc-bridge-index.ts
1574
- import { z as z3 } from "zod";
2461
+ import { z as z4 } from "zod";
1575
2462
  var INDEX_SCHEMA_VERSION = 1;
1576
- var ContentHashAlgoSchema = z3.literal("sha256-normalized-v1");
1577
- var EcosystemPropertySchema = z3.object({
1578
- id: z3.string().min(1).max(64),
1579
- name: z3.string().min(1).max(128),
1580
- url: z3.string().url().optional(),
1581
- llms: z3.string().url().optional()
2463
+ var ContentHashAlgoSchema = z4.literal("sha256-normalized-v1");
2464
+ var EcosystemPropertySchema = z4.object({
2465
+ id: z4.string().min(1).max(64),
2466
+ name: z4.string().min(1).max(128),
2467
+ url: z4.string().url().optional(),
2468
+ llms: z4.string().url().optional()
1582
2469
  }).strict();
1583
- var KnowledgeEntrySchema = z3.object({
1584
- id: z3.string().min(1).max(256),
1585
- type: z3.string().min(1).max(128),
1586
- title: z3.string().min(1).max(256),
1587
- path: z3.string().min(1).max(512),
1588
- description: z3.string().max(2048).optional(),
2470
+ var KnowledgeEntrySchema = z4.object({
2471
+ id: z4.string().min(1).max(256),
2472
+ type: z4.string().min(1).max(128),
2473
+ title: z4.string().min(1).max(256),
2474
+ path: z4.string().min(1).max(512),
2475
+ description: z4.string().max(2048).optional(),
1589
2476
  /** Flattened body excerpt for full-text search (not for display). */
1590
- body: z3.string().max(8e3).optional(),
1591
- links: z3.array(z3.string().min(1).max(512)).max(64).optional(),
1592
- tags: z3.array(z3.string().min(1).max(64)).max(32).optional()
2477
+ body: z4.string().max(8e3).optional(),
2478
+ links: z4.array(z4.string().min(1).max(512)).max(64).optional(),
2479
+ tags: z4.array(z4.string().min(1).max(64)).max(32).optional()
1593
2480
  }).strict();
1594
- var CapabilityRefSchema = z3.object({
1595
- id: z3.string().min(1).max(256),
1596
- kind: z3.string().min(1).max(64),
1597
- description: z3.string().max(512).optional()
2481
+ var CapabilityRefSchema = z4.object({
2482
+ id: z4.string().min(1).max(256),
2483
+ kind: z4.string().min(1).max(64),
2484
+ description: z4.string().max(512).optional()
1598
2485
  }).strict();
1599
- var OwnershipRecordSchema = z3.object({
1600
- id: z3.string().min(1).max(256),
1601
- path: z3.string().min(1).max(512),
1602
- group: z3.string().min(1).max(128).optional(),
1603
- layer: z3.string().min(1).max(32).optional(),
1604
- purpose: z3.string().max(1024).optional(),
1605
- checks: z3.array(z3.string().min(1).max(256)).max(32),
1606
- agentDoc: z3.string().min(1).max(512).optional(),
1607
- humanDoc: z3.string().min(1).max(512).optional(),
1608
- readme: z3.string().min(1).max(512).optional()
2486
+ var OwnershipRecordSchema = z4.object({
2487
+ id: z4.string().min(1).max(256),
2488
+ path: z4.string().min(1).max(512),
2489
+ group: z4.string().min(1).max(128).optional(),
2490
+ layer: z4.string().min(1).max(32).optional(),
2491
+ purpose: z4.string().max(1024).optional(),
2492
+ checks: z4.array(z4.string().min(1).max(256)).max(32),
2493
+ agentDoc: z4.string().min(1).max(512).optional(),
2494
+ humanDoc: z4.string().min(1).max(512).optional(),
2495
+ readme: z4.string().min(1).max(512).optional()
1609
2496
  }).strict();
1610
- var IndexLookupSchema = z3.object({
1611
- packages: z3.array(z3.string().min(1).max(256)).max(2e3),
1612
- ownership: z3.record(z3.string().min(1).max(256), OwnershipRecordSchema).optional(),
1613
- intents: z3.record(
1614
- z3.string().min(1).max(128),
1615
- z3.object({
1616
- id: z3.string().min(1).max(128),
1617
- title: z3.string().min(1).max(256),
1618
- paths: z3.array(z3.string().min(1).max(512)).max(32)
2497
+ var IndexLookupSchema = z4.object({
2498
+ packages: z4.array(z4.string().min(1).max(256)).max(2e3),
2499
+ ownership: z4.record(z4.string().min(1).max(256), OwnershipRecordSchema).optional(),
2500
+ intents: z4.record(
2501
+ z4.string().min(1).max(128),
2502
+ z4.object({
2503
+ id: z4.string().min(1).max(128),
2504
+ title: z4.string().min(1).max(256),
2505
+ paths: z4.array(z4.string().min(1).max(512)).max(32)
1619
2506
  }).strict()
1620
2507
  ).optional(),
1621
- changes: z3.record(
1622
- z3.string().min(1).max(128),
1623
- z3.object({
1624
- id: z3.string().min(1).max(128),
1625
- title: z3.string().min(1).max(256),
1626
- startHere: z3.string().min(1).max(512),
1627
- relatedPackages: z3.array(z3.string().min(1).max(256)).max(32).optional()
2508
+ changes: z4.record(
2509
+ z4.string().min(1).max(128),
2510
+ z4.object({
2511
+ id: z4.string().min(1).max(128),
2512
+ title: z4.string().min(1).max(256),
2513
+ startHere: z4.string().min(1).max(512),
2514
+ relatedPackages: z4.array(z4.string().min(1).max(256)).max(32).optional()
1628
2515
  }).strict()
1629
2516
  ).optional()
1630
2517
  }).strict();
1631
- var DocBridgeIndexV1Schema = z3.object({
1632
- schemaVersion: z3.literal(INDEX_SCHEMA_VERSION),
1633
- contentHash: z3.string().regex(/^[a-f0-9]{64}$/),
2518
+ var DocBridgeIndexV1Schema = z4.object({
2519
+ schemaVersion: z4.literal(INDEX_SCHEMA_VERSION),
2520
+ contentHash: z4.string().regex(/^[a-f0-9]{64}$/),
1634
2521
  contentHashAlgo: ContentHashAlgoSchema,
1635
- generatedAt: z3.string().datetime().optional(),
1636
- project: z3.object({
1637
- name: z3.string().min(1).max(128),
1638
- root: z3.string().min(1).max(512).optional()
2522
+ generatedAt: z4.string().datetime().optional(),
2523
+ project: z4.object({
2524
+ name: z4.string().min(1).max(128),
2525
+ root: z4.string().min(1).max(512).optional()
1639
2526
  }).strict().optional(),
1640
- properties: z3.array(EcosystemPropertySchema).max(16).optional(),
1641
- knowledge: z3.array(KnowledgeEntrySchema).max(1e4),
1642
- capabilities: z3.array(CapabilityRefSchema).max(5e3).optional(),
1643
- handoffs: z3.record(z3.string().min(1).max(256), AgentHandoffLegacySchema).optional(),
2527
+ properties: z4.array(EcosystemPropertySchema).max(16).optional(),
2528
+ knowledge: z4.array(KnowledgeEntrySchema).max(1e4),
2529
+ capabilities: z4.array(CapabilityRefSchema).max(5e3).optional(),
2530
+ handoffs: z4.record(z4.string().min(1).max(256), AgentHandoffLegacySchema).optional(),
1644
2531
  lookup: IndexLookupSchema.optional()
1645
2532
  }).strict();
1646
2533
 
1647
2534
  // src/schemas/memory-candidate.ts
1648
- import { z as z4 } from "zod";
2535
+ import { z as z5 } from "zod";
1649
2536
  var MEMORY_CANDIDATE_SCHEMA_VERSION = 1;
1650
- var MemorySourceSchema = z4.enum([
2537
+ var MemorySourceSchema = z5.enum([
1651
2538
  "cursor",
1652
2539
  "claude",
1653
2540
  "codex",
@@ -1655,24 +2542,24 @@ var MemorySourceSchema = z4.enum([
1655
2542
  "agent-memory",
1656
2543
  "manual"
1657
2544
  ]);
1658
- var MemorySuggestedTypeSchema = z4.enum([
2545
+ var MemorySuggestedTypeSchema = z5.enum([
1659
2546
  "user",
1660
2547
  "feedback",
1661
2548
  "project",
1662
2549
  "reference",
1663
2550
  "unknown"
1664
2551
  ]);
1665
- var MemoryCandidateV1Schema = z4.object({
1666
- schemaVersion: z4.literal(MEMORY_CANDIDATE_SCHEMA_VERSION),
1667
- id: z4.string().min(1).max(256),
2552
+ var MemoryCandidateV1Schema = z5.object({
2553
+ schemaVersion: z5.literal(MEMORY_CANDIDATE_SCHEMA_VERSION),
2554
+ id: z5.string().min(1).max(256),
1668
2555
  source: MemorySourceSchema,
1669
- rawPath: z4.string().min(1).max(512).optional(),
1670
- fact: z4.string().min(1).max(8e3),
1671
- why: z4.string().max(4e3).optional(),
1672
- howToApply: z4.string().max(4e3).optional(),
2556
+ rawPath: z5.string().min(1).max(512).optional(),
2557
+ fact: z5.string().min(1).max(8e3),
2558
+ why: z5.string().max(4e3).optional(),
2559
+ howToApply: z5.string().max(4e3).optional(),
1673
2560
  suggestedType: MemorySuggestedTypeSchema,
1674
- confidence: z4.number().min(0).max(1),
1675
- references: z4.array(z4.string().min(1).max(512)).max(64)
2561
+ confidence: z5.number().min(0).max(1),
2562
+ references: z5.array(z5.string().min(1).max(512)).max(64)
1676
2563
  }).strict();
1677
2564
 
1678
2565
  // src/validate.ts
@@ -1718,17 +2605,28 @@ var IndexNotFoundError = class extends Error {
1718
2605
  }
1719
2606
  path;
1720
2607
  };
1721
- var indexFilePath = (root, config) => join11(root, config.index?.outFile ?? ".doc-bridge/index.json");
2608
+ var indexFilePath = (root, config) => join8(root, config.index?.outFile ?? ".doc-bridge/index.json");
1722
2609
  var loadDocBridgeIndex = (root, config) => {
1723
2610
  const path = indexFilePath(root, config);
1724
- if (!existsSync8(path)) throw new IndexNotFoundError(path);
1725
- const raw = JSON.parse(readFileSync10(path, "utf8"));
2611
+ if (!existsSync10(path)) throw new IndexNotFoundError(path);
2612
+ const raw = JSON.parse(readFileSync9(path, "utf8"));
1726
2613
  return parseDocBridgeIndex(raw);
1727
2614
  };
1728
2615
 
1729
2616
  // src/gates/run-gates.ts
1730
- var SUPPORTED_GATES = ["index-freshness", "human-guide-links", "okf-type", "docs-style"];
2617
+ var RESERVED_GATE_IDS = /* @__PURE__ */ new Set(["link-rot", "routing-currency", "bootstrap-size"]);
1731
2618
  var runGate = (root, config, id) => {
2619
+ if (id === "documentation-standard-v1") {
2620
+ const details = runDocumentationStandardV1(root, config);
2621
+ return {
2622
+ id,
2623
+ ok: details.ok,
2624
+ message: details.ok ? "Documentation Standard v1 required rules pass" : `${details.summary.required.failed} Documentation Standard v1 required rule(s) failed`,
2625
+ expected: "all required rules pass or have approved exceptions",
2626
+ actual: `${details.summary.required.passed} passed, ${details.summary.required.failed} failed, ${details.summary.required.excepted} excepted`,
2627
+ details
2628
+ };
2629
+ }
1732
2630
  if (id === "human-guide-links") return runHumanGuideLinksGate(root, config);
1733
2631
  if (id === "okf-type") return runOkfTypeGate(root, config);
1734
2632
  if (id === "docs-style") return runDocsStyleGate(root, config);
@@ -1786,7 +2684,7 @@ var runOkfTypeGate = (root, config) => {
1786
2684
  const required = config.corpus.agent.okf?.requireType ?? config.gates?.preset === "strict";
1787
2685
  if (!required) return { id: "okf-type", ok: true, message: "OKF type frontmatter not required" };
1788
2686
  const allowed = config.corpus.agent.okf?.allowedTypes;
1789
- 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));
2687
+ 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));
1790
2688
  if (bad.length) {
1791
2689
  return {
1792
2690
  id: "okf-type",
@@ -1860,7 +2758,7 @@ var runDocsStyleGate = (root, config) => {
1860
2758
  }
1861
2759
  const bad = scanAgentCorpus(root, config).filter((doc) => doc.path !== config.corpus.agent.index).map((doc) => ({
1862
2760
  path: doc.path,
1863
- missing: missingStyleRules(readFileSync11(doc.absPath, "utf8"), required)
2761
+ missing: missingStyleRules(readFileSync10(doc.absPath, "utf8"), required)
1864
2762
  })).filter((doc) => doc.missing.length > 0);
1865
2763
  if (bad.length) {
1866
2764
  return {
@@ -1890,10 +2788,16 @@ var resolveGateIds = (config) => {
1890
2788
  ) : ["index-freshness", "human-guide-links"]
1891
2789
  );
1892
2790
  for (const id of config.gates?.include ?? []) {
1893
- if (SUPPORTED_GATES.includes(id)) ids.add(id);
2791
+ if (RESERVED_GATE_IDS.has(id)) {
2792
+ process.emitWarning(`Gate "${id}" is reserved and has no runtime implementation; it was not executed.`, {
2793
+ code: "AK_DOCS_RESERVED_GATE"
2794
+ });
2795
+ continue;
2796
+ }
2797
+ ids.add(id);
1894
2798
  }
1895
2799
  for (const id of config.gates?.exclude ?? []) {
1896
- if (SUPPORTED_GATES.includes(id)) ids.delete(id);
2800
+ if (!RESERVED_GATE_IDS.has(id)) ids.delete(id);
1897
2801
  }
1898
2802
  return [...ids];
1899
2803
  };
@@ -2009,7 +2913,7 @@ var runQuery = (index, config, req) => {
2009
2913
  };
2010
2914
 
2011
2915
  // src/intelligence/adapter.ts
2012
- import { join as join12 } from "path";
2916
+ import { join as join9 } from "path";
2013
2917
 
2014
2918
  // src/intelligence/peers.ts
2015
2919
  var PeerMissingError = class extends Error {
@@ -2136,20 +3040,20 @@ var resolveIntelligenceRuntime = async (config) => {
2136
3040
  }
2137
3041
  return { adapter, embed, provider, ...model ? { model } : {} };
2138
3042
  };
2139
- var defaultVectorStorePath = (root) => join12(root, ".doc-bridge", "vectors");
3043
+ var defaultVectorStorePath = (root) => join9(root, ".doc-bridge", "vectors");
2140
3044
 
2141
3045
  // src/intelligence/rag.ts
2142
- import { readFileSync as readFileSync12 } from "fs";
2143
- import { join as join13 } from "path";
3046
+ import { readFileSync as readFileSync11 } from "fs";
3047
+ import { join as join10 } from "path";
2144
3048
  var loadDocuments = (root, index, sources) => {
2145
3049
  const includeAgent = sources.includes("agent") || sources.length === 0;
2146
3050
  const docs = [];
2147
3051
  if (includeAgent) {
2148
3052
  for (const entry of index.knowledge) {
2149
- const abs = join13(root, entry.path);
3053
+ const abs = join10(root, entry.path);
2150
3054
  let content = "";
2151
3055
  try {
2152
- content = readFileSync12(abs, "utf8");
3056
+ content = readFileSync11(abs, "utf8");
2153
3057
  } catch {
2154
3058
  content = [entry.title, entry.description].filter(Boolean).join("\n\n");
2155
3059
  }
@@ -2167,7 +3071,7 @@ var createDocBridgeRag = async (root, config, index) => {
2167
3071
  const { embed } = await resolveIntelligenceRuntime(config);
2168
3072
  const ragMod = await importPeer("@agentskit/rag");
2169
3073
  const memoryMod = await importPeer("@agentskit/memory");
2170
- const storePath = typeof config.intelligence?.retriever?.options?.storePath === "string" ? join13(root, config.intelligence.retriever.options.storePath) : defaultVectorStorePath(root);
3074
+ const storePath = typeof config.intelligence?.retriever?.options?.storePath === "string" ? join10(root, config.intelligence.retriever.options.storePath) : defaultVectorStorePath(root);
2171
3075
  const store = memoryMod.fileVectorMemory({ path: storePath });
2172
3076
  const rag = ragMod.createRAG({
2173
3077
  embed,
@@ -2302,15 +3206,15 @@ var startInkChat = async (root, config, index) => {
2302
3206
  };
2303
3207
 
2304
3208
  // src/memory/ingest.ts
2305
- import { existsSync as existsSync9, readFileSync as readFileSync13 } from "fs";
2306
- import { join as join14 } from "path";
3209
+ import { existsSync as existsSync11, readFileSync as readFileSync12 } from "fs";
3210
+ import { join as join11 } from "path";
2307
3211
  var memoryFact = (raw, id) => firstParagraph(raw) ?? firstHeading(raw) ?? id;
2308
3212
  var relativePath = (root, abs) => toPosix(abs).replace(`${toPosix(root)}/`, "");
2309
3213
  var ingestMarkdownDir = (root, dir, source, confidence) => {
2310
- if (!existsSync9(dir)) return [];
3214
+ if (!existsSync11(dir)) return [];
2311
3215
  return walkFiles(dir, { extensions: [".md", ".mdc"] }).map((abs) => {
2312
3216
  const rel = relativePath(root, abs);
2313
- const raw = readFileSync13(abs, "utf8");
3217
+ const raw = readFileSync12(abs, "utf8");
2314
3218
  const id = slugFromPath(rel);
2315
3219
  return {
2316
3220
  schemaVersion: 1,
@@ -2325,10 +3229,10 @@ var ingestMarkdownDir = (root, dir, source, confidence) => {
2325
3229
  });
2326
3230
  };
2327
3231
  var ingestCursorRules = (root) => {
2328
- const dir = join14(root, ".cursor", "rules");
3232
+ const dir = join11(root, ".cursor", "rules");
2329
3233
  return ingestMarkdownDir(root, dir, "cursor", 0.6);
2330
3234
  };
2331
- var ingestAgentMemory = (root) => ingestMarkdownDir(root, join14(root, ".agent-memory"), "agent-memory", 0.7);
3235
+ var ingestAgentMemory = (root) => ingestMarkdownDir(root, join11(root, ".agent-memory"), "agent-memory", 0.7);
2332
3236
  var ingestMemoryCandidates = (root) => [
2333
3237
  ...ingestAgentMemory(root),
2334
3238
  ...ingestCursorRules(root)
@@ -2415,8 +3319,8 @@ var draftMemoryPromotion = (classifications) => {
2415
3319
 
2416
3320
  // src/memory/github-pr.ts
2417
3321
  import { execFileSync, spawnSync } from "child_process";
2418
- import { existsSync as existsSync10, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
2419
- import { join as join15 } from "path";
3322
+ import { existsSync as existsSync12, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
3323
+ import { join as join12 } from "path";
2420
3324
  var run = (cmd, args, cwd) => {
2421
3325
  const result = spawnSync(cmd, [...args], { cwd, encoding: "utf8" });
2422
3326
  const out = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
@@ -2424,10 +3328,10 @@ var run = (cmd, args, cwd) => {
2424
3328
  };
2425
3329
  var hasGh = () => run("gh", ["--version"], process.cwd()).ok;
2426
3330
  var slug = () => (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
2427
- var defaultPromotionDraftPath = (root) => join15(root, ".doc-bridge", "drafts", `memory-promotion-${slug()}.md`);
3331
+ var defaultPromotionDraftPath = (root) => join12(root, ".doc-bridge", "drafts", `memory-promotion-${slug()}.md`);
2428
3332
  var writePromotionDraft = (root, draft, path) => {
2429
3333
  const draftPath = path ?? defaultPromotionDraftPath(root);
2430
- mkdirSync2(join15(root, ".doc-bridge", "drafts"), { recursive: true });
3334
+ mkdirSync2(join12(root, ".doc-bridge", "drafts"), { recursive: true });
2431
3335
  writeFileSync2(draftPath, `${draft.body}
2432
3336
  `, "utf8");
2433
3337
  return draftPath;
@@ -2463,7 +3367,7 @@ var promoteMemoryToGithubPr = (root, draft, options = {}) => {
2463
3367
  message: `Wrote draft to ${relDraft}. Run the printed git/gh commands to open a draft PR.`
2464
3368
  };
2465
3369
  }
2466
- if (!existsSync10(join15(root, ".git"))) {
3370
+ if (!existsSync12(join12(root, ".git"))) {
2467
3371
  return {
2468
3372
  ok: false,
2469
3373
  dryRun: false,
@@ -2566,22 +3470,22 @@ ${auth.out}`
2566
3470
  };
2567
3471
 
2568
3472
  // src/index-builder/watch-index.ts
2569
- import { existsSync as existsSync11, watch } from "fs";
2570
- import { dirname as dirname4, resolve as resolve5 } from "path";
3473
+ import { existsSync as existsSync13, watch } from "fs";
3474
+ import { dirname as dirname4, resolve as resolve8 } from "path";
2571
3475
  var WATCH_PATTERN = /\.(md|mdx|json|ya?ml|mdc)$/i;
2572
3476
  var collectWatchRoots = (root, config, configPath) => {
2573
3477
  const roots = /* @__PURE__ */ new Set();
2574
- roots.add(resolve5(root, config.corpus.agent.root));
3478
+ roots.add(resolve8(root, config.corpus.agent.root));
2575
3479
  const humanSources = config.corpus.human ? Array.isArray(config.corpus.human) ? config.corpus.human : [config.corpus.human] : [];
2576
3480
  for (const source of humanSources) {
2577
3481
  const humanOpts = source.options ?? {};
2578
3482
  for (const key of ["contentDir", "docsDir", "root"]) {
2579
3483
  const value = humanOpts[key];
2580
- if (typeof value === "string" && value.length) roots.add(resolve5(root, value));
3484
+ if (typeof value === "string" && value.length) roots.add(resolve8(root, value));
2581
3485
  }
2582
3486
  }
2583
- if (configPath) roots.add(dirname4(resolve5(configPath)));
2584
- return [...roots].filter((dir) => existsSync11(dir));
3487
+ if (configPath) roots.add(dirname4(resolve8(configPath)));
3488
+ return [...roots].filter((dir) => existsSync13(dir));
2585
3489
  };
2586
3490
  var watchDocBridgeIndex = (opts) => {
2587
3491
  const debounceMs = opts.debounceMs ?? 350;
@@ -2622,8 +3526,8 @@ var watchDocBridgeIndex = (opts) => {
2622
3526
  rebuild();
2623
3527
  });
2624
3528
  }
2625
- const configDir = resolve5(opts.root);
2626
- if (existsSync11(configDir)) {
3529
+ const configDir = resolve8(opts.root);
3530
+ if (existsSync13(configDir)) {
2627
3531
  watch(configDir, (_event, filename) => {
2628
3532
  if (!filename || !/doc-bridge\.config/.test(filename)) return;
2629
3533
  rebuild();
@@ -2799,15 +3703,15 @@ var docBridgePatternPayload = () => ({
2799
3703
  });
2800
3704
 
2801
3705
  // src/cli/demo.ts
2802
- import { cpSync, existsSync as existsSync13, mkdtempSync, readFileSync as readFileSync15, rmSync } from "fs";
3706
+ import { cpSync, existsSync as existsSync15, mkdtempSync, readFileSync as readFileSync14, rmSync } from "fs";
2803
3707
  import { tmpdir } from "os";
2804
- import { dirname as dirname6, join as join18, resolve as resolve7 } from "path";
3708
+ import { dirname as dirname6, join as join15, resolve as resolve10 } from "path";
2805
3709
  import { fileURLToPath } from "url";
2806
3710
 
2807
3711
  // src/mcp/install.ts
2808
- import { existsSync as existsSync12, mkdirSync as mkdirSync3, readFileSync as readFileSync14, writeFileSync as writeFileSync3 } from "fs";
3712
+ import { existsSync as existsSync14, mkdirSync as mkdirSync3, readFileSync as readFileSync13, writeFileSync as writeFileSync3 } from "fs";
2809
3713
  import { homedir } from "os";
2810
- import { dirname as dirname5, join as join17, resolve as resolve6 } from "path";
3714
+ import { dirname as dirname5, join as join14, resolve as resolve9 } from "path";
2811
3715
  var SERVER_NAME = "ak-docs";
2812
3716
  var mcpServerEntry = (root) => ({
2813
3717
  command: "npx",
@@ -2815,9 +3719,9 @@ var mcpServerEntry = (root) => ({
2815
3719
  cwd: root
2816
3720
  });
2817
3721
  var readJson = (path) => {
2818
- if (!existsSync12(path)) return {};
3722
+ if (!existsSync14(path)) return {};
2819
3723
  try {
2820
- const parsed = JSON.parse(readFileSync14(path, "utf8"));
3724
+ const parsed = JSON.parse(readFileSync13(path, "utf8"));
2821
3725
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
2822
3726
  } catch {
2823
3727
  return {};
@@ -2829,12 +3733,12 @@ var writeJson = (path, value) => {
2829
3733
  `, "utf8");
2830
3734
  };
2831
3735
  var resolveTargetPath = (target, root) => {
2832
- if (target === "cursor") return resolve6(root, ".cursor", "mcp.json");
2833
- return join17(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
3736
+ if (target === "cursor") return resolve9(root, ".cursor", "mcp.json");
3737
+ return join14(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
2834
3738
  };
2835
3739
  var installMcpConfig = (root, target) => {
2836
3740
  const configPath = resolveTargetPath(target, root);
2837
- const created = !existsSync12(configPath);
3741
+ const created = !existsSync14(configPath);
2838
3742
  const existing = readJson(configPath);
2839
3743
  const servers = existing.mcpServers && typeof existing.mcpServers === "object" && !Array.isArray(existing.mcpServers) ? { ...existing.mcpServers } : {};
2840
3744
  servers[SERVER_NAME] = mcpServerEntry(root);
@@ -2859,12 +3763,12 @@ var installMcpConfig = (root, target) => {
2859
3763
  var mcpSnippet = (root) => JSON.stringify({ mcpServers: { [SERVER_NAME]: mcpServerEntry(root) } }, null, 2);
2860
3764
 
2861
3765
  // src/cli/demo.ts
2862
- var packageRoot = resolve7(dirname6(fileURLToPath(import.meta.url)), "..", "..");
3766
+ var packageRoot = resolve10(dirname6(fileURLToPath(import.meta.url)), "..", "..");
2863
3767
  var fixturePath = (fixture) => {
2864
3768
  if (fixture === "monorepo") {
2865
- return join18(packageRoot, "examples", "demo-monorepo");
3769
+ return join15(packageRoot, "examples", "demo-monorepo");
2866
3770
  }
2867
- return join18(packageRoot, "examples", "demo-example");
3771
+ return join15(packageRoot, "examples", "demo-example");
2868
3772
  };
2869
3773
  var formatHandoffText = (handoff) => {
2870
3774
  const bridge = handoff.bridge?.humanDoc === "missing" ? `human guide: missing \u2192 ${handoff.bridge.action ?? "ak-docs bootstrap agent-docs"}` : handoff.humanDoc ? `human guide: ${handoff.humanDoc}` : "human guide: (none)";
@@ -2880,11 +3784,11 @@ var formatHandoffText = (handoff) => {
2880
3784
  var runDemo = (root, config, fixture = "example", options = {}) => {
2881
3785
  const targetPackage = fixture === "monorepo" ? "auth" : "example";
2882
3786
  const fixtureDir = fixturePath(fixture);
2883
- if (options.copyFixture && existsSync13(fixtureDir)) {
3787
+ if (options.copyFixture && existsSync15(fixtureDir)) {
2884
3788
  for (const rel of ["doc-bridge.config.json", "docs", "packages", "pnpm-workspace.yaml", "package.json"]) {
2885
- const src = join18(fixtureDir, rel);
2886
- if (!existsSync13(src)) continue;
2887
- const dest = join18(root, rel);
3789
+ const src = join15(fixtureDir, rel);
3790
+ if (!existsSync15(src)) continue;
3791
+ const dest = join15(root, rel);
2888
3792
  cpSync(src, dest, { recursive: true });
2889
3793
  }
2890
3794
  }
@@ -2939,14 +3843,14 @@ var formatDemoText = (result) => {
2939
3843
  return lines;
2940
3844
  };
2941
3845
  var withDemoWorkspace = (fixture, fn) => {
2942
- const dir = mkdtempSync(join18(tmpdir(), "ak-docs-demo-"));
3846
+ const dir = mkdtempSync(join15(tmpdir(), "ak-docs-demo-"));
2943
3847
  try {
2944
3848
  const fixtureDir = fixturePath(fixture);
2945
- if (!existsSync13(fixtureDir)) {
3849
+ if (!existsSync15(fixtureDir)) {
2946
3850
  throw new Error(`Demo fixture "${fixture}" not found at ${fixtureDir}`);
2947
3851
  }
2948
3852
  cpSync(fixtureDir, dir, { recursive: true });
2949
- const config = JSON.parse(readFileSync15(join18(dir, "doc-bridge.config.json"), "utf8"));
3853
+ const config = JSON.parse(readFileSync14(join15(dir, "doc-bridge.config.json"), "utf8"));
2950
3854
  return fn(dir, config);
2951
3855
  } finally {
2952
3856
  rmSync(dir, { recursive: true, force: true });
@@ -3157,9 +4061,9 @@ var formatDoctorText = (report) => {
3157
4061
  };
3158
4062
 
3159
4063
  // src/mcp/server.ts
3160
- import { readFileSync as readFileSync16, realpathSync } from "fs";
3161
- import { relative, resolve as resolve8 } from "path";
3162
- import { z as z5, ZodError } from "zod";
4064
+ import { readFileSync as readFileSync15, realpathSync as realpathSync6 } from "fs";
4065
+ import { relative as relative4, resolve as resolve11 } from "path";
4066
+ import { z as z6, ZodError } from "zod";
3163
4067
  var MCP_TOOLS = [
3164
4068
  {
3165
4069
  name: "handoff.resolve",
@@ -3218,21 +4122,21 @@ var MCP_TOOLS = [
3218
4122
  }
3219
4123
  ];
3220
4124
  var asRecord = (value) => value && typeof value === "object" ? value : {};
3221
- var HandoffResolveArgsSchema = z5.object({
3222
- id: z5.string().min(1),
3223
- kind: z5.enum(["package", "ownership"]).optional()
4125
+ var HandoffResolveArgsSchema = z6.object({
4126
+ id: z6.string().min(1),
4127
+ kind: z6.enum(["package", "ownership"]).optional()
3224
4128
  });
3225
- var DocSearchArgsSchema = z5.object({
3226
- term: z5.string().min(1),
3227
- limit: z5.number().int().positive().max(100).optional()
4129
+ var DocSearchArgsSchema = z6.object({
4130
+ term: z6.string().min(1),
4131
+ limit: z6.number().int().positive().max(100).optional()
3228
4132
  });
3229
- var RetrieverQueryArgsSchema = z5.object({
3230
- query: z5.string().min(1),
3231
- limit: z5.number().int().positive().max(100).optional()
4133
+ var RetrieverQueryArgsSchema = z6.object({
4134
+ query: z6.string().min(1),
4135
+ limit: z6.number().int().positive().max(100).optional()
3232
4136
  });
3233
- var DocGetArgsSchema = z5.object({
3234
- id: z5.string().min(1).optional(),
3235
- path: z5.string().min(1).optional()
4137
+ var DocGetArgsSchema = z6.object({
4138
+ id: z6.string().min(1).optional(),
4139
+ path: z6.string().min(1).optional()
3236
4140
  }).refine((args) => args.id || args.path, "doc.get requires id or path");
3237
4141
  var parseToolArgs = (tool, schema, value) => {
3238
4142
  try {
@@ -3264,12 +4168,12 @@ var findDocPath = (index, args) => {
3264
4168
  return doc.path;
3265
4169
  };
3266
4170
  var resolveDocPath = (root, relPath) => {
3267
- const rootAbs = realpathSync.native(root);
3268
- const unresolved = resolve8(rootAbs, relPath);
3269
- const unresolvedRel = relative(rootAbs, unresolved);
4171
+ const rootAbs = realpathSync6.native(root);
4172
+ const unresolved = resolve11(rootAbs, relPath);
4173
+ const unresolvedRel = relative4(rootAbs, unresolved);
3270
4174
  if (unresolvedRel.startsWith("..")) throw new Error("doc.get path escapes project root");
3271
- const abs = realpathSync.native(unresolved);
3272
- const rel = relative(rootAbs, abs);
4175
+ const abs = realpathSync6.native(unresolved);
4176
+ const rel = relative4(rootAbs, abs);
3273
4177
  if (rel.startsWith("..")) throw new Error("doc.get path escapes project root");
3274
4178
  return abs;
3275
4179
  };
@@ -3303,7 +4207,7 @@ var handleMcpRequest = (ctx, request) => {
3303
4207
  }
3304
4208
  if (name === "doc.get") {
3305
4209
  const relPath = findDocPath(index(), parseToolArgs("doc.get", DocGetArgsSchema, args));
3306
- return textResult(readFileSync16(resolveDocPath(ctx.root, relPath), "utf8"));
4210
+ return textResult(readFileSync15(resolveDocPath(ctx.root, relPath), "utf8"));
3307
4211
  }
3308
4212
  if (name === "gate.status") return textResult(runGates(ctx.root, ctx.config));
3309
4213
  if (name === "retriever.query") {
@@ -3388,11 +4292,12 @@ Core (no API key):
3388
4292
  ak-docs demo [--fixture example|monorepo] [--text] [--in-project]
3389
4293
  ak-docs doctor [--text] [--badge] [--write-badge]
3390
4294
  ak-docs index [--watch]
3391
- ak-docs query <package|ownership|intent|change> <id> [--agent] [--text]
4295
+ ak-docs query [package|ownership|intent|change] <id> [--agent] [--text]
3392
4296
  ak-docs search <term> [--agent] [--text]
3393
4297
  ak-docs list <packages|intents|changes|knowledge> [--text]
3394
4298
  ak-docs ask [question] local consult (no LLM)
3395
4299
  ak-docs gate run [gate-id]
4300
+ ak-docs conformance run documentation-standard-v1 [--text|--json]
3396
4301
  ak-docs mcp
3397
4302
  ak-docs mcp install --cursor | --claude
3398
4303
  ak-docs memory ingest|classify|promote [--pr] [--dry-run]
@@ -3416,7 +4321,13 @@ Global flags:
3416
4321
  `;
3417
4322
  var QUERY_KINDS = /* @__PURE__ */ new Set(["package", "ownership", "intent", "change", "search"]);
3418
4323
  var LIST_KINDS = /* @__PURE__ */ new Set(["packages", "intents", "changes", "knowledge"]);
3419
- var GATE_IDS = /* @__PURE__ */ new Set(["index-freshness", "human-guide-links", "okf-type", "docs-style"]);
4324
+ var GATE_IDS = /* @__PURE__ */ new Set([
4325
+ "index-freshness",
4326
+ "human-guide-links",
4327
+ "okf-type",
4328
+ "docs-style",
4329
+ "documentation-standard-v1"
4330
+ ]);
3420
4331
  var parseArgs = (argv) => {
3421
4332
  const flags = /* @__PURE__ */ new Set();
3422
4333
  let configPath;
@@ -3457,6 +4368,7 @@ var parseArgs = (argv) => {
3457
4368
  else if (positional[0] === "chat") command = "chat";
3458
4369
  else if (positional[0] === "rag") command = "rag";
3459
4370
  else if (positional[0] === "list") command = "list";
4371
+ else if (positional[0] === "conformance") command = "conformance";
3460
4372
  return { command, flags, configPath, positional };
3461
4373
  };
3462
4374
  var writeJson2 = (payload) => {
@@ -3550,12 +4462,12 @@ var readIndexedDoc = (root, config, idOrPath) => {
3550
4462
  const index = loadDocBridgeIndex(root, config);
3551
4463
  const entry = index.knowledge.find((doc) => doc.id === idOrPath || doc.path === idOrPath);
3552
4464
  if (!entry) throw new Error(`Unknown indexed doc "${idOrPath}". Try: search ${idOrPath}`);
3553
- const abs = resolve9(root, entry.path);
3554
- const rootAbs = resolve9(root);
4465
+ const abs = resolve12(root, entry.path);
4466
+ const rootAbs = resolve12(root);
3555
4467
  if (abs !== rootAbs && !abs.startsWith(`${rootAbs}/`)) {
3556
4468
  throw new Error(`Indexed doc escapes project root: ${entry.path}`);
3557
4469
  }
3558
- return readFileSync17(abs, "utf8");
4470
+ return readFileSync16(abs, "utf8");
3559
4471
  };
3560
4472
  var runAskRepl = async (root, config) => {
3561
4473
  const index = loadDocBridgeIndex(root, config);
@@ -3631,7 +4543,7 @@ var diagnosticNextCommands = (config, result) => {
3631
4543
  ];
3632
4544
  };
3633
4545
  var writeIfMissing = (path, contents) => {
3634
- if (existsSync14(path)) return false;
4546
+ if (existsSync16(path)) return false;
3635
4547
  mkdirSync5(dirname7(path), { recursive: true });
3636
4548
  writeFileSync4(path, contents, "utf8");
3637
4549
  return true;
@@ -3736,7 +4648,7 @@ var scaffoldWorkspaceDocs = (root, config) => {
3736
4648
  const created = [];
3737
4649
  const skipped = [];
3738
4650
  for (const pkg of discoverPnpmPackages(root, config)) {
3739
- const path = resolve9(root, config.corpus.agent.root, "packages", `${pkg.id}.md`);
4651
+ const path = resolve12(root, config.corpus.agent.root, "packages", `${pkg.id}.md`);
3740
4652
  if (writeIfMissing(path, workspaceDocDraft(pkg.id, pkg.path))) created.push(path);
3741
4653
  else skipped.push(path);
3742
4654
  }
@@ -3746,11 +4658,11 @@ var bootstrapAgentDocs = (root, config) => {
3746
4658
  const created = [];
3747
4659
  const skipped = [];
3748
4660
  for (const doc of scanHumanDocRecords(root, config)) {
3749
- const raw = readFileSync17(doc.path, "utf8");
4661
+ const raw = readFileSync16(doc.path, "utf8");
3750
4662
  const body = raw.replace(/^---\n[\s\S]*?\n---\n?/, "");
3751
4663
  const title = firstHeading(body) ?? doc.id;
3752
4664
  const description = firstParagraph(body);
3753
- const draftPath = resolve9(root, config.corpus.agent.root, "human", `${doc.id}.md`);
4665
+ const draftPath = resolve12(root, config.corpus.agent.root, "human", `${doc.id}.md`);
3754
4666
  const draft = [
3755
4667
  "---",
3756
4668
  "type: knowledge",
@@ -3814,8 +4726,8 @@ var runCli = (argv) => {
3814
4726
  return 1;
3815
4727
  }
3816
4728
  try {
3817
- const abs = resolve9(file);
3818
- const raw = readFileSync17(abs, "utf8");
4729
+ const abs = resolve12(file);
4730
+ const raw = readFileSync16(abs, "utf8");
3819
4731
  const handoff = parseAgentHandoff(JSON.parse(raw));
3820
4732
  writeJson2({ ok: true, handoff });
3821
4733
  return 0;
@@ -3828,10 +4740,10 @@ var runCli = (argv) => {
3828
4740
  if (command === "init") {
3829
4741
  const root = process.cwd();
3830
4742
  const withDemo = flags.has("--demo") || !flags.has("--no-demo");
3831
- const configFile = resolve9(root, configPath ?? "doc-bridge.config.json");
3832
- const docsIndex = resolve9(root, "docs/for-agents/INDEX.md");
3833
- const exampleDoc = resolve9(root, "docs/for-agents/packages/example.md");
3834
- const agentsMd = resolve9(root, "AGENTS.md");
4743
+ const configFile = resolve12(root, configPath ?? "doc-bridge.config.json");
4744
+ const docsIndex = resolve12(root, "docs/for-agents/INDEX.md");
4745
+ const exampleDoc = resolve12(root, "docs/for-agents/packages/example.md");
4746
+ const agentsMd = resolve12(root, "AGENTS.md");
3835
4747
  const configWritten = writeIfMissing(configFile, initConfigContents(configFile, withDemo));
3836
4748
  const indexWritten = writeIfMissing(
3837
4749
  docsIndex,
@@ -3839,7 +4751,7 @@ var runCli = (argv) => {
3839
4751
  );
3840
4752
  const exampleWritten = withDemo ? writeIfMissing(exampleDoc, exampleAgentDoc) : false;
3841
4753
  const agentsWritten = writeIfMissing(agentsMd, agentsMdSnippet);
3842
- if (withDemo) writeIfMissing(resolve9(root, "src/.gitkeep"), "");
4754
+ if (withDemo) writeIfMissing(resolve12(root, "src/.gitkeep"), "");
3843
4755
  const scaffold = flags.has("--scaffold-workspaces") ? scaffoldWorkspaceDocs(root, loadProject(configFile).config) : void 0;
3844
4756
  writeJson2({
3845
4757
  ok: true,
@@ -3997,12 +4909,12 @@ var runCli = (argv) => {
3997
4909
  const action = positional[1];
3998
4910
  const gateId = positional[2];
3999
4911
  if (action !== "run") {
4000
- process.stderr.write("Usage: ak-docs gate run [index-freshness]\n");
4912
+ process.stderr.write("Usage: ak-docs gate run [gate-id]\n");
4001
4913
  return 1;
4002
4914
  }
4003
4915
  if (gateId && !GATE_IDS.has(gateId)) {
4004
4916
  process.stderr.write(
4005
- `Unsupported gate "${gateId}". Supported gates: index-freshness, human-guide-links, okf-type, docs-style
4917
+ `Unsupported gate "${gateId}". Supported gates: ${[...GATE_IDS].join(", ")}
4006
4918
  `
4007
4919
  );
4008
4920
  return 1;
@@ -4014,6 +4926,26 @@ var runCli = (argv) => {
4014
4926
  return result.ok ? 0 : 1;
4015
4927
  } catch (error) {
4016
4928
  process.stderr.write(`${error instanceof Error ? error.message : String(error)}
4929
+ `);
4930
+ return 1;
4931
+ }
4932
+ }
4933
+ if (command === "conformance") {
4934
+ const action = positional[1];
4935
+ const profile = positional[2];
4936
+ if (action !== "run" || profile !== DOCUMENTATION_STANDARD_V1_ID) {
4937
+ process.stderr.write(`Usage: ak-docs conformance run ${DOCUMENTATION_STANDARD_V1_ID} [--text|--json]
4938
+ `);
4939
+ return 1;
4940
+ }
4941
+ try {
4942
+ const { config, root } = loadProject(configPath);
4943
+ const report = runDocumentationStandardV1(root, config);
4944
+ if (wantsTextOutput(flags, config)) writeLines(formatDocumentationStandardText(report));
4945
+ else writeJson2(report);
4946
+ return report.ok ? 0 : 1;
4947
+ } catch (error) {
4948
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}
4017
4949
  `);
4018
4950
  return 1;
4019
4951
  }
@@ -4062,7 +4994,7 @@ var runCli = (argv) => {
4062
4994
  const { config, root } = loadProject(configPath);
4063
4995
  const report = runDoctor(root, config);
4064
4996
  if (flags.has("--write-badge")) {
4065
- const badgePath = resolve9(root, ".doc-bridge", "coverage-badge.json");
4997
+ const badgePath = resolve12(root, ".doc-bridge", "coverage-badge.json");
4066
4998
  mkdirSync5(dirname7(badgePath), { recursive: true });
4067
4999
  writeFileSync4(badgePath, `${formatDoctorBadgeJson(report.badge)}
4068
5000
  `, "utf8");
@@ -4116,15 +5048,15 @@ var runCli = (argv) => {
4116
5048
  }
4117
5049
  }
4118
5050
  if (command === "query") {
4119
- const kind = positional[1];
4120
- const id = positional[2];
4121
- if (!kind || !QUERY_KINDS.has(kind) || kind === "search") {
4122
- process.stderr.write("Usage: ak-docs query <package|ownership|intent|change> <id> [--agent]\n");
5051
+ const maybeKind = positional[1];
5052
+ if (maybeKind === "search") {
5053
+ process.stderr.write("Usage: ak-docs query [package|ownership|intent|change] <id> [--agent]\n");
4123
5054
  return 1;
4124
5055
  }
5056
+ const kind = maybeKind && QUERY_KINDS.has(maybeKind) ? maybeKind : "package";
5057
+ const id = kind === maybeKind ? positional[2] : positional[1];
4125
5058
  if (!id) {
4126
- process.stderr.write(`Missing id for query kind "${kind}".
4127
- `);
5059
+ process.stderr.write("Usage: ak-docs query [package|ownership|intent|change] <id> [--agent]\n");
4128
5060
  return 1;
4129
5061
  }
4130
5062
  try {