@open-agent-toolkit/cli 0.3.27 → 0.3.29

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 (105) hide show
  1. package/README.md +8 -0
  2. package/assets/bundle-metadata.json +1 -1
  3. package/assets/docs/contributing/documentation.md +11 -2
  4. package/assets/docs/docs-tooling/add-docs-to-a-repo.md +12 -0
  5. package/assets/docs/docs-tooling/check.md +154 -0
  6. package/assets/docs/docs-tooling/commands.md +61 -11
  7. package/assets/docs/docs-tooling/index.md +1 -0
  8. package/assets/docs/docs-tooling/meta.json +7 -1
  9. package/assets/docs/docs-tooling/workflows.md +4 -0
  10. package/assets/docs/reference/cli-reference.md +2 -0
  11. package/assets/docs/reference/configuration.md +1 -0
  12. package/assets/public-package-versions.json +4 -4
  13. package/assets/skills/authoring-docs/SKILL.md +2 -2
  14. package/assets/skills/authoring-docs/references/information-architecture.md +5 -2
  15. package/assets/skills/authoring-docs/references/page-templates/alert-runbook.md +63 -0
  16. package/assets/skills/authoring-docs/references/page-templates/command-reference.md +55 -0
  17. package/assets/skills/authoring-docs/references/page-templates/decisions-pointer.md +44 -0
  18. package/assets/skills/authoring-docs/references/page-templates/engineering-feature.md +53 -0
  19. package/assets/skills/authoring-docs/references/page-templates/per-area-agents.md +42 -0
  20. package/assets/skills/authoring-docs/references/page-templates/product-feature.md +49 -0
  21. package/assets/skills/authoring-docs/references/page-templates/qa-validation.md +59 -0
  22. package/assets/skills/authoring-docs/references/page-templates/screen-spec.md +51 -0
  23. package/assets/skills/authoring-docs/references/page-templates/skill-command-guide.md +44 -0
  24. package/assets/skills/authoring-docs/references/page-templates/solution-record.md +43 -0
  25. package/assets/skills/authoring-docs/references/templates.md +22 -2
  26. package/assets/skills/oat-docs-analyze/SKILL.md +13 -2
  27. package/assets/skills/oat-docs-authoring/SKILL.md +1 -1
  28. package/assets/skills/oat-docs-authoring/references/validation.md +4 -0
  29. package/assets/skills/oat-docs-bootstrap/SKILL.md +63 -6
  30. package/assets/skills/oat-docs-bootstrap/references/pr-ci.md +89 -0
  31. package/assets/templates/docs-app-fuma/AGENTS.md +9 -2
  32. package/assets/templates/docs-app-fuma/docs/contributing/docs-toolchain.md +40 -3
  33. package/assets/templates/docs-app-fuma/docs/contributing.md +7 -1
  34. package/assets/templates/docs-app-fuma/docs/index.md +1 -1
  35. package/assets/templates/docs-app-fuma/gitignore.template +12 -0
  36. package/assets/templates/docs-app-fuma/package.json.template +2 -1
  37. package/assets/templates/docs-app-fuma/pnpm-workspace.yaml +5 -0
  38. package/assets/templates/docs-app-mkdocs/AGENTS.md +4 -2
  39. package/assets/templates/docs-app-mkdocs/docs/contributing/docs-toolchain.md +4 -2
  40. package/assets/templates/docs-app-mkdocs/docs/contributing.md +7 -1
  41. package/assets/templates/docs-app-mkdocs/docs/index.md +1 -1
  42. package/assets/templates/docs-app-mkdocs/gitignore.template +8 -0
  43. package/assets/templates/docs-app-mkdocs/package.json.template +3 -2
  44. package/dist/commands/config/index.d.ts.map +1 -1
  45. package/dist/commands/config/index.js +35 -3
  46. package/dist/commands/docs/check/check.d.ts +3 -0
  47. package/dist/commands/docs/check/check.d.ts.map +1 -0
  48. package/dist/commands/docs/check/check.js +48 -0
  49. package/dist/commands/docs/check/check.types.d.ts +17 -0
  50. package/dist/commands/docs/check/check.types.d.ts.map +1 -0
  51. package/dist/commands/docs/check/check.types.js +1 -0
  52. package/dist/commands/docs/check/checker.d.ts +8 -0
  53. package/dist/commands/docs/check/checker.d.ts.map +1 -0
  54. package/dist/commands/docs/check/checker.js +82 -0
  55. package/dist/commands/docs/check/commands.d.ts +5 -0
  56. package/dist/commands/docs/check/commands.d.ts.map +1 -0
  57. package/dist/commands/docs/check/commands.js +232 -0
  58. package/dist/commands/docs/check/diagrams.d.ts +5 -0
  59. package/dist/commands/docs/check/diagrams.d.ts.map +1 -0
  60. package/dist/commands/docs/check/diagrams.js +197 -0
  61. package/dist/commands/docs/check/files.d.ts +21 -0
  62. package/dist/commands/docs/check/files.d.ts.map +1 -0
  63. package/dist/commands/docs/check/files.js +121 -0
  64. package/dist/commands/docs/check/markdown.d.ts +60 -0
  65. package/dist/commands/docs/check/markdown.d.ts.map +1 -0
  66. package/dist/commands/docs/check/markdown.js +125 -0
  67. package/dist/commands/docs/check/mermaid-runtime.d.ts +3 -0
  68. package/dist/commands/docs/check/mermaid-runtime.d.ts.map +1 -0
  69. package/dist/commands/docs/check/mermaid-runtime.js +57 -0
  70. package/dist/commands/docs/check/navigation.d.ts +4 -0
  71. package/dist/commands/docs/check/navigation.d.ts.map +1 -0
  72. package/dist/commands/docs/check/navigation.js +104 -0
  73. package/dist/commands/docs/check/reader-rules.d.ts +6 -0
  74. package/dist/commands/docs/check/reader-rules.d.ts.map +1 -0
  75. package/dist/commands/docs/check/reader-rules.js +214 -0
  76. package/dist/commands/docs/index.d.ts.map +1 -1
  77. package/dist/commands/docs/index.js +2 -0
  78. package/dist/commands/docs/init/content.d.ts +23 -0
  79. package/dist/commands/docs/init/content.d.ts.map +1 -0
  80. package/dist/commands/docs/init/content.js +361 -0
  81. package/dist/commands/docs/init/index.d.ts +1 -0
  82. package/dist/commands/docs/init/index.d.ts.map +1 -1
  83. package/dist/commands/docs/init/index.js +40 -1
  84. package/dist/commands/docs/init/markdown.d.ts.map +1 -1
  85. package/dist/commands/docs/init/markdown.js +21 -2
  86. package/dist/commands/docs/init/resolve-options.d.ts +4 -1
  87. package/dist/commands/docs/init/resolve-options.d.ts.map +1 -1
  88. package/dist/commands/docs/init/resolve-options.js +4 -0
  89. package/dist/commands/docs/init/scaffold.d.ts +1 -0
  90. package/dist/commands/docs/init/scaffold.d.ts.map +1 -1
  91. package/dist/commands/docs/init/scaffold.js +57 -4
  92. package/dist/commands/docs/nav/contents.d.ts +4 -0
  93. package/dist/commands/docs/nav/contents.d.ts.map +1 -1
  94. package/dist/commands/docs/nav/contents.js +10 -0
  95. package/dist/config/documentation-check.d.ts +38 -0
  96. package/dist/config/documentation-check.d.ts.map +1 -0
  97. package/dist/config/documentation-check.js +132 -0
  98. package/dist/config/oat-config.d.ts +2 -0
  99. package/dist/config/oat-config.d.ts.map +1 -1
  100. package/dist/config/oat-config.js +4 -0
  101. package/dist/config/resolve.d.ts.map +1 -1
  102. package/dist/config/resolve.js +1 -0
  103. package/dist/release/public-package-contract.d.ts.map +1 -1
  104. package/dist/release/public-package-contract.js +13 -0
  105. package/package.json +11 -2
