@open-agent-toolkit/cli 0.3.26 → 0.3.28

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 (104) hide show
  1. package/README.md +12 -0
  2. package/assets/bundle-metadata.json +1 -1
  3. package/assets/docs/contributing/documentation.md +48 -6
  4. package/assets/docs/contributing/markdown-features.md +14 -2
  5. package/assets/docs/docs-tooling/add-docs-to-a-repo.md +22 -9
  6. package/assets/docs/docs-tooling/check.md +154 -0
  7. package/assets/docs/docs-tooling/commands.md +15 -10
  8. package/assets/docs/docs-tooling/index.md +1 -0
  9. package/assets/docs/docs-tooling/meta.json +7 -1
  10. package/assets/docs/docs-tooling/workflows.md +18 -10
  11. package/assets/docs/getting-started/tool-packs.md +5 -3
  12. package/assets/docs/reference/cli-reference.md +2 -0
  13. package/assets/docs/reference/configuration.md +1 -0
  14. package/assets/docs/skills/index.md +8 -8
  15. package/assets/public-package-versions.json +4 -4
  16. package/assets/skills/oat-docs-analyze/SKILL.md +14 -3
  17. package/assets/skills/oat-docs-analyze/references/legacy-scaffold-checks.md +4 -0
  18. package/assets/skills/oat-docs-authoring/SKILL.md +1 -1
  19. package/assets/skills/oat-docs-authoring/references/validation.md +4 -0
  20. package/assets/skills/oat-docs-bootstrap/SKILL.md +92 -61
  21. package/assets/skills/oat-docs-bootstrap/references/pr-ci.md +89 -0
  22. package/assets/templates/docs-app-fuma/AGENTS.md +57 -0
  23. package/assets/templates/docs-app-fuma/app/[[...slug]]/page.tsx +7 -3
  24. package/assets/templates/docs-app-fuma/app/llms/[...slug]/route.ts +15 -0
  25. package/assets/templates/docs-app-fuma/app/llms-full.txt/route.ts +7 -0
  26. package/assets/templates/docs-app-fuma/app/llms.txt/route.ts +7 -0
  27. package/assets/templates/docs-app-fuma/docs/contributing/docs-toolchain.md +85 -0
  28. package/assets/templates/docs-app-fuma/docs/contributing/index.md +13 -0
  29. package/assets/templates/docs-app-fuma/docs/contributing.md +83 -41
  30. package/assets/templates/docs-app-fuma/docs/getting-started.md +3 -33
  31. package/assets/templates/docs-app-fuma/docs/index.md +3 -3
  32. package/assets/templates/docs-app-fuma/gitignore.template +12 -0
  33. package/assets/templates/docs-app-fuma/lib/source.ts +5 -0
  34. package/assets/templates/docs-app-fuma/package.json.template +2 -1
  35. package/assets/templates/docs-app-fuma/pnpm-workspace.yaml +5 -0
  36. package/assets/templates/docs-app-mkdocs/AGENTS.md +48 -0
  37. package/assets/templates/docs-app-mkdocs/docs/contributing/docs-toolchain.md +46 -0
  38. package/assets/templates/docs-app-mkdocs/docs/contributing/index.md +13 -0
  39. package/assets/templates/docs-app-mkdocs/docs/contributing.md +111 -21
  40. package/assets/templates/docs-app-mkdocs/docs/getting-started.md +7 -25
  41. package/assets/templates/docs-app-mkdocs/docs/index.md +7 -2
  42. package/assets/templates/docs-app-mkdocs/gitignore.template +8 -0
  43. package/assets/templates/docs-app-mkdocs/mkdocs.yml +1 -0
  44. package/assets/templates/docs-app-mkdocs/package.json.template +3 -2
  45. package/dist/commands/config/index.d.ts.map +1 -1
  46. package/dist/commands/config/index.js +35 -3
  47. package/dist/commands/docs/check/check.d.ts +3 -0
  48. package/dist/commands/docs/check/check.d.ts.map +1 -0
  49. package/dist/commands/docs/check/check.js +48 -0
  50. package/dist/commands/docs/check/check.types.d.ts +17 -0
  51. package/dist/commands/docs/check/check.types.d.ts.map +1 -0
  52. package/dist/commands/docs/check/check.types.js +1 -0
  53. package/dist/commands/docs/check/checker.d.ts +8 -0
  54. package/dist/commands/docs/check/checker.d.ts.map +1 -0
  55. package/dist/commands/docs/check/checker.js +82 -0
  56. package/dist/commands/docs/check/commands.d.ts +5 -0
  57. package/dist/commands/docs/check/commands.d.ts.map +1 -0
  58. package/dist/commands/docs/check/commands.js +232 -0
  59. package/dist/commands/docs/check/diagrams.d.ts +5 -0
  60. package/dist/commands/docs/check/diagrams.d.ts.map +1 -0
  61. package/dist/commands/docs/check/diagrams.js +197 -0
  62. package/dist/commands/docs/check/files.d.ts +21 -0
  63. package/dist/commands/docs/check/files.d.ts.map +1 -0
  64. package/dist/commands/docs/check/files.js +121 -0
  65. package/dist/commands/docs/check/markdown.d.ts +60 -0
  66. package/dist/commands/docs/check/markdown.d.ts.map +1 -0
  67. package/dist/commands/docs/check/markdown.js +125 -0
  68. package/dist/commands/docs/check/mermaid-runtime.d.ts +3 -0
  69. package/dist/commands/docs/check/mermaid-runtime.d.ts.map +1 -0
  70. package/dist/commands/docs/check/mermaid-runtime.js +57 -0
  71. package/dist/commands/docs/check/navigation.d.ts +4 -0
  72. package/dist/commands/docs/check/navigation.d.ts.map +1 -0
  73. package/dist/commands/docs/check/navigation.js +104 -0
  74. package/dist/commands/docs/check/reader-rules.d.ts +6 -0
  75. package/dist/commands/docs/check/reader-rules.d.ts.map +1 -0
  76. package/dist/commands/docs/check/reader-rules.js +214 -0
  77. package/dist/commands/docs/index.d.ts.map +1 -1
  78. package/dist/commands/docs/index.js +2 -0
  79. package/dist/commands/docs/init/docs-commands.d.ts +1 -0
  80. package/dist/commands/docs/init/docs-commands.d.ts.map +1 -1
  81. package/dist/commands/docs/init/docs-commands.js +8 -3
  82. package/dist/commands/docs/init/index.d.ts +1 -0
  83. package/dist/commands/docs/init/index.d.ts.map +1 -1
  84. package/dist/commands/docs/init/index.js +8 -0
  85. package/dist/commands/docs/init/scaffold.d.ts +1 -0
  86. package/dist/commands/docs/init/scaffold.d.ts.map +1 -1
  87. package/dist/commands/docs/init/scaffold.js +61 -13
  88. package/dist/commands/docs/nav/contents.d.ts +4 -0
  89. package/dist/commands/docs/nav/contents.d.ts.map +1 -1
  90. package/dist/commands/docs/nav/contents.js +10 -0
  91. package/dist/commands/docs/nav/fumadocs.d.ts.map +1 -1
  92. package/dist/commands/docs/nav/fumadocs.js +32 -10
  93. package/dist/config/documentation-check.d.ts +38 -0
  94. package/dist/config/documentation-check.d.ts.map +1 -0
  95. package/dist/config/documentation-check.js +132 -0
  96. package/dist/config/oat-config.d.ts +2 -0
  97. package/dist/config/oat-config.d.ts.map +1 -1
  98. package/dist/config/oat-config.js +4 -0
  99. package/dist/config/resolve.d.ts.map +1 -1
  100. package/dist/config/resolve.js +1 -0
  101. package/dist/release/public-package-contract.d.ts.map +1 -1
  102. package/dist/release/public-package-contract.js +3 -0
  103. package/package.json +11 -2
  104. package/assets/skills/oat-docs-bootstrap/assets/AGENTS.md.template +0 -64
