@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.
- package/README.md +12 -0
- package/assets/bundle-metadata.json +1 -1
- package/assets/docs/contributing/documentation.md +48 -6
- package/assets/docs/contributing/markdown-features.md +14 -2
- package/assets/docs/docs-tooling/add-docs-to-a-repo.md +22 -9
- package/assets/docs/docs-tooling/check.md +154 -0
- package/assets/docs/docs-tooling/commands.md +15 -10
- 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 +18 -10
- package/assets/docs/getting-started/tool-packs.md +5 -3
- package/assets/docs/reference/cli-reference.md +2 -0
- package/assets/docs/reference/configuration.md +1 -0
- package/assets/docs/skills/index.md +8 -8
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-docs-analyze/SKILL.md +14 -3
- package/assets/skills/oat-docs-analyze/references/legacy-scaffold-checks.md +4 -0
- 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 +92 -61
- package/assets/skills/oat-docs-bootstrap/references/pr-ci.md +89 -0
- package/assets/templates/docs-app-fuma/AGENTS.md +57 -0
- package/assets/templates/docs-app-fuma/app/[[...slug]]/page.tsx +7 -3
- package/assets/templates/docs-app-fuma/app/llms/[...slug]/route.ts +15 -0
- package/assets/templates/docs-app-fuma/app/llms-full.txt/route.ts +7 -0
- package/assets/templates/docs-app-fuma/app/llms.txt/route.ts +7 -0
- package/assets/templates/docs-app-fuma/docs/contributing/docs-toolchain.md +85 -0
- package/assets/templates/docs-app-fuma/docs/contributing/index.md +13 -0
- package/assets/templates/docs-app-fuma/docs/contributing.md +83 -41
- package/assets/templates/docs-app-fuma/docs/getting-started.md +3 -33
- package/assets/templates/docs-app-fuma/docs/index.md +3 -3
- package/assets/templates/docs-app-fuma/gitignore.template +12 -0
- package/assets/templates/docs-app-fuma/lib/source.ts +5 -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 +48 -0
- package/assets/templates/docs-app-mkdocs/docs/contributing/docs-toolchain.md +46 -0
- package/assets/templates/docs-app-mkdocs/docs/contributing/index.md +13 -0
- package/assets/templates/docs-app-mkdocs/docs/contributing.md +111 -21
- package/assets/templates/docs-app-mkdocs/docs/getting-started.md +7 -25
- package/assets/templates/docs-app-mkdocs/docs/index.md +7 -2
- package/assets/templates/docs-app-mkdocs/gitignore.template +8 -0
- package/assets/templates/docs-app-mkdocs/mkdocs.yml +1 -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/docs-commands.d.ts +1 -0
- package/dist/commands/docs/init/docs-commands.d.ts.map +1 -1
- package/dist/commands/docs/init/docs-commands.js +8 -3
- 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 +8 -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 +61 -13
- 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/commands/docs/nav/fumadocs.d.ts.map +1 -1
- package/dist/commands/docs/nav/fumadocs.js +32 -10
- 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 +3 -0
- package/package.json +11 -2
- package/assets/skills/oat-docs-bootstrap/assets/AGENTS.md.template +0 -64
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { remarkTabs } from '@open-agent-toolkit/docs-transforms';
|
|
2
|
+
import Slugger from 'github-slugger';
|
|
3
|
+
import { parseFragment } from 'parse5';
|
|
4
|
+
import remarkGfm from 'remark-gfm';
|
|
5
|
+
import remarkParse from 'remark-parse';
|
|
6
|
+
import { unified } from 'unified';
|
|
7
|
+
import YAML from 'yaml';
|
|
8
|
+
export function nodeText(node) {
|
|
9
|
+
return node.children
|
|
10
|
+
? node.children.map(nodeText).join('')
|
|
11
|
+
: (node.value ?? '');
|
|
12
|
+
}
|
|
13
|
+
export function htmlNodes(html) {
|
|
14
|
+
const nodes = [];
|
|
15
|
+
const walk = (n) => {
|
|
16
|
+
nodes.push(n);
|
|
17
|
+
n.childNodes?.forEach(walk);
|
|
18
|
+
};
|
|
19
|
+
walk(parseFragment(html, { sourceCodeLocationInfo: true }));
|
|
20
|
+
return nodes;
|
|
21
|
+
}
|
|
22
|
+
export function attributes(node) {
|
|
23
|
+
return Object.fromEntries(node.attrs?.map((a) => [a.name, a.value]) ?? []);
|
|
24
|
+
}
|
|
25
|
+
export function parsePage(path, source) {
|
|
26
|
+
let body = source;
|
|
27
|
+
let frontmatter = {};
|
|
28
|
+
let frontmatterError;
|
|
29
|
+
const match = /^(?:\uFEFF)?---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(source);
|
|
30
|
+
if (match) {
|
|
31
|
+
// Preserve physical positions for both AST and Contents diagnostics.
|
|
32
|
+
body = match[0].replace(/[^\r\n]/g, ' ') + source.slice(match[0].length);
|
|
33
|
+
try {
|
|
34
|
+
const doc = YAML.parseDocument(match[1]);
|
|
35
|
+
if (doc.errors.length)
|
|
36
|
+
frontmatterError = `Invalid YAML frontmatter: ${doc.errors[0].message}`;
|
|
37
|
+
else {
|
|
38
|
+
const data = doc.toJS();
|
|
39
|
+
if (typeof data !== 'object' || data === null || Array.isArray(data))
|
|
40
|
+
frontmatterError = 'Frontmatter must be a YAML mapping';
|
|
41
|
+
else
|
|
42
|
+
frontmatter = data;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
frontmatterError = `Invalid YAML frontmatter: ${error.message}`;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const processor = unified().use(remarkParse).use(remarkGfm).use(remarkTabs);
|
|
50
|
+
const tree = processor.runSync(processor.parse(body), {
|
|
51
|
+
value: body,
|
|
52
|
+
});
|
|
53
|
+
const nodes = [];
|
|
54
|
+
const walk = (node) => {
|
|
55
|
+
nodes.push(node);
|
|
56
|
+
node.children?.forEach(walk);
|
|
57
|
+
};
|
|
58
|
+
walk(tree);
|
|
59
|
+
const definitions = new Map();
|
|
60
|
+
for (const n of nodes)
|
|
61
|
+
if (n.type === 'definition' &&
|
|
62
|
+
n.identifier &&
|
|
63
|
+
n.url &&
|
|
64
|
+
!definitions.has(n.identifier))
|
|
65
|
+
definitions.set(n.identifier, n.url);
|
|
66
|
+
const anchors = new Set();
|
|
67
|
+
const slugger = new Slugger();
|
|
68
|
+
const links = [];
|
|
69
|
+
for (const n of nodes) {
|
|
70
|
+
const line = n.position?.start.line ?? 1;
|
|
71
|
+
if (n.type === 'heading') {
|
|
72
|
+
const text = nodeText(n);
|
|
73
|
+
const custom = /\s*(?:\[#([^\]]+)\]|\{#([^}]+)\})\s*$/.exec(text);
|
|
74
|
+
anchors.add(custom?.[1] ?? custom?.[2] ?? slugger.slug(text));
|
|
75
|
+
}
|
|
76
|
+
if (['link', 'image', 'linkReference', 'imageReference'].includes(n.type)) {
|
|
77
|
+
const href = n.url ?? definitions.get(n.identifier ?? '');
|
|
78
|
+
if (href !== undefined)
|
|
79
|
+
links.push({
|
|
80
|
+
href,
|
|
81
|
+
line,
|
|
82
|
+
image: n.type.startsWith('image'),
|
|
83
|
+
alt: n.alt,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (n.type === 'html')
|
|
87
|
+
for (const element of htmlNodes(n.value ?? '')) {
|
|
88
|
+
const a = attributes(element);
|
|
89
|
+
if (a.id)
|
|
90
|
+
anchors.add(a.id);
|
|
91
|
+
if (element.nodeName === 'a' && a.name)
|
|
92
|
+
anchors.add(a.name);
|
|
93
|
+
if (element.nodeName === 'a' && a.href)
|
|
94
|
+
links.push({
|
|
95
|
+
href: a.href,
|
|
96
|
+
image: false,
|
|
97
|
+
html: true,
|
|
98
|
+
line: line + (element.sourceCodeLocation?.startLine ?? 1) - 1,
|
|
99
|
+
});
|
|
100
|
+
if (element.nodeName === 'img' && a.src)
|
|
101
|
+
links.push({
|
|
102
|
+
href: a.src,
|
|
103
|
+
alt: a.alt,
|
|
104
|
+
image: true,
|
|
105
|
+
html: true,
|
|
106
|
+
describedBy: a['aria-describedby'],
|
|
107
|
+
line: line + (element.sourceCodeLocation?.startLine ?? 1) - 1,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
path,
|
|
113
|
+
source,
|
|
114
|
+
body,
|
|
115
|
+
frontmatter,
|
|
116
|
+
...(frontmatterError ? { frontmatterError } : {}),
|
|
117
|
+
nodes,
|
|
118
|
+
anchors,
|
|
119
|
+
links,
|
|
120
|
+
text: nodes
|
|
121
|
+
.filter((n) => n.type === 'text')
|
|
122
|
+
.map((n) => n.value ?? '')
|
|
123
|
+
.join(' '),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mermaid-runtime.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/check/mermaid-runtime.ts"],"names":[],"mappings":"AA6CA,8EAA8E;AAC9E,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAehE"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
let runtime;
|
|
2
|
+
let queue = Promise.resolve();
|
|
3
|
+
async function withDom(dom, action) {
|
|
4
|
+
const keys = ['window', 'document'];
|
|
5
|
+
const saved = keys.map((key) => Object.getOwnPropertyDescriptor(globalThis, key));
|
|
6
|
+
Object.defineProperty(globalThis, 'window', {
|
|
7
|
+
configurable: true,
|
|
8
|
+
value: dom.window,
|
|
9
|
+
});
|
|
10
|
+
Object.defineProperty(globalThis, 'document', {
|
|
11
|
+
configurable: true,
|
|
12
|
+
value: dom.window.document,
|
|
13
|
+
});
|
|
14
|
+
try {
|
|
15
|
+
return await action();
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
keys.forEach((key, index) => {
|
|
19
|
+
const descriptor = saved[index];
|
|
20
|
+
if (descriptor)
|
|
21
|
+
Object.defineProperty(globalThis, key, descriptor);
|
|
22
|
+
else
|
|
23
|
+
Reflect.deleteProperty(globalThis, key);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function loadRuntime() {
|
|
28
|
+
const { JSDOM } = await import('jsdom');
|
|
29
|
+
// Defaults intentionally disable script execution and external resources.
|
|
30
|
+
const dom = new JSDOM('');
|
|
31
|
+
try {
|
|
32
|
+
const mermaid = await withDom(dom, async () => (await import('mermaid')).default);
|
|
33
|
+
process.once('beforeExit', () => dom.window.close());
|
|
34
|
+
return { dom, mermaid };
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
dom.window.close();
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Lazy, real Node DOM for Mermaid syntax parsing only. Never renders SVG. */
|
|
42
|
+
export async function parseMermaid(source) {
|
|
43
|
+
const result = queue.then(async () => {
|
|
44
|
+
runtime ??= loadRuntime();
|
|
45
|
+
const { dom, mermaid } = await runtime;
|
|
46
|
+
await withDom(dom, async () => {
|
|
47
|
+
mermaid.initialize({
|
|
48
|
+
startOnLoad: false,
|
|
49
|
+
securityLevel: 'strict',
|
|
50
|
+
logLevel: 'fatal',
|
|
51
|
+
});
|
|
52
|
+
await mermaid.parse(source);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
queue = result.catch(() => undefined);
|
|
56
|
+
await result;
|
|
57
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/check/navigation.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAgCpD,wBAAsB,eAAe,CACnC,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAmGf"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
4
|
+
import { buildDocsNavTree } from '../../docs/nav/contents.js';
|
|
5
|
+
import { syncFumadocsNavigation } from '../../docs/nav/fumadocs.js';
|
|
6
|
+
import { syncDocsNavigation } from '../../docs/nav/sync.js';
|
|
7
|
+
import YAML from 'yaml';
|
|
8
|
+
import { present } from './files.js';
|
|
9
|
+
function pageIdentity(item) {
|
|
10
|
+
// Hand-authored collision links can use their own display labels.
|
|
11
|
+
return item.replace(/^\[[^\]]*\]\((.*)\)$/, '[]($1)').replace(/^\.\//, '');
|
|
12
|
+
}
|
|
13
|
+
function navIdentity(value, expected) {
|
|
14
|
+
if (!Array.isArray(value))
|
|
15
|
+
return value;
|
|
16
|
+
return value.map((item, index) => {
|
|
17
|
+
if (typeof item === 'string')
|
|
18
|
+
return item;
|
|
19
|
+
if (typeof item !== 'object' || item === null)
|
|
20
|
+
return item;
|
|
21
|
+
const entry = Object.entries(item)[0];
|
|
22
|
+
if (!entry)
|
|
23
|
+
return item;
|
|
24
|
+
const expectedItem = Array.isArray(expected) ? expected[index] : undefined;
|
|
25
|
+
const children = expectedItem && typeof expectedItem === 'object'
|
|
26
|
+
? Object.values(expectedItem)[0]
|
|
27
|
+
: undefined;
|
|
28
|
+
// The Contents-derived tree identifies sections by their direct landing path.
|
|
29
|
+
// Actual landing/page labels are presentation; explicit group labels remain meaningful.
|
|
30
|
+
const section = Array.isArray(children) &&
|
|
31
|
+
children.some((child) => typeof child === 'string' && child.endsWith('/index.md'));
|
|
32
|
+
return Array.isArray(entry[1])
|
|
33
|
+
? {
|
|
34
|
+
[section ? '$section' : entry[0]]: navIdentity(entry[1], children),
|
|
35
|
+
}
|
|
36
|
+
: entry[1];
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export async function checkNavigation(target, report) {
|
|
40
|
+
if (target.framework === 'markdown')
|
|
41
|
+
return;
|
|
42
|
+
try {
|
|
43
|
+
const generated = target.documentation.navOwner === 'nav-sync';
|
|
44
|
+
const nonReaderPaths = target.documentation.nonReaderPaths;
|
|
45
|
+
if (target.framework === 'fumadocs') {
|
|
46
|
+
const result = await syncFumadocsNavigation({
|
|
47
|
+
docsRoot: target.contentRoot,
|
|
48
|
+
check: true,
|
|
49
|
+
nonReaderPaths,
|
|
50
|
+
});
|
|
51
|
+
for (const file of result.metaFiles) {
|
|
52
|
+
let stale = file.changed;
|
|
53
|
+
if (!generated) {
|
|
54
|
+
if (!(await present(join(target.contentRoot, file.path))))
|
|
55
|
+
continue;
|
|
56
|
+
try {
|
|
57
|
+
const actual = JSON.parse(await readFile(join(target.contentRoot, file.path), 'utf8'));
|
|
58
|
+
if (actual &&
|
|
59
|
+
typeof actual === 'object' &&
|
|
60
|
+
!Array.isArray(actual) &&
|
|
61
|
+
!Object.hasOwn(actual, 'pages'))
|
|
62
|
+
continue;
|
|
63
|
+
stale =
|
|
64
|
+
!Array.isArray(actual.pages) ||
|
|
65
|
+
!isDeepStrictEqual(actual.pages.map((p) => typeof p === 'string' ? pageIdentity(p) : p), file.meta.pages.map(pageIdentity));
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
report('navigation', 'error', file.path, 'Cannot read or parse meta.json; check file permissions and JSON syntax.');
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (stale)
|
|
73
|
+
report('navigation', 'error', file.path, generated
|
|
74
|
+
? 'Generated navigation is stale; run oat docs nav sync.'
|
|
75
|
+
: 'Navigation membership/order differs from authored Contents; update pages or Contents.');
|
|
76
|
+
}
|
|
77
|
+
for (const path of result.unlisted)
|
|
78
|
+
report('navigation', 'error', path, 'Reader page/folder is unlisted in authored Contents and would be hidden from navigation.');
|
|
79
|
+
}
|
|
80
|
+
else if (generated) {
|
|
81
|
+
const result = await syncDocsNavigation({
|
|
82
|
+
appRoot: target.appRoot,
|
|
83
|
+
check: true,
|
|
84
|
+
nonReaderPaths,
|
|
85
|
+
});
|
|
86
|
+
for (const path of result.stale)
|
|
87
|
+
report('navigation', 'error', path, 'Generated navigation is stale; run oat docs nav sync.');
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const expected = await buildDocsNavTree({
|
|
91
|
+
docsRoot: target.contentRoot,
|
|
92
|
+
nonReaderPaths,
|
|
93
|
+
});
|
|
94
|
+
const actual = YAML.parse(await readFile(join(target.appRoot, 'mkdocs.yml'), 'utf8'));
|
|
95
|
+
if (!actual || !Object.hasOwn(actual, 'nav'))
|
|
96
|
+
return;
|
|
97
|
+
if (!isDeepStrictEqual(navIdentity(actual.nav, expected), navIdentity(expected, expected)))
|
|
98
|
+
report('navigation', 'error', 'mkdocs.yml', 'Navigation membership/order differs from authored Contents; update nav or Contents.');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
report('navigation', 'error', 'index.md', error.message);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
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 checkReaders(target: CheckTarget, pages: ParsedPage[], report: Report): Promise<void>;
|
|
5
|
+
export declare function checkProvenance(target: CheckTarget, pages: ParsedPage[], report: Report): void;
|
|
6
|
+
//# sourceMappingURL=reader-rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader-rules.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/check/reader-rules.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAML,KAAK,WAAW,EACjB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAEvD,wBAAsB,YAAY,CAChC,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,UAAU,EAAE,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAuVf;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,UAAU,EAAE,EACnB,MAAM,EAAE,MAAM,GACb,IAAI,CA+CN"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { dirname, extname, join, resolve } from 'node:path';
|
|
2
|
+
import { parseIndexContents, resolveEntryTarget, } from '../../docs/nav/contents.js';
|
|
3
|
+
import { isExcludedPath } from '../../docs/shared/exclusions.js';
|
|
4
|
+
import { DOCS_CHECK_THRESHOLDS } from '../../../config/documentation-check.js';
|
|
5
|
+
import { containedFile, inside, posix, present, readerDirectories, } from './files.js';
|
|
6
|
+
import { nodeText } from './markdown.js';
|
|
7
|
+
export async function checkReaders(target, pages, report) {
|
|
8
|
+
const t = {
|
|
9
|
+
...DOCS_CHECK_THRESHOLDS,
|
|
10
|
+
...target.documentation.check?.thresholds,
|
|
11
|
+
};
|
|
12
|
+
const byPath = new Map(pages.map((p) => [p.path, p]));
|
|
13
|
+
const dirs = readerDirectories(pages.map((p) => p.path));
|
|
14
|
+
const separators = new Map();
|
|
15
|
+
for (const dir of dirs) {
|
|
16
|
+
const path = posix(join(dir, 'index.md'));
|
|
17
|
+
const page = byPath.get(path);
|
|
18
|
+
let grouped = false;
|
|
19
|
+
if (!page)
|
|
20
|
+
report('directory-index', 'error', path, 'Reader-bearing directory needs index.md with a nonempty ## Contents map.');
|
|
21
|
+
else {
|
|
22
|
+
try {
|
|
23
|
+
const entries = parseIndexContents(page.body, path, {
|
|
24
|
+
locations: true,
|
|
25
|
+
});
|
|
26
|
+
const retained = [];
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
const lexical = resolve(target.contentRoot, dir, entry.href.split('#')[0] ?? '');
|
|
29
|
+
if (inside(target.contentRoot, lexical) &&
|
|
30
|
+
isExcludedPath(target.matcher, posix(lexical.slice(target.contentRoot.length + 1))))
|
|
31
|
+
continue;
|
|
32
|
+
retained.push(entry);
|
|
33
|
+
if (entry.description && /(?:\.\.\.|…)\s*$/.test(entry.description))
|
|
34
|
+
report('contents-description', 'error', path, 'Contents description is truncated; finish the sentence.', entry.line);
|
|
35
|
+
if (entry.separator)
|
|
36
|
+
separators.set(entry.separator, { path, line: entry.line });
|
|
37
|
+
try {
|
|
38
|
+
// Existing strict Contents resolution owns local map semantics.
|
|
39
|
+
await resolveEntryTarget(target.contentRoot, join(target.contentRoot, dir), dir, entry, ['.md', '.mdx'], target.matcher);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
report('directory-index', 'error', path, String(error.message), entry.line);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
grouped = retained.some((e) => e.group !== undefined);
|
|
46
|
+
if (dir === '.' && !grouped) {
|
|
47
|
+
if (retained.length > t.rootError)
|
|
48
|
+
report('root-width', 'error', path, `Flat root has ${retained.length} Contents links; maximum ${t.rootError}.`);
|
|
49
|
+
else if (retained.length > t.rootWarn)
|
|
50
|
+
report('root-width', 'warn', path, `Flat root has ${retained.length} Contents links; group above ${t.rootWarn}.`);
|
|
51
|
+
}
|
|
52
|
+
const catalog = page.frontmatter.catalog === true ||
|
|
53
|
+
page.source.includes('<!-- AUTOGENERATED by `oat docs generate-index`.');
|
|
54
|
+
if (!grouped && !catalog) {
|
|
55
|
+
if (retained.length > t.contentsError)
|
|
56
|
+
report('contents-width', 'error', path, `Ungrouped Contents has ${retained.length} links; maximum ${t.contentsError}.`);
|
|
57
|
+
else if (retained.length > t.contentsWarn)
|
|
58
|
+
report('contents-width', 'warn', path, `Ungrouped Contents has ${retained.length} links; group above ${t.contentsWarn}.`);
|
|
59
|
+
}
|
|
60
|
+
const contentsHeading = page.nodes.find((n) => n.type === 'heading' &&
|
|
61
|
+
n.depth === 2 &&
|
|
62
|
+
nodeText(n).trim() === 'Contents');
|
|
63
|
+
const words = page.nodes
|
|
64
|
+
.filter((n) => n.type === 'paragraph' &&
|
|
65
|
+
(n.position?.end.line ?? Infinity) <
|
|
66
|
+
(contentsHeading?.position?.start.line ?? 0))
|
|
67
|
+
.map(nodeText)
|
|
68
|
+
.join(' ')
|
|
69
|
+
.trim()
|
|
70
|
+
.split(/\s+/)
|
|
71
|
+
.filter(Boolean).length;
|
|
72
|
+
if (words < t.overviewWords)
|
|
73
|
+
report('overview', 'warn', path, `Overview has ${words} words; use at least ${t.overviewWords} before Contents.`);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
report('directory-index', 'error', path, error.message);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const count = pages.filter((p) => dirname(p.path) === dir).length;
|
|
80
|
+
const child = dirs.some((d) => d !== dir && (dir === '.' || d.startsWith(`${dir}/`)));
|
|
81
|
+
if (!child) {
|
|
82
|
+
if (count === 1 && page)
|
|
83
|
+
report('leaf-size', 'error', path, 'Index-only leaf has no reader destination; flatten it or add its reader pages.');
|
|
84
|
+
else if (count === 2)
|
|
85
|
+
report('leaf-size', 'warn', path, 'Leaf has only two direct reader pages including index.md; consider flattening.');
|
|
86
|
+
}
|
|
87
|
+
if (!grouped) {
|
|
88
|
+
if (count > t.folderError)
|
|
89
|
+
report('folder-size', 'error', path, `Folder has ${count} direct reader pages including index; maximum ${t.folderError} without groups.`);
|
|
90
|
+
else if (count > t.folderWarn)
|
|
91
|
+
report('folder-size', 'warn', path, `Folder has ${count} direct reader pages including index; group above ${t.folderWarn}.`);
|
|
92
|
+
}
|
|
93
|
+
const depth = dir === '.' ? 0 : dir.split('/').length;
|
|
94
|
+
if (depth >= t.depthError)
|
|
95
|
+
report('depth', 'error', path, `Directory depth ${depth}; error at ${t.depthError} (content root is 0).`);
|
|
96
|
+
else if (depth >= t.depthWarn)
|
|
97
|
+
report('depth', 'warn', path, `Directory depth ${depth}; warning at ${t.depthWarn} (content root is 0).`);
|
|
98
|
+
}
|
|
99
|
+
if (separators.size > 1)
|
|
100
|
+
for (const { path, line } of separators.values())
|
|
101
|
+
report('contents-separator', 'warn', path, `Contents separators differ within this tree (${[...separators.keys()].sort().join(', ')}).`, line);
|
|
102
|
+
for (const p of pages) {
|
|
103
|
+
if (!p.frontmatterError) {
|
|
104
|
+
const desc = p.frontmatter.description;
|
|
105
|
+
if (typeof desc !== 'string' || !desc.trim())
|
|
106
|
+
report('description', 'error', p.path, 'Frontmatter description is required and must be nonempty.', 1);
|
|
107
|
+
else if (desc.trim().length < t.descriptionMin ||
|
|
108
|
+
desc.trim().length > t.descriptionMax)
|
|
109
|
+
report('description', 'warn', p.path, `Description has ${desc.trim().length} characters; expected ${t.descriptionMin}–${t.descriptionMax}.`, 1);
|
|
110
|
+
}
|
|
111
|
+
const h1 = p.nodes.filter((n) => n.type === 'heading' && n.depth === 1);
|
|
112
|
+
if (h1.length !== 1)
|
|
113
|
+
report('h1', 'error', p.path, `Expected one real H1; found ${h1.length}.`, h1[1]?.position?.start.line ?? 1);
|
|
114
|
+
const reference = p.frontmatter.type === 'reference' ||
|
|
115
|
+
/(?:^|\/)references?(?:\/|$)/.test(p.path);
|
|
116
|
+
const lines = p.source.split(/\r?\n/).length - (p.source.endsWith('\n') ? 1 : 0);
|
|
117
|
+
const limit = reference ? t.referenceLines : t.pageLines;
|
|
118
|
+
if (lines > limit)
|
|
119
|
+
report('page-length', 'warn', p.path, `Page has ${lines} physical source lines; limit ${limit}${reference ? ' for reference pages' : ''}.`);
|
|
120
|
+
const h3 = p.nodes.filter((n) => n.type === 'heading' && n.depth === 3).length;
|
|
121
|
+
if (reference && h3 > t.referenceH3)
|
|
122
|
+
report('page-length', 'warn', p.path, `Reference page has ${h3} real H3 headings; limit ${t.referenceH3}.`);
|
|
123
|
+
for (const link of p.links) {
|
|
124
|
+
const href = link.href;
|
|
125
|
+
if (/^(?:[a-z][a-z\d+.-]*:|\/\/)/i.test(href))
|
|
126
|
+
continue;
|
|
127
|
+
let pathname;
|
|
128
|
+
let anchor;
|
|
129
|
+
try {
|
|
130
|
+
const hash = href.indexOf('#');
|
|
131
|
+
pathname = decodeURIComponent((hash < 0 ? href : href.slice(0, hash)).split('?')[0]);
|
|
132
|
+
anchor = hash < 0 ? '' : decodeURIComponent(href.slice(hash + 1));
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
report('links', 'error', p.path, `Malformed percent encoding in link "${href}".`, link.line);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (!pathname) {
|
|
139
|
+
if (anchor && !p.anchors.has(anchor))
|
|
140
|
+
report('links', 'error', p.path, `Unresolved anchor "${href}".`, link.line);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (pathname.startsWith('~/'))
|
|
144
|
+
continue; // provenance reports it, never read home paths
|
|
145
|
+
const file = pathname.startsWith('/')
|
|
146
|
+
? resolve(target.contentRoot, `.${pathname}`)
|
|
147
|
+
: resolve(target.contentRoot, dirname(p.path), pathname);
|
|
148
|
+
if (!inside(target.contentRoot, file))
|
|
149
|
+
continue; // provenance warns without outside IO
|
|
150
|
+
const relativePath = posix(file.slice(target.contentRoot.length + 1));
|
|
151
|
+
if (isExcludedPath(target.matcher, relativePath))
|
|
152
|
+
continue;
|
|
153
|
+
let resolved = file;
|
|
154
|
+
let isFile = await containedFile(target.contentRoot, file);
|
|
155
|
+
if (!isFile && !extname(pathname)) {
|
|
156
|
+
for (const suffix of ['.md', '.mdx', '/index.md'])
|
|
157
|
+
if (await containedFile(target.contentRoot, file + suffix)) {
|
|
158
|
+
resolved = file + suffix;
|
|
159
|
+
isFile = true;
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Framework public assets have a separate explicit allowed root. Rendered
|
|
164
|
+
// absolute routes are validated only when they identify a reader file.
|
|
165
|
+
if (!isFile && pathname.startsWith('/') && link.image) {
|
|
166
|
+
const publicRoot = join(target.appRoot, 'public');
|
|
167
|
+
isFile =
|
|
168
|
+
(await present(publicRoot)) &&
|
|
169
|
+
(await containedFile(publicRoot, resolve(publicRoot, `.${pathname}`)));
|
|
170
|
+
}
|
|
171
|
+
if (!isFile &&
|
|
172
|
+
pathname.startsWith('/') &&
|
|
173
|
+
!link.image &&
|
|
174
|
+
!/\.mdx?$/.test(pathname))
|
|
175
|
+
continue;
|
|
176
|
+
if (!isFile)
|
|
177
|
+
report('links', 'error', p.path, `Unresolved in-root link "${href}".`, link.line);
|
|
178
|
+
else if (anchor && /\.mdx?$/.test(resolved)) {
|
|
179
|
+
const destination = byPath.get(posix(resolved.slice(target.contentRoot.length + 1)));
|
|
180
|
+
if (destination && !destination.anchors.has(anchor))
|
|
181
|
+
report('links', 'error', p.path, `Unresolved anchor "${href}".`, link.line);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
export function checkProvenance(target, pages, report) {
|
|
187
|
+
const patterns = [
|
|
188
|
+
/\.oat\//u,
|
|
189
|
+
/\b[Bb][Ll]-[\w-]+/u,
|
|
190
|
+
/(?:~\/|\/Users\/|\/home\/)/u,
|
|
191
|
+
...(target.documentation.check?.provenance?.ticketPatterns ?? []).map((p) => new RegExp(p, 'u')),
|
|
192
|
+
...(target.documentation.check?.provenance?.milestonePatterns ?? []).map((p) => new RegExp(p, 'u')),
|
|
193
|
+
];
|
|
194
|
+
for (const p of pages) {
|
|
195
|
+
p.source.split(/\r?\n/).forEach((text, line) => {
|
|
196
|
+
if (patterns.some((pattern) => pattern.test(text)))
|
|
197
|
+
report('provenance', 'warn', p.path, 'Reader page contains a planning/backlog/home path or configured ticket/milestone pattern; remove it or record a reason-bearing decision-pointer exception.', line + 1);
|
|
198
|
+
});
|
|
199
|
+
for (const link of p.links) {
|
|
200
|
+
if (/^(?:[a-z][a-z\d+.-]*:|\/)/i.test(link.href))
|
|
201
|
+
continue;
|
|
202
|
+
const href = link.href.split(/[?#]/)[0];
|
|
203
|
+
let decoded;
|
|
204
|
+
try {
|
|
205
|
+
decoded = decodeURIComponent(href);
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (!inside(target.contentRoot, resolve(target.contentRoot, dirname(p.path), decoded)))
|
|
211
|
+
report('provenance', 'warn', p.path, `Link "${link.href}" escapes the docs root; target was not read.`, link.line);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/docs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/docs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,iBAAiB,IAAI,OAAO,CAU3C"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { createDocsAnalyzeCommand } from './analyze.js';
|
|
3
3
|
import { createDocsApplyCommand } from './apply.js';
|
|
4
|
+
import { createDocsCheckCommand } from './check/check.js';
|
|
4
5
|
import { createDocsGenerateIndexCommand } from './index-generate/index.js';
|
|
5
6
|
import { createDocsInitCommand } from './init/index.js';
|
|
6
7
|
import { createDocsMigrateCommand } from './migrate/index.js';
|
|
@@ -8,6 +9,7 @@ import { createDocsNavCommand } from './nav/index.js';
|
|
|
8
9
|
export function createDocsCommand() {
|
|
9
10
|
return new Command('docs')
|
|
10
11
|
.description('OAT documentation bootstrap and maintenance commands')
|
|
12
|
+
.addCommand(createDocsCheckCommand())
|
|
11
13
|
.addCommand(createDocsAnalyzeCommand())
|
|
12
14
|
.addCommand(createDocsApplyCommand())
|
|
13
15
|
.addCommand(createDocsGenerateIndexCommand())
|
|
@@ -4,5 +4,6 @@ export interface DocsCommands {
|
|
|
4
4
|
dev: string;
|
|
5
5
|
build: string;
|
|
6
6
|
}
|
|
7
|
+
export declare function shellQuote(value: string): string;
|
|
7
8
|
export declare function buildDocsCommands(repoShape: DocsRepoShape, targetDir: string, appName: string): DocsCommands;
|
|
8
9
|
//# sourceMappingURL=docs-commands.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docs-commands.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/docs-commands.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAMD,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,YAAY,CAsBd"}
|
|
1
|
+
{"version":3,"file":"docs-commands.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/docs-commands.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhD;AAMD,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,YAAY,CAsBd"}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { normalize } from 'node:path';
|
|
2
|
+
export function shellQuote(value) {
|
|
3
|
+
return /^[a-zA-Z0-9_./-]+$/.test(value)
|
|
4
|
+
? value
|
|
5
|
+
: `'${value.replaceAll("'", "'\\''")}'`;
|
|
6
|
+
}
|
|
2
7
|
function isRootTarget(targetDir) {
|
|
3
8
|
return targetDir.trim() === '' || normalize(targetDir) === '.';
|
|
4
9
|
}
|
|
@@ -18,8 +23,8 @@ export function buildDocsCommands(repoShape, targetDir, appName) {
|
|
|
18
23
|
};
|
|
19
24
|
}
|
|
20
25
|
return {
|
|
21
|
-
install: `cd ${targetDir} && pnpm install`,
|
|
22
|
-
dev: `cd ${targetDir} && pnpm dev`,
|
|
23
|
-
build: `cd ${targetDir} && pnpm build`,
|
|
26
|
+
install: `cd ${shellQuote(targetDir)} && pnpm install`,
|
|
27
|
+
dev: `cd ${shellQuote(targetDir)} && pnpm dev`,
|
|
28
|
+
build: `cd ${shellQuote(targetDir)} && pnpm build`,
|
|
24
29
|
};
|
|
25
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,KAAK,mBAAmB,EAGxB,sBAAsB,EAEvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,YAAY,EAElB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAU5C,OAAO,EAIL,KAAK,uBAAuB,EAK7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,gBAAgB,CAAC;AAgBxB,UAAU,uBAAuB;IAC/B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,YAAY,CAAC,EACT,SAAS,GACT,SAAS,GACT,WAAW,GACX,QAAQ,GACR,eAAe,CAAC;IACpB,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,UAAU,GAAG,QAAQ,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D;AAED,UAAU,oBAAoB;IAC5B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,gBAAgB,CAAC,CAAC;IAC9E,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;IACvB,WAAW,EAAE,CACX,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,uBAAuB,EAChC,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAAC;IAC7C,qBAAqB,EAAE,CACrB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAClC,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -176,11 +176,16 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
176
176
|
context.logger.info(` Format: ${options.format}`);
|
|
177
177
|
if (rootPackagePatch)
|
|
178
178
|
logRootPackagePatch(context, rootPackagePatch);
|
|
179
|
+
for (const advice of result.installationAdvice ?? [])
|
|
180
|
+
context.logger.info(advice);
|
|
179
181
|
}
|
|
180
182
|
return {
|
|
181
183
|
createdFiles: result.createdFiles,
|
|
182
184
|
appRoot: result.appRoot,
|
|
183
185
|
rootPackagePatch,
|
|
186
|
+
...(result.installationAdvice
|
|
187
|
+
? { installationAdvice: result.installationAdvice }
|
|
188
|
+
: {}),
|
|
184
189
|
};
|
|
185
190
|
},
|
|
186
191
|
upsertAgentsMdSection,
|
|
@@ -384,6 +389,9 @@ async function runDocsInitCommand(context, options, dependencies) {
|
|
|
384
389
|
framework: resolved.framework,
|
|
385
390
|
},
|
|
386
391
|
guidance: sectionResult,
|
|
392
|
+
...(scaffold?.installationAdvice
|
|
393
|
+
? { installationAdvice: scaffold.installationAdvice }
|
|
394
|
+
: {}),
|
|
387
395
|
});
|
|
388
396
|
}
|
|
389
397
|
else {
|