@@ -9,6 +9,7 @@ import { readOatConfig, writeOatConfig, } from '../../../config/oat-config.js';
9
9
  import { resolveAssetsRoot } from '../../../fs/assets.js';
10
10
  import { atomicWriteJson, fileExists } from '../../../fs/io.js';
11
11
  import { Command, Option } from 'commander';
12
+ import { mergeTemplateExclusion } from './content.js';
12
13
  import { buildDocsCommands } from './docs-commands.js';
13
14
  import { applyMarkdownDocsPlan, MarkdownDocsWriteError, planMarkdownDocs, validateMarkdownConfig, validateMarkdownTarget, } from './markdown.js';
14
15
  import { DEFAULT_DOCS_REPO_SHAPE_DEPENDENCIES, detectDocsRepoShape, getDefaultDocsAppName, resolveDocsInitOptions, } from './resolve-options.js';
@@ -107,8 +108,27 @@ const DEFAULT_DEPENDENCIES = {
107
108
  root: plan.targetDir,
108
109
  tooling: 'markdown',
109
110
  index: `${plan.targetDir}/index.md`,
111
+ ...(options.iaPreset
112
+ ? {
113
+ nonReaderPaths: mergeTemplateExclusion(latest.documentation?.nonReaderPaths),
114
+ }
115
+ : {}),
110
116
  };
111
- await writeOatConfig(context.cwd, latest);
117
+ if (options.iaPreset) {
118
+ const configPath = join(context.cwd, '.oat/config.json');
119
+ const raw = (await fileExists(configPath))
120
+ ? JSON.parse(await readFile(configPath, 'utf8'))
121
+ : latest;
122
+ await atomicWriteJson(configPath, {
123
+ ...raw,
124
+ documentation: {
125
+ ...raw.documentation,
126
+ ...latest.documentation,
127
+ },
128
+ });
129
+ }
130
+ else
131
+ await writeOatConfig(context.cwd, latest);
112
132
  report.configStatus = 'updated';
113
133
  }
114
134
  catch (error) {
@@ -145,6 +165,8 @@ const DEFAULT_DEPENDENCIES = {
145
165
  enabled: options.rootPatch,
146
166
  });
147
167
  const config = await readOatConfig(context.cwd);
168
+ if (options.iaPreset)
169
+ result.documentationConfig.nonReaderPaths = mergeTemplateExclusion(config.documentation?.nonReaderPaths);
148
170
  config.documentation = {
149
171
  ...config.documentation,
150
172
  ...result.documentationConfig,
@@ -176,11 +198,16 @@ const DEFAULT_DEPENDENCIES = {
176
198
  context.logger.info(` Format: ${options.format}`);
177
199
  if (rootPackagePatch)
178
200
  logRootPackagePatch(context, rootPackagePatch);
201
+ for (const advice of result.installationAdvice ?? [])
202
+ context.logger.info(advice);
179
203
  }
180
204
  return {
181
205
  createdFiles: result.createdFiles,
182
206
  appRoot: result.appRoot,
183
207
  rootPackagePatch,
208
+ ...(result.installationAdvice
209
+ ? { installationAdvice: result.installationAdvice }
210
+ : {}),
184
211
  };
185
212
  },
186
213
  upsertAgentsMdSection,