@@ -1,29 +1,125 @@
1
+ ---
2
+ title: Contributing
3
+ description: 'Authoring contract, generated files, supported syntax and validation.'
4
+ ---
5
+
1
6
  # Contributing to {{SITE_NAME}}
2
7
 
3
- Documentation should ship with the code it explains. This docs app is scaffolded to give contributors and agents a shared contract for navigation, Markdown features, and local tooling.
8
+ Ship documentation with the behavior it explains. Use the [docs toolchain guide](contributing/docs-toolchain.md) for setup and validation and [contributor guides](contributing/index.md) as the local map.
9
+
10
+ Agent working rules: `../AGENTS.md` (app-root source file).
11
+
12
+ ## Authored and generated files
13
+
14
+ | Surface | Owner and action |
15
+ | ---------------------------------------------------- | ------------------------------------------------------------------------- |
16
+ | `docs/**/*.md`, including `docs/**/index.md` | Authored source; edit purpose and Contents maps directly. |
17
+ | `AGENTS.md` and this contributor guide | Authored working rules and human guidance; keep their audiences separate. |
18
+ | `mkdocs.yml` outside `nav:` | Authored framework configuration. |
19
+ | `mkdocs.yml` `nav:` | Committed derived sidebar; regenerate with nav sync. |
20
+ | `site/` | Generated site output; do not edit. |
21
+ | `requirements.txt`, `setup-docs.sh`, package scripts | Authored toolchain; changing pins needs an explicit tooling review. |
22
+
23
+ MkDocs 1.4.2 has no configurable rendering exclusion: non-reader pages leave nav/manifest but still render as routes. Do not promise private draft routes or add an exclusion plugin as an implicit repair.
24
+
25
+ This MkDocs/Material scaffold is **legacy**. [Material's upstream changelog](https://squidfunk.github.io/mkdocs-material/changelog/) states that it is in maintenance mode, with critical bug fixes and security updates through **May 5, 2027**, then upstream maintenance ends. The team identifies [Zensical](https://zensical.org/) as its maintained successor. This date applies to Material, not MkDocs core. Existing Python pins remain unchanged; the maintenance statement does not promise backports to these exact old pins. Plan an explicit tooling review before adopting this path for a new site.
4
26
 
5
27
  ## Navigation contract
6
28
 
7
- - Every documentation directory must contain an `index.md`.
8
- - Each `index.md` must include a `## Contents` section.
9
- - The `## Contents` section is the machine-readable local map for sibling pages and child directories.
10
- - `overview.md` is deprecated in favor of `index.md`.
29
+ Fresh scaffolds set `use_directory_urls: false` in `mkdocs.yml`. Pages use `.html` URLs: `contributing.md` renders as `contributing.html`, and the local map `contributing/index.md` renders as `contributing/index.html`. Keep both source files and `.md`-suffixed authored links; MkDocs resolves them to the distinct rendered destinations. Changing this setting requires reviewing published URLs and inbound links.
30
+
31
+ Every content directory has an authored `index.md` with a useful purpose paragraph and one `## Contents` local map. Prefer `.md` pages with nonempty `title` and `description` frontmatter and exactly one document H1. `overview.md` is deprecated.
32
+
33
+ Within `## Contents`, use dash-only links to sibling pages or child indexes, optionally followed by a description. A `### Label` starts a group and must contain at least one authored entry before the next group/end. Entries before the first group are ungrouped. A `*` or `+` link bullet, or an empty authored group, is an error naming the file and line. The map ends at the next level-two heading; fenced examples are ignored. A self-index link retains the existing landing-page behavior. Optional Markdown inventories keep deterministic fallback when Contents is missing; MkDocs nav sync needs authored maps to construct navigation. The pinned MkDocs build can still render pages absent from its navigation.
34
+
35
+ ```markdown
36
+ ## Contents
37
+
38
+ - [Start here](getting-started.md) - The first safe result.
39
+
40
+ ### Contributor guides
41
+
42
+ - [Toolchain](contributing/index.md) - Local setup and authoring.
43
+ ```
44
+
45
+ `documentation.navOwner: nav-sync` means nav sync owns derived navigation. With `hand-authored` or undeclared ownership, do not silently regenerate; agree the ownership/change first. Configured `documentation.nonReaderPaths` omits drafts/templates from navigation and manifests; an explicit Contents link does not override an exclusion. `documentation.excludes` affects only the manifest. Do not add an exclusion to hide an unlisted reader page.
46
+
47
+ ## Add, move or rename a page
48
+
49
+ 1. Read the nearest authored map and choose a path in its scope; create a child `index.md` when adding a directory.
50
+ 2. Add useful title/description frontmatter, one H1, and the page's reader outcome. Use `.md`-suffixed source links such as `[Guide](guide.md)` and `[Section](section/index.md)`.
51
+ 3. Update the nearest Contents map. For a move/rename, update both source and destination maps and every inbound link in the same change. Review old published URLs; agree a redirect or a static stub/recovery page when needed.
52
+ 4. Refresh owned navigation, run the checks below and inspect the rendered links/navigation before committing. Never repair drift by hand-editing derived files.
53
+
54
+ ## Supported Markdown features
11
55
 
12
- ## Local workflow
56
+ Use the least complex layer that expresses the reader's need: **Markdown → existing transform → MDX**. Ordinary prose stays `.md`. Fumadocs MDX is for actual JSX/component needs; MkDocs does not compile MDX. MDX is excluded from OAT's Markdown manifest and the Fumadocs agent Markdown endpoints.
13
57
 
14
- 1. Install Python dependencies:
58
+ Tables, task lists, fenced code, callouts, Mermaid and `=== "Title"` tabs are supported by the configured framework pipeline. Tabs may contain links, GFM and nested tabs in Fumadocs. Use a language on every fence and `bash` for shell commands.
15
59
 
16
- ```bash
17
- pnpm docs:setup
18
- ```
60
+ === "Syntax"
19
61
 
20
- 2. Run the live preview:
62
+ ````text
63
+ === "Example"
21
64
 
22
- ```bash
23
- pnpm docs:dev
24
- ```
65
+ > [!NOTE]
66
+ > Read the local map before editing.
25
67
 
26
- 3. Run Markdown formatting and linting as configured for this docs app.
68
+ | Check | Result |
69
+ | --- | --- |
70
+ | Reader links | Resolve |
71
+
72
+ ```bash
73
+ cd {{APP_CWD}}
74
+ pnpm docs:lint
75
+ ```
76
+ ````
77
+
78
+ === "Rendered"
79
+
80
+ === "Example"
81
+
82
+ > [!NOTE]
83
+ > Read the local map before editing.
84
+
85
+ | Check | Result |
86
+ | --- | --- |
87
+ | Reader links | Resolve |
88
+
89
+ ```bash
90
+ cd {{APP_CWD}}
91
+ pnpm docs:lint
92
+ ```
93
+
94
+ Not configured: arbitrary custom components, executable notebooks, API playgrounds or screenshot testing. Do not describe those as supported without an approved configuration and a working example. Check the actual package scripts: lint is {{LINT_STATUS}} and formatting is {{FORMAT_STATUS}}; disabled scripts only print a message.
95
+
96
+ ## Diagrams and accessibility
97
+
98
+ Run the app’s docs:check script (from the repository root: `cd {{APP_CWD}} && pnpm docs:check`) before committing. It checks reader metadata/maps/links, navigation, contributor commands and real Mermaid syntax without building the site. Errors fail; warnings prompt review. Fix authored sources, then explicitly sync owned navigation and retry.
99
+
100
+ Mermaid is the diagram source of truth. Important or phone-sized diagrams also get matching `<name>-light.svg` and `<name>-dark.svg` assets. Change the Mermaid and both SVGs in the same commit, preserving nodes, edges and labels. Each SVG uses `role="img"`, a descriptive `<title>` and `<desc>` (connected with `aria-labelledby`), a legible viewBox and readable labels. Keep image alt text concise, about 155 characters or less, and describe the diagram's meaning without inventing claims.
101
+
102
+ === "Syntax"
103
+
104
+ ````text
105
+ === "Mermaid source"
106
+
107
+ ```mermaid
108
+ flowchart LR
109
+ A[Read local map] --> B[Make a focused edit]
110
+ ```
111
+ ````
112
+
113
+ === "Rendered"
114
+
115
+ ```mermaid
116
+ flowchart LR
117
+ accTitle: Documentation edit
118
+ accDescr: Read the local map before making a focused edit.
119
+ A[Read local map] --> B[Make a focused edit]
120
+ ```
121
+
122
+ Put diagram assets under `docs/assets/diagrams/` and link relative to the source page. Keep both SVG variants with the source; automatic light/dark image selection is not configured in this MkDocs scaffold. Inspect theme contrast manually; do not claim the Fumadocs image/basePath behavior here.
27
123
 
28
124
  ## Installed plugins
29
125
 
@@ -112,9 +208,3 @@ Supports tabbed content blocks for related workflows or platform variants.
112
208
  ### `toc`
113
209
 
114
210
  Adds table-of-contents anchors and permalinks for headings.
115
-
116
- ## Agent guidance
117
-
118
- - Treat `index.md` plus its `## Contents` section as the local discovery source of truth.
119
- - Prefer linking to source files and commands explicitly when documenting behavior.
120
- - When adding a new plugin or extension, update this guide with what it does and how to use it.
@@ -1,28 +1,10 @@
1
- # Getting Started
2
-
3
- Use this guide to set up your local environment and preview {{SITE_NAME}}.
4
-
5
- ## Prerequisites
6
-
7
- - Node.js 22+
8
- - pnpm 10+
9
- - Python 3.11+ for MkDocs tooling
1
+ ---
2
+ title: Getting Started
3
+ description: 'Reach the first safe reader result with {{SITE_NAME}}.'
4
+ ---
10
5
 
11
- ## Install documentation tooling
12
-
13
- ```bash
14
- pnpm docs:setup
15
- ```
16
-
17
- ## Run the docs locally
18
-
19
- ```bash
20
- pnpm docs:dev
21
- ```
6
+ # Getting Started
22
7
 
23
- ## Editing workflow
8
+ Start with the [documentation map](index.md), choose the guide for your task, and confirm its prerequisites before changing anything. Your first safe result is to identify the right procedure and its expected outcome.
24
9
 
25
- 1. Update Markdown files under `docs/`.
26
- 2. Check the preview site for formatting and navigation.
27
- 3. Run the formatter and linter before committing.
28
- 4. Keep every directory discoverable through its `index.md` file.
10
+ Replace this starter paragraph with one concrete, low-risk reader task for your product: the input, the command or action, and the result the reader can verify. Keep contributor setup in the [docs toolchain guide](contributing/docs-toolchain.md).
@@ -1,8 +1,13 @@
1
+ ---
2
+ title: '{{SITE_NAME}}'
3
+ description: '{{PAGE_DESCRIPTION}}'
4
+ ---
5
+
1
6
  # {{SITE_NAME}}
2
7
 
3
8
  Use this site as the central documentation hub for the repository. It is organized to support both human readers and AI agents, with every directory exposing an `index.md` entrypoint.
4
9
 
5
10
  ## Contents
6
11
 
7
- - [Getting Started](getting-started.md) - Set up the local docs toolchain and preview the site.
8
- - [Contributing](contributing.md) - Authoring conventions, plugin inventory, and navigation rules.
12
+ - [Getting Started](getting-started.md) - Reach the first safe reader result.
13
+ - [Contributing](contributing/index.md) - Authoring contract and local toolchain setup.
@@ -0,0 +1,8 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # MkDocs build output
5
+ site/
6
+
7
+ # Python virtual environment
8
+ .venv/
@@ -1,5 +1,6 @@
1
1
  site_name: {{SITE_NAME}}
2
2
  docs_dir: './docs'
3
+ use_directory_urls: false
3
4
 
4
5
  site_description: {{SITE_NAME}}
5
6
 
@@ -6,12 +6,13 @@
6
6
  "description": "MkDocs Material documentation for {{SITE_NAME}}.",
7
7
  "scripts": {
8
8
  "docs:dev": "mkdocs serve",
9
- "docs:build": "{{NAV_SYNC_CHECK_CMD}} && mkdocs build",
9
+ "docs:build": "{{DOCS_CHECK_CMD}} && {{NAV_SYNC_CHECK_CMD}} && mkdocs build",
10
10
  "docs:setup": "sh ./setup-docs.sh",
11
+ "docs:check": "{{DOCS_CHECK_CMD}}",
11
12
  "docs:lint": "{{DOCS_LINT_SCRIPT}}",
12
13
  "docs:format": "{{DOCS_FORMAT_SCRIPT}}",
13
14
  "docs:format:check": "{{DOCS_FORMAT_CHECK_SCRIPT}}",
14
- "test": "echo 'Documentation tests complete'"
15
+ "test": "{{DOCS_CHECK_CMD}}"
15
16
  },
16
17
  "devDependencies": {
17
18
  "@open-agent-toolkit/cli": "{{OAT_CLI_DEP}}"{{DEV_DEPENDENCIES}}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@ import { compileDispatchCeilingPreset } from '../../config/dispatch-ceiling-pres
11
11
  import { normalizeDispatchMatrix, validateDispatchRouteTarget, walkDispatchMatrix, } from '../../config/dispatch-matrix.js';
12
12
  import { formatDispatchNotices, terminalReviewerNoticesForMatrix, } from '../../config/dispatch-notices.js';
13
13
  import { dispatchPolicyModeDescription, dispatchPolicyPolicyDescription, managedDispatchPolicyValueList, } from '../../config/dispatch-policy-options.js';
14
+ import { normalizeDocumentationCheck } from '../../config/documentation-check.js';
14
15
  import { parseJsonConfig } from '../../config/json.js';
15
16
  import { DEFAULT_INSTRUCTION_SYNC_STRATEGY, INSTRUCTION_SYNC_STRATEGIES, VALID_DISPATCH_POLICY_MODES, VALID_MANAGED_DISPATCH_POLICIES, MAX_GATE_TIMEOUT_MS, MIN_GATE_TIMEOUT_MS, isValidGateTimeoutMs, isValidProjectLogDigestBound, normalizeWorkflowPostImplementSequence, normalizeDocumentationGuidance, normalizeDocumentationIa, normalizeDocumentationNavOwner, readOatConfig, readOatConfigForDefaultScopeRepair, readOatConfigForDocumentationExcludesRepair, readOatConfigForInstructionPointerExcludesRepair, readOatConfigForInstructionSyncStrategyRepair, readOatConfigWithWarnings, readOatLocalConfig, readUserConfig, writeOatConfig, writeOatLocalConfig, writeUserConfig, VALID_POST_IMPLEMENT_LEGACY_SEQUENCES, } from '../../config/oat-config.js';
16
17
  import { getOwnKey, setOwnKey } from '../../config/own-keys.js';
@@ -67,6 +68,7 @@ const KEY_ORDER = [
67
68
  'archive.awsRegion',
68
69
  'autoReviewAtCheckpoints',
69
70
  'lastPausedProject',
71
+ 'documentation.check',
70
72
  'documentation.ia',
71
73
  'documentation.nonReaderPaths',
72
74
  'documentation.navOwner',
@@ -242,6 +244,17 @@ const CONFIG_CATALOG = [
242
244
  description: 'Deprecated compatibility alias for workflow.autoReviewAtHillCheckpoints. Prefer `oat config set workflow.autoReviewAtHillCheckpoints <true|false>`.',
243
245
  deprecated: { supersededBy: 'workflow.autoReviewAtHillCheckpoints' },
244
246
  },
247
+ {
248
+ key: 'documentation.check',
249
+ group: 'Shared Repo (.oat/config.json)',
250
+ scope: 'shared repo',
251
+ file: '.oat/config.json',
252
+ type: 'JSON object',
253
+ defaultValue: 'null (portable checker defaults)',
254
+ mutability: 'read/write',
255
+ owningCommand: 'oat config set documentation.check <JSON>',
256
+ description: 'Portable docs rule severities, named thresholds, reason-bearing path exceptions, provenance patterns and diagram base ref.',
257
+ },
245
258
  {
246
259
  key: 'documentation.ia',
247
260
  group: 'Shared Repo (.oat/config.json)',
@@ -1822,6 +1835,7 @@ async function setConfigValue(repoRoot, userConfigDir, key, rawValue, surface, d
1822
1835
  const effectiveSurface = surface === 'auto' ? defaultSurfaceForKey(key) : surface;
1823
1836
  if (key === 'documentation.nonReaderPaths' ||
1824
1837
  key === 'documentation.guidance' ||
1838
+ key === 'documentation.check' ||
1825
1839
  key === 'documentation.ia' ||
1826
1840
  key === 'documentation.navOwner') {
1827
1841
  const configPath = effectiveSurface === 'user'
@@ -1831,7 +1845,13 @@ async function setConfigValue(repoRoot, userConfigDir, key, rawValue, surface, d
1831
1845
  const trimmed = rawValue.trim();
1832
1846
  let value;
1833
1847
  try {
1834
- if (key === 'documentation.nonReaderPaths') {
1848
+ if (key === 'documentation.check') {
1849
+ const parsed = JSON.parse(trimmed);
1850
+ if (parsed === null)
1851
+ throw new Error('Expected a checker JSON object.');
1852
+ value = normalizeDocumentationCheck(parsed);
1853
+ }
1854
+ else if (key === 'documentation.nonReaderPaths') {
1835
1855
  const paths = parseDocumentationExcludes(rawValue);
1836
1856
  value = paths.length > 0 ? paths : undefined;
1837
1857
  }
@@ -1848,8 +1868,10 @@ async function setConfigValue(repoRoot, userConfigDir, key, rawValue, surface, d
1848
1868
  : normalizeDocumentationGuidance(trimmed.startsWith('[') ? JSON.parse(trimmed) : trimmed, configPath, effectiveSurface === 'user' ? 'user' : 'shared');
1849
1869
  }
1850
1870
  }
1851
- catch {
1852
- throw new Error(`Invalid ${key} value: ${key === 'documentation.ia' ? 'expected IA JSON with preset, repo-relative decision, optional tracks and verification' : key === 'documentation.navOwner' ? 'expected nav-sync or hand-authored' : 'expected a non-empty path/URL string or ordered non-empty string array'}.`);
1871
+ catch (error) {
1872
+ if (key === 'documentation.check')
1873
+ throw error;
1874
+ throw new Error(`Invalid ${key} value: ${key === 'documentation.ia' ? 'expected IA JSON with preset, repo-relative decision, optional tracks and verification' : key === 'documentation.navOwner' ? 'expected nav-sync or hand-authored' : 'expected a non-empty path/URL string or ordered non-empty string array'}.`, { cause: error });
1853
1875
  }
1854
1876
  let raw = { version: 1 };
1855
1877
  try {
@@ -2450,6 +2472,7 @@ async function unsetConfigValue(repoRoot, userConfigDir, key, surface, dependenc
2450
2472
  async function removeFromSurface(repoRoot, userConfigDir, key, effectiveSurface, path, dependencies) {
2451
2473
  if (key === 'documentation.nonReaderPaths' ||
2452
2474
  key === 'documentation.guidance' ||
2475
+ key === 'documentation.check' ||
2453
2476
  key === 'documentation.ia' ||
2454
2477
  key === 'documentation.navOwner') {
2455
2478
  const configPath = effectiveSurface === 'user'
@@ -2577,6 +2600,15 @@ async function removeConfigPathOnDisk(configPath, path) {
2577
2600
  if (!isRecord(parsed)) {
2578
2601
  return null;
2579
2602
  }
2603
+ // Checker null is malformed rather than an inherited unset sentinel.
2604
+ if (path.join('.') === 'documentation.check' &&
2605
+ isRecord(parsed.documentation) &&
2606
+ Object.hasOwn(parsed.documentation, 'check')) {
2607
+ return {
2608
+ ...parsed,
2609
+ documentation: withoutOwnKey(parsed.documentation, 'check'),
2610
+ };
2611
+ }
2580
2612
  const { next, removed } = removeConfigPath(parsed, path);
2581
2613
  return removed ? next : null;
2582
2614
  }
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function createDocsCheckCommand(): Command;
3
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/check/check.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,sBAAsB,IAAI,OAAO,CA4DhD"}
@@ -0,0 +1,48 @@
1
+ import { buildCommandContext } from '../../../app/command-context.js';
2
+ import { readGlobalOptions } from '../../shared/shared.utils.js';
3
+ import { Command } from 'commander';
4
+ import { checkDocs } from './checker.js';
5
+ export function createDocsCheckCommand() {
6
+ return new Command('check')
7
+ .description('Read-only portable reader, navigation, command and diagram validation')
8
+ .option('--target-dir <dir>', 'Docs app root or literal Markdown content root')
9
+ .option('--rule <id...>', 'Run only these stable rule IDs (repeatable)', (values, previous) => previous.concat(values), [])
10
+ .action(async (options, command) => {
11
+ const context = buildCommandContext(readGlobalOptions(command));
12
+ let result;
13
+ try {
14
+ result = await checkDocs({
15
+ cwd: context.cwd,
16
+ targetDir: options.targetDir,
17
+ rules: options.rule,
18
+ });
19
+ process.exitCode = result.summary.errors ? 1 : 0;
20
+ }
21
+ catch (error) {
22
+ const message = error.message;
23
+ result = {
24
+ summary: { errors: 1, warnings: 0 },
25
+ findings: [
26
+ {
27
+ ruleId: 'configuration',
28
+ severity: 'error',
29
+ path: '.oat/config.json',
30
+ message,
31
+ },
32
+ ],
33
+ };
34
+ // Invalid input/config is actionable. Unexpected filesystem/runtime
35
+ // failures retain the CLI's separate runtime-error exit convention.
36
+ process.exitCode = error.code ? 2 : 1;
37
+ }
38
+ if (context.json)
39
+ context.logger.json(result);
40
+ else {
41
+ for (const f of result.findings) {
42
+ const location = `${f.path}${f.line === undefined ? '' : `:${f.line}`}`;
43
+ context.logger[f.severity === 'error' ? 'error' : 'warn'](`${location} [${f.ruleId}] ${f.message}`);
44
+ }
45
+ context.logger.info(`Docs check: ${result.summary.errors} error(s), ${result.summary.warnings} warning(s).`);
46
+ }
47
+ });
48
+ }
@@ -0,0 +1,17 @@
1
+ import type { DocsCheckRule } from '../../../config/documentation-check.js';
2
+ export interface DocsFinding {
3
+ ruleId: DocsCheckRule | 'configuration';
4
+ severity: 'error' | 'warn';
5
+ path: string;
6
+ line?: number;
7
+ message: string;
8
+ }
9
+ export interface DocsCheckResult {
10
+ summary: {
11
+ errors: number;
12
+ warnings: number;
13
+ };
14
+ findings: DocsFinding[];
15
+ }
16
+ export type Report = (rule: DocsCheckRule, severity: 'error' | 'warn', path: string, message: string, line?: number) => void;
17
+ //# sourceMappingURL=check.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.types.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/check/check.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,aAAa,GAAG,eAAe,CAAC;IACxC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AACD,MAAM,MAAM,MAAM,GAAG,CACnB,IAAI,EAAE,aAAa,EACnB,QAAQ,EAAE,OAAO,GAAG,MAAM,EAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,KACV,IAAI,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import type { DocsCheckResult } from './check.types.js';
2
+ /** Read-only portable checker. Output paths are content-root-relative POSIX. */
3
+ export declare function checkDocs(options: {
4
+ cwd: string;
5
+ targetDir?: string;
6
+ rules?: string[];
7
+ }): Promise<DocsCheckResult>;
8
+ //# sourceMappingURL=checker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checker.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/check/checker.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAuB,MAAM,eAAe,CAAC;AAQ1E,gFAAgF;AAChF,wBAAsB,SAAS,CAAC,OAAO,EAAE;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB,GAAG,OAAO,CAAC,eAAe,CAAC,CAwF3B"}
@@ -0,0 +1,82 @@
1
+ import { createExclusionMatcher, isExcludedPath, } from '../../docs/shared/exclusions.js';
2
+ import { DOCS_CHECK_RULES, } from '../../../config/documentation-check.js';
3
+ import { checkCommands } from './commands.js';
4
+ import { checkDiagrams } from './diagrams.js';
5
+ import { readPage, readerFiles, resolveCheckTarget } from './files.js';
6
+ import { checkNavigation } from './navigation.js';
7
+ import { checkProvenance, checkReaders } from './reader-rules.js';
8
+ /** Read-only portable checker. Output paths are content-root-relative POSIX. */
9
+ export async function checkDocs(options) {
10
+ const unknown = options.rules?.find((rule) => !DOCS_CHECK_RULES.includes(rule));
11
+ if (unknown)
12
+ throw new Error(`Unknown docs check rule "${unknown}". Choose: ${DOCS_CHECK_RULES.join(', ')}.`);
13
+ const target = await resolveCheckTarget(options.cwd, options.targetDir);
14
+ const policy = target.documentation.check;
15
+ const findings = [];
16
+ const exceptions = policy?.exceptions?.map((e) => ({
17
+ ...e,
18
+ matcher: createExclusionMatcher([e.path]),
19
+ })) ?? [];
20
+ const report = (ruleId, defaultSeverity, path, message, line) => {
21
+ if (options.rules?.length && !options.rules.includes(ruleId))
22
+ return;
23
+ let severity = policy?.rules?.[ruleId] ?? defaultSeverity;
24
+ for (const e of exceptions)
25
+ if (e.rule === ruleId && isExcludedPath(e.matcher, path))
26
+ severity = e.severity ?? 'off';
27
+ if (severity === 'off')
28
+ return;
29
+ findings.push({
30
+ ruleId,
31
+ severity,
32
+ path,
33
+ ...(line === undefined ? {} : { line }),
34
+ message,
35
+ });
36
+ };
37
+ const pages = [];
38
+ for (const path of await readerFiles(target)) {
39
+ try {
40
+ const page = await readPage(target, path);
41
+ pages.push(page);
42
+ if (page.frontmatterError)
43
+ report('frontmatter', 'error', path, page.frontmatterError, 1);
44
+ }
45
+ catch (error) {
46
+ const code = error?.code;
47
+ const safeCode = typeof code === 'string' && /^[A-Z][A-Z0-9_]*$/.test(code)
48
+ ? code
49
+ : 'UNKNOWN';
50
+ report('frontmatter', 'error', path, `Cannot read documentation source (${safeCode}); check file permissions and readability.`, 1);
51
+ }
52
+ }
53
+ await checkReaders(target, pages, report);
54
+ checkProvenance(target, pages, report);
55
+ if (!options.rules?.length || options.rules.includes('navigation'))
56
+ await checkNavigation(target, report);
57
+ if (!options.rules?.length || options.rules.includes('commands'))
58
+ await checkCommands(target, pages, report);
59
+ if (!options.rules?.length ||
60
+ options.rules.some((r) => [
61
+ 'mermaid',
62
+ 'diagram-accessibility',
63
+ 'diagram-pairs',
64
+ 'diagram-freshness',
65
+ 'image-alt',
66
+ ].includes(r)))
67
+ await checkDiagrams(target, pages, report);
68
+ findings.sort((a, b) => a.path < b.path
69
+ ? -1
70
+ : a.path > b.path
71
+ ? 1
72
+ : (a.line ?? 0) - (b.line ?? 0) ||
73
+ a.ruleId.localeCompare(b.ruleId) ||
74
+ a.message.localeCompare(b.message));
75
+ return {
76
+ summary: {
77
+ errors: findings.filter((f) => f.severity === 'error').length,
78
+ warnings: findings.filter((f) => f.severity === 'warn').length,
79
+ },
80
+ findings,
81
+ };
82
+ }
@@ -0,0 +1,5 @@
1
+ import type { Report } from './check.types.js';
2
+ import { type CheckTarget } from './files.js';
3
+ import type { ParsedPage } from './markdown.js';
4
+ export declare function checkCommands(target: CheckTarget, pages: ParsedPage[], report: Report): Promise<void>;
5
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/check/commands.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAA0B,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAgI7C,wBAAsB,aAAa,CACjC,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,UAAU,EAAE,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAyJf"}