@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.
- package/README.md +8 -0
- package/assets/bundle-metadata.json +1 -1
- package/assets/docs/contributing/documentation.md +11 -2
- package/assets/docs/docs-tooling/add-docs-to-a-repo.md +12 -0
- package/assets/docs/docs-tooling/check.md +154 -0
- package/assets/docs/docs-tooling/commands.md +61 -11
- package/assets/docs/docs-tooling/index.md +1 -0
- package/assets/docs/docs-tooling/meta.json +7 -1
- package/assets/docs/docs-tooling/workflows.md +4 -0
- package/assets/docs/reference/cli-reference.md +2 -0
- package/assets/docs/reference/configuration.md +1 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/authoring-docs/SKILL.md +2 -2
- package/assets/skills/authoring-docs/references/information-architecture.md +5 -2
- package/assets/skills/authoring-docs/references/page-templates/alert-runbook.md +63 -0
- package/assets/skills/authoring-docs/references/page-templates/command-reference.md +55 -0
- package/assets/skills/authoring-docs/references/page-templates/decisions-pointer.md +44 -0
- package/assets/skills/authoring-docs/references/page-templates/engineering-feature.md +53 -0
- package/assets/skills/authoring-docs/references/page-templates/per-area-agents.md +42 -0
- package/assets/skills/authoring-docs/references/page-templates/product-feature.md +49 -0
- package/assets/skills/authoring-docs/references/page-templates/qa-validation.md +59 -0
- package/assets/skills/authoring-docs/references/page-templates/screen-spec.md +51 -0
- package/assets/skills/authoring-docs/references/page-templates/skill-command-guide.md +44 -0
- package/assets/skills/authoring-docs/references/page-templates/solution-record.md +43 -0
- package/assets/skills/authoring-docs/references/templates.md +22 -2
- package/assets/skills/oat-docs-analyze/SKILL.md +13 -2
- package/assets/skills/oat-docs-authoring/SKILL.md +1 -1
- package/assets/skills/oat-docs-authoring/references/validation.md +4 -0
- package/assets/skills/oat-docs-bootstrap/SKILL.md +63 -6
- package/assets/skills/oat-docs-bootstrap/references/pr-ci.md +89 -0
- package/assets/templates/docs-app-fuma/AGENTS.md +9 -2
- package/assets/templates/docs-app-fuma/docs/contributing/docs-toolchain.md +40 -3
- package/assets/templates/docs-app-fuma/docs/contributing.md +7 -1
- package/assets/templates/docs-app-fuma/docs/index.md +1 -1
- package/assets/templates/docs-app-fuma/gitignore.template +12 -0
- package/assets/templates/docs-app-fuma/package.json.template +2 -1
- package/assets/templates/docs-app-fuma/pnpm-workspace.yaml +5 -0
- package/assets/templates/docs-app-mkdocs/AGENTS.md +4 -2
- package/assets/templates/docs-app-mkdocs/docs/contributing/docs-toolchain.md +4 -2
- package/assets/templates/docs-app-mkdocs/docs/contributing.md +7 -1
- package/assets/templates/docs-app-mkdocs/docs/index.md +1 -1
- package/assets/templates/docs-app-mkdocs/gitignore.template +8 -0
- package/assets/templates/docs-app-mkdocs/package.json.template +3 -2
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +35 -3
- package/dist/commands/docs/check/check.d.ts +3 -0
- package/dist/commands/docs/check/check.d.ts.map +1 -0
- package/dist/commands/docs/check/check.js +48 -0
- package/dist/commands/docs/check/check.types.d.ts +17 -0
- package/dist/commands/docs/check/check.types.d.ts.map +1 -0
- package/dist/commands/docs/check/check.types.js +1 -0
- package/dist/commands/docs/check/checker.d.ts +8 -0
- package/dist/commands/docs/check/checker.d.ts.map +1 -0
- package/dist/commands/docs/check/checker.js +82 -0
- package/dist/commands/docs/check/commands.d.ts +5 -0
- package/dist/commands/docs/check/commands.d.ts.map +1 -0
- package/dist/commands/docs/check/commands.js +232 -0
- package/dist/commands/docs/check/diagrams.d.ts +5 -0
- package/dist/commands/docs/check/diagrams.d.ts.map +1 -0
- package/dist/commands/docs/check/diagrams.js +197 -0
- package/dist/commands/docs/check/files.d.ts +21 -0
- package/dist/commands/docs/check/files.d.ts.map +1 -0
- package/dist/commands/docs/check/files.js +121 -0
- package/dist/commands/docs/check/markdown.d.ts +60 -0
- package/dist/commands/docs/check/markdown.d.ts.map +1 -0
- package/dist/commands/docs/check/markdown.js +125 -0
- package/dist/commands/docs/check/mermaid-runtime.d.ts +3 -0
- package/dist/commands/docs/check/mermaid-runtime.d.ts.map +1 -0
- package/dist/commands/docs/check/mermaid-runtime.js +57 -0
- package/dist/commands/docs/check/navigation.d.ts +4 -0
- package/dist/commands/docs/check/navigation.d.ts.map +1 -0
- package/dist/commands/docs/check/navigation.js +104 -0
- package/dist/commands/docs/check/reader-rules.d.ts +6 -0
- package/dist/commands/docs/check/reader-rules.d.ts.map +1 -0
- package/dist/commands/docs/check/reader-rules.js +214 -0
- package/dist/commands/docs/index.d.ts.map +1 -1
- package/dist/commands/docs/index.js +2 -0
- package/dist/commands/docs/init/content.d.ts +23 -0
- package/dist/commands/docs/init/content.d.ts.map +1 -0
- package/dist/commands/docs/init/content.js +361 -0
- package/dist/commands/docs/init/index.d.ts +1 -0
- package/dist/commands/docs/init/index.d.ts.map +1 -1
- package/dist/commands/docs/init/index.js +40 -1
- package/dist/commands/docs/init/markdown.d.ts.map +1 -1
- package/dist/commands/docs/init/markdown.js +21 -2
- package/dist/commands/docs/init/resolve-options.d.ts +4 -1
- package/dist/commands/docs/init/resolve-options.d.ts.map +1 -1
- package/dist/commands/docs/init/resolve-options.js +4 -0
- package/dist/commands/docs/init/scaffold.d.ts +1 -0
- package/dist/commands/docs/init/scaffold.d.ts.map +1 -1
- package/dist/commands/docs/init/scaffold.js +57 -4
- package/dist/commands/docs/nav/contents.d.ts +4 -0
- package/dist/commands/docs/nav/contents.d.ts.map +1 -1
- package/dist/commands/docs/nav/contents.js +10 -0
- package/dist/config/documentation-check.d.ts +38 -0
- package/dist/config/documentation-check.d.ts.map +1 -0
- package/dist/config/documentation-check.js +132 -0
- package/dist/config/oat-config.d.ts +2 -0
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +4 -0
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +1 -0
- package/dist/release/public-package-contract.d.ts.map +1 -1
- package/dist/release/public-package-contract.js +13 -0
- 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
|
-
|
|
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;
|
|
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:
|
|
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":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACb,MAAM,iCAAiC,CAAC;AAGzC,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,
|
|
1
|
+
{"version":3,"file":"resolve-options.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/resolve-options.ts"],"names":[],"mappings":"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"}
|
|
@@ -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,
|
|
@@ -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;
|
|
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: '.
|
|
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: '.
|
|
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
|
-
|
|
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,
|
|
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. */
|