@@ -245,6 +272,8 @@ async function runDocsInitCommand(context, options, dependencies) {
245
272
  interactive: context.interactive,
246
273
  acceptDefaults: options.yes ?? false,
247
274
  providedFramework: options.framework,
275
+ providedIaPreset: options.iaPreset,
276
+ providedPlannedPages: options.plannedPages,
248
277
  providedAdopt: options.adopt,
249
278
  providedAppName: options.appName,
250
279
  providedSiteName: options.siteName,
@@ -271,6 +300,11 @@ async function runDocsInitCommand(context, options, dependencies) {
271
300
  }
272
301
  const inapplicableOptions = [];
273
302
  const existingConfig = await dependencies.readOatConfig(context.cwd);
303
+ if (resolved.iaPreset &&
304
+ (existingConfig.documentation?.root ||
305
+ existingConfig.documentation?.ia ||
306
+ existingConfig.documentation?.navOwner))
307
+ throw new Error('Preset init cannot replace an existing docs surface or navigation ownership. Use oat-docs-analyze and individually approved oat-docs-apply.');
274
308
  if (resolved.framework === 'markdown') {
275
309
  resolved.targetDir = await validateMarkdownTarget(context.cwd, resolved.targetDir);
276
310
  validateMarkdownConfig(context.cwd, resolved.targetDir, existingConfig.documentation);
@@ -384,6 +418,9 @@ async function runDocsInitCommand(context, options, dependencies) {
384
418
  framework: resolved.framework,
385
419
  },
386
420
  guidance: sectionResult,
421
+ ...(scaffold?.installationAdvice
422
+ ? { installationAdvice: scaffold.installationAdvice }
423
+ : {}),
387
424
  });
388
425
  }
389
426
  else {
@@ -456,6 +493,8 @@ export function createDocsInitCommand(overrides = {}) {
456
493
  .addOption(new Option('--app-name <name>', 'Docs app name (inapplicable to Markdown)'))
457
494
  .addOption(new Option('--site-name <name>', 'Site display title or Markdown documentation title'))
458
495
  .addOption(new Option('--target-dir <path>', 'Docs directory (Markdown defaults to docs; requires a dedicated directory)'))
496
+ .option('--ia-preset <preset>', 'Approved IA preset (requires --planned-pages; fresh empty target only)')
497
+ .option('--planned-pages <count>', 'Anticipated reader pages: integer >=1; collapse below 15 (requires --ia-preset)')
459
498
  .addOption(new Option('--description <text>', 'Documentation description'))
460
499
  .addOption(new Option('--lint <mode>', 'Markdown lint mode').choices([
461
500
  'none',
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/markdown.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAKjE,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,mBAAmB,CAAC;AAE3B,gFAAgF;AAChF,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CA0CjB;AAsBD,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB;IAClE,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,sBAAsB,CAAC;CACxC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3C,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,mBAAmB,EAAE,sBAAsB,CAAC;IAC5C,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,mBAAmB,EAAE,sBAAsB,CAAC;CAC7C;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAG7C,QAAQ,CAAC,MAAM,EAAE,kBAAkB;IAFrC,YACE,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,kBAAkB,EACnC,KAAK,EAAE,OAAO,EAGf;CACF;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,sBAAsB,GAChC,IAAI,CAeN;AA6JD,kEAAkE;AAClE,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CA2E3B;AAED,kFAAkF;AAClF,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,kBAAkB,CAAC,CA8E7B"}
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/markdown.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAMjE,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,mBAAmB,CAAC;AAE3B,gFAAgF;AAChF,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CA0CjB;AAsBD,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB;IAClE,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,sBAAsB,CAAC;CACxC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3C,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,mBAAmB,EAAE,sBAAsB,CAAC;IAC5C,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,mBAAmB,EAAE,sBAAsB,CAAC;CAC7C;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAG7C,QAAQ,CAAC,MAAM,EAAE,kBAAkB;IAFrC,YACE,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,kBAAkB,EACnC,KAAK,EAAE,OAAO,EAGf;CACF;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,sBAAsB,GAChC,IAAI,CAeN;AA6JD,kEAAkE;AAClE,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAuG3B;AAED,kFAAkF;AAClF,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,kBAAkB,CAAC,CA+E7B"}
@@ -4,6 +4,7 @@ import { createExclusionMatcher } from '../../docs/index-generate/generator.js';
4
4
  import { dirExists, ensureDir } from '../../../fs/io.js';
5
5
  import { normalizeToPosixPath, validatePathWithinScope } from '../../../fs/paths.js';
6
6
  import { parse as parseYaml } from 'yaml';
7
+ import { mergeTemplateExclusion, planPresetContent } from './content.js';
7
8
  import { humanizeAppName, } from './resolve-options.js';
8
9
  /** Validate a dedicated Markdown root, including existing symlink ancestors. */
9
10
  export async function validateMarkdownTarget(repoRoot, targetDir) {
@@ -192,15 +193,27 @@ export async function planMarkdownDocs(options) {
192
193
  (await readdir(appRoot)).length > 0) {
193
194
  throw new Error(`Markdown docs target is not empty: ${targetDir}. Use --adopt to preserve existing docs, then run oat-docs-analyze for content gaps.`);
194
195
  }
196
+ if (options.iaPreset &&
197
+ (await dirExists(appRoot)) &&
198
+ (await readdir(appRoot)).length > 0)
199
+ throw new Error('Preset init requires an empty docs target. Preserve existing docs and use oat-docs-analyze with individually approved oat-docs-apply.');
200
+ const contentPlan = await planPresetContent({ ...options, markdown: true });
195
201
  const documentationConfig = {
196
202
  ...options.documentation,
197
203
  root: targetDir,
198
204
  tooling: 'markdown',
199
205
  index: `${targetDir}/index.md`,
206
+ ...(contentPlan
207
+ ? {
208
+ nonReaderPaths: mergeTemplateExclusion(options.documentation?.nonReaderPaths),
209
+ }
210
+ : {}),
200
211
  };
201
212
  const configChanged = options.documentation?.root !== targetDir ||
202
213
  options.documentation?.tooling !== 'markdown' ||
203
- options.documentation?.index !== `${targetDir}/index.md`;
214
+ options.documentation?.index !== `${targetDir}/index.md` ||
215
+ (contentPlan !== null &&
216
+ !options.documentation?.nonReaderPaths?.includes('contributing/templates/**'));
204
217
  const existing = new Map();
205
218
  for (const name of ['index.md', 'contributing.md'])
206
219
  existing.set(name, await readBaseline(options.repoRoot, join(appRoot, name)));
@@ -223,9 +236,14 @@ export async function planMarkdownDocs(options) {
223
236
  const template = await readFile(join(options.assetsRoot, 'templates', 'docs-markdown', name), 'utf8');
224
237
  files.push({
225
238
  name,
226
- content: renderMarkdownTemplate(template, options, contents),
239
+ content: (contentPlan?.files.find((file) => file.name === name)?.content ??
240
+ renderMarkdownTemplate(template, options, contents)) +
241
+ (contentPlan && name === 'contributing.md'
242
+ ? `\n${contentPlan.guidance}`
243
+ : ''),
227
244
  });
228
245
  }
246
+ files.push(...(contentPlan?.files.filter((file) => file.name !== 'index.md') ?? []));
229
247
  return {
230
248
  repoRoot: options.repoRoot,
231
249
  targetDir,
@@ -254,6 +272,7 @@ export async function applyMarkdownDocsPlan(plan) {
254
272
  for (const { name, content } of plan.files) {
255
273
  await validateMarkdownTarget(plan.repoRoot, plan.targetDir);
256
274
  const path = join(plan.appRoot, name);
275
+ await ensureDir(dirname(path));
257
276
  let handle;
258
277
  try {
259
278
  handle = await open(path, 'wx');
@@ -1,10 +1,11 @@
1
1
  import type { PromptContext, SelectChoice } from '../../shared/shared.prompts.js';
2
+ import { type PresetSelection } from './content.js';
2
3
  export type DocsRepoShape = 'monorepo' | 'single-package' | 'nested-standalone';
3
4
  export type DocsDetectedRepoShape = Exclude<DocsRepoShape, 'nested-standalone'>;
4
5
  export type DocsFramework = 'fumadocs' | 'mkdocs' | 'markdown';
5
6
  export type DocsLintMode = 'none' | 'markdownlint-cli2';
6
7
  export type DocsFormatMode = 'oxfmt' | 'none';
7
- export interface DocsInitResolvedOptions {
8
+ export interface DocsInitResolvedOptions extends PresetSelection {
8
9
  repoRoot: string;
9
10
  repoShape: DocsRepoShape;
10
11
  framework: DocsFramework;
@@ -23,6 +24,8 @@ export interface ResolveDocsInitOptionsInput {
23
24
  interactive: boolean;
24
25
  acceptDefaults: boolean;
25
26
  providedFramework?: DocsFramework;
27
+ providedIaPreset?: string;
28
+ providedPlannedPages?: string;
26
29
  providedAdopt?: boolean;
27
30
  providedAppName?: string;
28
31
  providedSiteName?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-options.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/resolve-options.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolve-options.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/resolve-options.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACb,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAEzE,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,gBAAgB,GAAG,mBAAmB,CAAC;AAChF,MAAM,MAAM,qBAAqB,GAAG,OAAO,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAAC;AAChF,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;AAC/D,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,mBAAmB,CAAC;AACxD,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,CAAC;AAE9C,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,aAAa,CAAC;IACzB,SAAS,EAAE,aAAa,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,aAAa,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,aAAa,CAAC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,EAAE,CAChB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,aAAa,KACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5B,eAAe,EAAE,CAAC,CAAC,SAAS,MAAM,EAChC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,EAC1B,GAAG,EAAE,aAAa,KACf,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACvE;AAkBD,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,aAAa,GACvB,MAAM,CAMR;AAED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,MAAM,GACd,MAAM,CAMR;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMvD;AAoBD,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,yBAAyB,GACtC,OAAO,CAAC,qBAAqB,CAAC,CAqBhC;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM,CAG/D;AAED,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,aAAa,EACxB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,aAAa,CAkBf;AAED,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAgJzC;AAED,eAAO,MAAM,oCAAoC,EAAE,yBAOlD,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { basename, isAbsolute, join, relative, resolve } from 'node:path';
2
2
  import { dirExists, fileExists } from '../../../fs/io.js';
3
+ import { resolvePresetSelection } from './content.js';
3
4
  const FRAMEWORK_CHOICES = [
4
5
  { label: 'Fumadocs (Next.js + MDX, static export)', value: 'fumadocs' },
5
6
  { label: 'MkDocs (Python, Material theme)', value: 'mkdocs' },
@@ -83,6 +84,7 @@ export function resolveEffectiveDocsShape(repoShape, framework, repoRoot, target
83
84
  return isRepoSubdirectory ? 'nested-standalone' : repoShape;
84
85
  }
85
86
  export async function resolveDocsInitOptions(input) {
87
+ const selection = resolvePresetSelection(input.providedIaPreset, input.providedPlannedPages);
86
88
  const ctx = { interactive: input.interactive };
87
89
  const framework = input.providedFramework ||
88
90
  (input.interactive && !input.acceptDefaults
@@ -109,6 +111,7 @@ export async function resolveDocsInitOptions(input) {
109
111
  if (!targetDir)
110
112
  return null;
111
113
  return {
114
+ ...selection,
112
115
  repoRoot: input.repoRoot,
113
116
  repoShape: input.repoShape,
114
117
  framework,
@@ -168,6 +171,7 @@ export async function resolveDocsInitOptions(input) {
168
171
  }
169
172
  const repoShape = resolveEffectiveDocsShape(input.repoShape, framework, input.repoRoot, targetDir);
170
173
  return {
174
+ ...selection,
171
175
  repoRoot: input.repoRoot,
172
176
  repoShape,
173
177
  framework,
@@ -7,6 +7,7 @@ export interface ScaffoldDocsAppResult {
7
7
  appRoot: string;
8
8
  createdFiles: string[];
9
9
  documentationConfig: OatDocumentationConfig;
10
+ installationAdvice?: string[];
10
11
  }
11
12
  export interface OatDepContext {
12
13
  isOatRepo: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/scaffold.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAMjE,OAAO,KAAK,EAEV,aAAa,EACb,uBAAuB,EAExB,MAAM,mBAAmB,CAAC;AAoG3B,MAAM,WAAW,sBAAuB,SAAQ,uBAAuB;IACrE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mBAAmB,EAAE,sBAAsB,CAAC;CAC7C;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAED,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAEtC,MAAM,WAAW,2BAA2B;IAC1C,iBAAiB,EAAE,MAAM,YAAY,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACjE,0BAA0B,EAAE,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,KACZ,YAAY,CAAC,OAAO,CAAC,CAAC;CAC5B;AAUD,eAAO,MAAM,aAAa,YAAY,CAAC;AAEvC,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOxE;AAgDD,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC,CAaxB;AA0ND;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,MAAM,GAChB,sBAAsB,CAwBxB;AA6CD,wBAAsB,eAAe,CACnC,OAAO,EAAE,sBAAsB,EAC/B,SAAS,GAAE,OAAO,CAAC,2BAA2B,CAAM,GACnD,OAAO,CAAC,qBAAqB,CAAC,CAyDhC"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/scaffold.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAOjE,OAAO,KAAK,EAEV,aAAa,EACb,uBAAuB,EAExB,MAAM,mBAAmB,CAAC;AAqG3B,MAAM,WAAW,sBAAuB,SAAQ,uBAAuB;IACrE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mBAAmB,EAAE,sBAAsB,CAAC;IAC5C,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAED,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAEtC,MAAM,WAAW,2BAA2B;IAC1C,iBAAiB,EAAE,MAAM,YAAY,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACjE,0BAA0B,EAAE,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,KACZ,YAAY,CAAC,OAAO,CAAC,CAAC;CAC5B;AAUD,eAAO,MAAM,aAAa,YAAY,CAAC;AAEvC,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOxE;AAgDD,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC,CAaxB;AAmOD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,MAAM,GAChB,sBAAsB,CAwBxB;AAyDD,wBAAsB,eAAe,CACnC,OAAO,EAAE,sBAAsB,EAC/B,SAAS,GAAE,OAAO,CAAC,2BAA2B,CAAM,GACnD,OAAO,CAAC,qBAAqB,CAAC,CA0GhC"}
@@ -1,7 +1,8 @@
1
- import { readdir, readFile, writeFile } from 'node:fs/promises';
1
+ import { readdir, readFile, realpath, writeFile } from 'node:fs/promises';
2
2
  import { basename, dirname, isAbsolute, join, relative, resolve, } from 'node:path';
3
3
  import { dirExists, ensureDir, fileExists } from '../../../fs/io.js';
4
4
  import { OAT_VERSION } from '../../../shared/oat-version.js';
5
+ import { planPresetContent } from './content.js';
5
6
  import { buildDocsCommands, shellQuote } from './docs-commands.js';
6
7
  import { applyMarkdownDocsPlan, planMarkdownDocs } from './markdown.js';
7
8
  import { getTemplateDir } from './resolve-options.js';
@@ -11,7 +12,7 @@ const MKDOCS_TEMPLATE_FILES = [
11
12
  source: join('docs', 'contributing', name),
12
13
  destination: join('docs', 'contributing', name),
13
14
  })),
14
- { source: '.gitignore', destination: '.gitignore' },
15
+ { source: 'gitignore.template', destination: '.gitignore' },
15
16
  { source: 'mkdocs.yml', destination: 'mkdocs.yml' },
16
17
  { source: 'package.json.template', destination: 'package.json' },
17
18
  { source: 'requirements.txt', destination: 'requirements.txt' },
@@ -36,7 +37,8 @@ const FUMA_TEMPLATE_FILES = [
36
37
  source: join('app', route, 'route.ts'),
37
38
  destination: join('app', route, 'route.ts'),
38
39
  })),
39
- { source: '.gitignore', destination: '.gitignore' },
40
+ { source: 'gitignore.template', destination: '.gitignore' },
41
+ { source: 'pnpm-workspace.yaml', destination: 'pnpm-workspace.yaml' },
40
42
  { source: 'next.config.js', destination: 'next.config.js' },
41
43
  { source: 'postcss.config.mjs', destination: 'postcss.config.mjs' },
42
44
  { source: 'source.config.ts', destination: 'source.config.ts' },
@@ -250,6 +252,8 @@ function renderTemplate(template, options, depContext, packageManagerField, node
250
252
  '{{PACKAGE_NAME}}': options.appName,
251
253
  '{{SITE_NAME}}': options.siteName,
252
254
  '{{SITE_DESCRIPTION}}': options.siteDescription,
255
+ '{{PAGE_DESCRIPTION}}': (options.siteDescription.trim() ||
256
+ `Reader guides and contributor information for ${options.siteName}.`).replaceAll("'", "''"),
253
257
  '{{INSTALL_CMD}}': commands.install,
254
258
  '{{DEV_CMD}}': commands.dev,
255
259
  '{{BUILD_CMD}}': commands.build,
@@ -273,6 +277,9 @@ function renderTemplate(template, options, depContext, packageManagerField, node
273
277
  '{{APP_CWD}}': shellQuote(options.targetDir),
274
278
  '{{LINT_STATUS}}': options.lint === 'none' ? 'disabled' : 'enabled (markdownlint-cli2)',
275
279
  '{{FORMAT_STATUS}}': options.format === 'none' ? 'disabled' : 'enabled (oxfmt)',
280
+ '{{DOCS_CHECK_CMD}}': command(depContext.isOatRepo
281
+ ? `pnpm -w run cli:source -- docs check --target-dir ${shellQuote(options.targetDir)}`
282
+ : 'oat docs check --target-dir .'),
276
283
  '{{NAV_SYNC_CMD}}': command(buildNavSyncCheckCmd(depContext.isOatRepo, options.targetDir).replace(/ --check$/, '')),
277
284
  '{{GENERATE_INDEX_CMD}}': command(buildGenerateIndexCmd(depContext.isOatRepo, options.targetDir)),
278
285
  '{{NAV_SYNC_CHECK_CMD}}': command(buildNavSyncCheckCmd(depContext.isOatRepo, options.targetDir)),
@@ -341,6 +348,19 @@ async function detectNodeRequirement(repoRoot) {
341
348
  }
342
349
  return '>=22.17.0';
343
350
  }
351
+ // Any enclosing pnpm root makes a local boundary unsafe, even when the
352
+ // requested repo shape was detected from a directory inside that workspace.
353
+ async function hasAncestorPnpmWorkspace(appRoot) {
354
+ let current = dirname(await realpath(appRoot));
355
+ while (true) {
356
+ if (await fileExists(join(current, 'pnpm-workspace.yaml')))
357
+ return true;
358
+ const parent = dirname(current);
359
+ if (parent === current)
360
+ return false;
361
+ current = parent;
362
+ }
363
+ }
344
364
  async function ensureTargetWritable(appRoot) {
345
365
  if (!(await dirExists(appRoot))) {
346
366
  return;
@@ -368,21 +388,54 @@ export async function scaffoldDocsApp(options, overrides = {}) {
368
388
  throw new Error(`Docs app templates not found under ${templateRoot}`);
369
389
  }
370
390
  await ensureTargetWritable(appRoot);
391
+ const contentPlan = await planPresetContent({ ...options, markdown: false });
371
392
  await ensureDir(appRoot);
372
393
  const packageManagerField = await buildPackageManagerField(options, appRoot, dependencies);
373
394
  const nodeRequirement = await detectNodeRequirement(options.repoRoot);
395
+ const independentPnpmRoot = options.repoShape !== 'monorepo' &&
396
+ !(await hasAncestorPnpmWorkspace(appRoot));
374
397
  for (const templateFile of frameworkConfig.templateFiles) {
398
+ if (templateFile.destination === 'pnpm-workspace.yaml' &&
399
+ !independentPnpmRoot)
400
+ continue;
401
+ if (contentPlan &&
402
+ [join('docs', 'index.md'), join('docs', 'getting-started.md')].includes(templateFile.destination))
403
+ continue;
375
404
  const source = join(templateRoot, templateFile.source);
376
405
  const destination = join(appRoot, templateFile.destination);
377
406
  const template = await readFile(source, 'utf8');
378
- const rendered = renderTemplate(template, options, depContext, packageManagerField, nodeRequirement, templateFile.destination === 'package.json');
407
+ let rendered = renderTemplate(template, options, depContext, packageManagerField, nodeRequirement, templateFile.destination === 'package.json');
408
+ if (contentPlan && templateFile.destination === 'AGENTS.md') {
409
+ rendered = rendered.replace('This starter separates reader Getting Started from contributor setup.', 'This starter uses the selected reader tracks and entry principles listed below.');
410
+ rendered += `\n${contentPlan.guidance}`;
411
+ }
412
+ if (contentPlan &&
413
+ templateFile.destination ===
414
+ join('docs', 'contributing', 'docs-toolchain.md'))
415
+ rendered = rendered.replaceAll('[Getting Started](../getting-started.md)', '[the documentation home](../index.md)');
379
416
  await ensureDir(dirname(destination));
380
417
  await writeFile(destination, rendered, 'utf8');
381
418
  createdFiles.push(templateFile.destination);
382
419
  }
420
+ for (const file of contentPlan?.files ?? []) {
421
+ const destination = join(appRoot, 'docs', file.name);
422
+ await ensureDir(dirname(destination));
423
+ await writeFile(destination, file.content, 'utf8');
424
+ createdFiles.push(join('docs', file.name));
425
+ }
383
426
  return {
384
427
  appRoot,
385
428
  createdFiles,
429
+ ...(options.framework === 'fumadocs'
430
+ ? {
431
+ installationAdvice: [
432
+ independentPnpmRoot
433
+ ? 'Created app-install-root pnpm-workspace.yaml with mdast-util-to-markdown: 2.1.2 for Fumadocs Markdown compatibility; retain this policy and the generated lockfile.'
434
+ : 'Before installing, approve or manually set overrides.mdast-util-to-markdown to "2.1.2" in the effective install-root pnpm-workspace.yaml, preserving existing settings. No local workspace boundary or root dependency-policy edit was made.',
435
+ `Read ${join(options.targetDir, 'docs/contributing/docs-toolchain.md')} for exact setup and conflict/skip guidance. --no-root-patch controls root scripts only.`,
436
+ ],
437
+ }
438
+ : {}),
386
439
  documentationConfig: buildDocumentationConfig(options.framework, options.targetDir),
387
440
  };
388
441
  }
@@ -2,6 +2,9 @@ import { type ExclusionMatcher } from '../../docs/shared/exclusions.js';
2
2
  export interface DocsContentsEntry {
3
3
  title: string;
4
4
  href: string;
5
+ line?: number;
6
+ description?: string;
7
+ separator?: string;
5
8
  group?: {
6
9
  title: string;
7
10
  line: number;
@@ -11,6 +14,7 @@ export interface DocsContentsEntry {
11
14
  export declare function hasIndexContents(markdown: string): boolean;
12
15
  export declare function parseIndexContents(markdown: string, sourcePath?: string, options?: {
13
16
  allowEmpty?: boolean;
17
+ locations?: boolean;
14
18
  }): DocsContentsEntry[];
15
19
  export type DocsNavTree = Array<Record<string, DocsNavTree | string> | string>;
16
20
  interface BuildDocsNavTreeOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"contents.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/nav/contents.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,kCAAkC,CAAC;AAG1C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACzC;AA8BD,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,UAAU,SAAa,EACvB,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GACrC,iBAAiB,EAAE,CAoDrB;AAED,MAAM,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;AAE/E,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAMD,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,EACvB,KAAK,EAAE,iBAAiB;AACxB;;;GAGG;AACH,cAAc,GAAE,SAAS,MAAM,EAAY,EAC3C,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAuElE;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,WAAW,CAAC,CA0EtB"}
1
+ {"version":3,"file":"contents.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/nav/contents.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,kCAAkC,CAAC;AAG1C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACzC;AA8BD,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,UAAU,SAAa,EACvB,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1D,iBAAiB,EAAE,CA8DrB;AAED,MAAM,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;AAE/E,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAMD,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,EACvB,KAAK,EAAE,iBAAiB;AACxB;;;GAGG;AACH,cAAc,GAAE,SAAS,MAAM,EAAY,EAC3C,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAuElE;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,WAAW,CAAC,CA0EtB"}
@@ -64,6 +64,16 @@ export function parseIndexContents(markdown, sourcePath = 'index.md', options =
64
64
  title: match[1].trim(),
65
65
  href: match[2].trim(),
66
66
  ...(group ? { group } : {}),
67
+ ...(options.locations
68
+ ? {
69
+ line: i + 1,
70
+ description: line
71
+ .slice(match[0].length)
72
+ .replace(/^\s*[-–—:]\s*/, '')
73
+ .trim(),
74
+ separator: /^\s*([-–—:])/.exec(line.slice(match[0].length))?.[1],
75
+ }
76
+ : {}),
67
77
  });
68
78
  groupEntries += 1;
69
79
  }
@@ -0,0 +1,38 @@
1
+ /** Stable portable documentation rule identifiers. */
2
+ export declare const DOCS_CHECK_RULES: readonly ['directory-index', 'root-width', 'contents-width', 'leaf-size', 'folder-size', 'depth', 'page-length', 'frontmatter', 'description', 'h1', 'links', 'contents-description', 'overview', 'contents-separator', 'navigation', 'commands', 'mermaid', 'diagram-accessibility', 'diagram-pairs', 'diagram-freshness', 'image-alt', 'provenance'];
3
+ export type DocsCheckRule = (typeof DOCS_CHECK_RULES)[number];
4
+ export type DocsCheckSeverity = 'error' | 'warn' | 'off';
5
+ export declare const DOCS_CHECK_THRESHOLDS: {
6
+ rootWarn: number;
7
+ rootError: number;
8
+ contentsWarn: number;
9
+ contentsError: number;
10
+ folderWarn: number;
11
+ folderError: number;
12
+ depthWarn: number;
13
+ depthError: number;
14
+ pageLines: number;
15
+ referenceLines: number;
16
+ referenceH3: number;
17
+ descriptionMin: number;
18
+ descriptionMax: number;
19
+ overviewWords: number;
20
+ altMax: number;
21
+ };
22
+ export interface DocumentationCheckConfig {
23
+ rules?: Partial<Record<DocsCheckRule, DocsCheckSeverity>>;
24
+ thresholds?: Partial<typeof DOCS_CHECK_THRESHOLDS>;
25
+ exceptions?: Array<{
26
+ path: string;
27
+ rule: DocsCheckRule;
28
+ reason: string;
29
+ severity?: DocsCheckSeverity;
30
+ }>;
31
+ provenance?: {
32
+ ticketPatterns?: string[];
33
+ milestonePatterns?: string[];
34
+ };
35
+ diagramBaseRef?: string;
36
+ }
37
+ export declare function normalizeDocumentationCheck(value: unknown): DocumentationCheckConfig | undefined;
38
+ //# sourceMappingURL=documentation-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"documentation-check.d.ts","sourceRoot":"","sources":["../../src/config/documentation-check.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,YAC3B,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,OAAO,EACP,aAAa,EACb,aAAa,EACb,aAAa,EACb,IAAI,EACJ,OAAO,EACP,sBAAsB,EACtB,UAAU,EACV,oBAAoB,EACpB,YAAY,EACZ,UAAU,EACV,SAAS,EACT,uBAAuB,EACvB,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,YAAY,CACJ,CAAC;AACX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC9D,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AACzD,eAAO,MAAM,qBAAqB;IAChC,QAAQ;IACR,SAAS;IACT,YAAY;IACZ,aAAa;IACb,UAAU;IACV,WAAW;IACX,SAAS;IACT,UAAU;IACV,SAAS;IACT,cAAc;IACd,WAAW;IACX,cAAc;IACd,cAAc;IACd,aAAa;IACb,MAAM;CACP,CAAC;AACF,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC1D,UAAU,CAAC,EAAE,OAAO,CAAC,OAAO,qBAAqB,CAAC,CAAC;IACnD,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,aAAa,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,iBAAiB,CAAC;KAC9B,CAAC,CAAC;IACH,UAAU,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAID,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,GACb,wBAAwB,GAAG,SAAS,CAgHtC"}
@@ -0,0 +1,132 @@
1
+ /** Stable portable documentation rule identifiers. */
2
+ export const DOCS_CHECK_RULES = [
3
+ 'directory-index',
4
+ 'root-width',
5
+ 'contents-width',
6
+ 'leaf-size',
7
+ 'folder-size',
8
+ 'depth',
9
+ 'page-length',
10
+ 'frontmatter',
11
+ 'description',
12
+ 'h1',
13
+ 'links',
14
+ 'contents-description',
15
+ 'overview',
16
+ 'contents-separator',
17
+ 'navigation',
18
+ 'commands',
19
+ 'mermaid',
20
+ 'diagram-accessibility',
21
+ 'diagram-pairs',
22
+ 'diagram-freshness',
23
+ 'image-alt',
24
+ 'provenance',
25
+ ];
26
+ export const DOCS_CHECK_THRESHOLDS = {
27
+ rootWarn: 10,
28
+ rootError: 14,
29
+ contentsWarn: 10,
30
+ contentsError: 15,
31
+ folderWarn: 12,
32
+ folderError: 20,
33
+ depthWarn: 4,
34
+ depthError: 5,
35
+ pageLines: 500,
36
+ referenceLines: 1000,
37
+ referenceH3: 40,
38
+ descriptionMin: 40,
39
+ descriptionMax: 160,
40
+ overviewWords: 10,
41
+ altMax: 155,
42
+ };
43
+ function record(value) {
44
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
45
+ }
46
+ export function normalizeDocumentationCheck(value) {
47
+ if (value === undefined)
48
+ return undefined;
49
+ const fail = (detail) => {
50
+ throw new Error(`Invalid documentation.check: ${detail}. Repair with oat config set documentation.check '<JSON>' or oat config unset documentation.check --shared.`);
51
+ };
52
+ const object = (input, keys, label) => {
53
+ if (!record(input))
54
+ return fail(`${label} must be an object`);
55
+ const unknown = Object.keys(input).find((key) => !keys.includes(key));
56
+ if (unknown)
57
+ return fail(`unknown ${label} option "${unknown}"`);
58
+ return input;
59
+ };
60
+ const severity = (v) => typeof v === 'string' && ['error', 'warn', 'off'].includes(v);
61
+ const root = object(value, ['rules', 'thresholds', 'exceptions', 'provenance', 'diagramBaseRef'], 'check');
62
+ if (root.rules !== undefined) {
63
+ for (const [key, v] of Object.entries(object(root.rules, DOCS_CHECK_RULES, 'rules'))) {
64
+ if (!severity(v))
65
+ fail(`${key} severity must be error, warn or off`);
66
+ }
67
+ }
68
+ if (root.thresholds !== undefined) {
69
+ const thresholds = object(root.thresholds, Object.keys(DOCS_CHECK_THRESHOLDS), 'thresholds');
70
+ for (const [key, v] of Object.entries(thresholds)) {
71
+ if (typeof v !== 'number' || !Number.isSafeInteger(v) || v < 0)
72
+ fail(`${key} must be a nonnegative safe integer`);
73
+ }
74
+ const t = {
75
+ ...DOCS_CHECK_THRESHOLDS,
76
+ ...thresholds,
77
+ };
78
+ for (const [low, high] of [
79
+ ['rootWarn', 'rootError'],
80
+ ['contentsWarn', 'contentsError'],
81
+ ['folderWarn', 'folderError'],
82
+ ['depthWarn', 'depthError'],
83
+ ['descriptionMin', 'descriptionMax'],
84
+ ]) {
85
+ if (t[low] > t[high])
86
+ fail(`${low} must not exceed ${high}`);
87
+ }
88
+ }
89
+ if (root.exceptions !== undefined) {
90
+ if (!Array.isArray(root.exceptions))
91
+ fail('exceptions must be an array');
92
+ for (const input of root.exceptions) {
93
+ const e = object(input, ['path', 'rule', 'reason', 'severity'], 'exception');
94
+ if (typeof e.path !== 'string' ||
95
+ !e.path.trim() ||
96
+ e.path.startsWith('/') ||
97
+ e.path.includes('\\') ||
98
+ e.path.split('/').includes('..'))
99
+ fail('exception path must be a content-root-relative bounded pattern');
100
+ if (!DOCS_CHECK_RULES.includes(e.rule))
101
+ fail(`unknown exception rule "${String(e.rule)}"`);
102
+ if (typeof e.reason !== 'string' || !e.reason.trim())
103
+ fail('every exception needs a nonempty reason');
104
+ if (e.severity !== undefined && !severity(e.severity))
105
+ fail('exception severity must be error, warn or off');
106
+ }
107
+ }
108
+ if (root.provenance !== undefined) {
109
+ const p = object(root.provenance, ['ticketPatterns', 'milestonePatterns'], 'provenance');
110
+ for (const [key, patterns] of Object.entries(p)) {
111
+ if (!Array.isArray(patterns) ||
112
+ patterns.some((pattern) => typeof pattern !== 'string' || !pattern.trim()))
113
+ fail(`${key} must be an array of nonempty regular expression strings`);
114
+ for (const pattern of patterns) {
115
+ try {
116
+ RegExp(pattern, 'u');
117
+ }
118
+ catch {
119
+ fail(`invalid ${key} regular expression "${pattern}"`);
120
+ }
121
+ }
122
+ }
123
+ }
124
+ if (root.diagramBaseRef !== undefined &&
125
+ (typeof root.diagramBaseRef !== 'string' ||
126
+ !root.diagramBaseRef.trim() ||
127
+ root.diagramBaseRef.startsWith('-') ||
128
+ /\s/.test(root.diagramBaseRef) ||
129
+ root.diagramBaseRef.includes(String.fromCharCode(0))))
130
+ fail('diagramBaseRef must be a Git ref without whitespace or leading dash');
131
+ return root;
132
+ }
@@ -1,4 +1,5 @@
1
1
  import { type WorkflowDispatchProviderValue } from './dispatch-matrix.js';
2
+ import { type DocumentationCheckConfig } from './documentation-check.js';
2
3
  export { VALID_DISPATCH_MATRIX_TIERS, isCodexMaterializedRouteTarget, isWorkflowDispatchCandidateLadder, isWorkflowDispatchFallbackRoute, toWorkflowDispatchCandidateLadder, validateDispatchRouteTarget, type DispatchRouteTargetValidation, type WorkflowDispatchCandidate, type WorkflowDispatchCandidateLadder, type WorkflowDispatchFallbackRoute, type WorkflowDispatchLegacyMatrixCell, type WorkflowDispatchMatrixCell, type WorkflowDispatchMatrixTier, type WorkflowDispatchProviderValue, type WorkflowDispatchRoute, type WorkflowDispatchRouteEntry, type WorkflowDispatchRouteTarget, } from './dispatch-matrix.js';
3
4
  /**
4
5
  * The CLAUDE.md strategies `oat instructions sync` and
@@ -33,6 +34,7 @@ export interface OatDocumentationIa {
33
34
  verification?: 'triad' | 'agent-only' | 'none';
34
35
  }
35
36
  export interface OatDocumentationConfig {
37
+ check?: DocumentationCheckConfig;
36
38
  /** Repository-only mirror; the authored decision and local guidance own IA. */
37
39
  ia?: OatDocumentationIa;
38
40
  /** Content-root-relative globs excluded from reader navigation and manifests. */