@open-agent-toolkit/cli 0.3.24 → 0.3.26
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/assets/bundle-metadata.json +1 -1
- package/assets/docs/docs-tooling/add-docs-to-a-repo.md +14 -6
- package/assets/docs/docs-tooling/commands.md +12 -9
- package/assets/docs/docs-tooling/workflows.md +53 -8
- package/assets/docs/reference/cli-reference.md +1 -1
- package/assets/docs/reference/configuration.md +3 -0
- package/assets/docs/reference/docs-index-contract.md +19 -6
- package/assets/docs/reference/oat-directory-structure.md +13 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-docs-analyze/SKILL.md +106 -6
- package/assets/skills/oat-docs-analyze/references/analysis-artifact-template.md +42 -2
- package/assets/skills/oat-docs-analyze/scripts/package-drift.mjs +129 -0
- package/assets/skills/oat-docs-apply/SKILL.md +131 -12
- package/assets/skills/oat-docs-apply/references/apply-plan-template.md +58 -14
- package/assets/skills/oat-docs-bootstrap/SKILL.md +33 -8
- package/assets/templates/docs-app-fuma/package.json.template +1 -1
- package/assets/templates/docs-app-fuma/source.config.ts +6 -1
- package/assets/templates/docs-app-mkdocs/package.json.template +2 -2
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +67 -9
- package/dist/commands/docs/index-generate/generator.d.ts +4 -34
- package/dist/commands/docs/index-generate/generator.d.ts.map +1 -1
- package/dist/commands/docs/index-generate/generator.js +51 -157
- package/dist/commands/docs/index-generate/index.d.ts +1 -1
- package/dist/commands/docs/index-generate/index.d.ts.map +1 -1
- package/dist/commands/docs/index-generate/index.js +26 -8
- package/dist/commands/docs/init/index.d.ts.map +1 -1
- package/dist/commands/docs/init/index.js +21 -1
- package/dist/commands/docs/init/scaffold.d.ts.map +1 -1
- package/dist/commands/docs/init/scaffold.js +20 -13
- package/dist/commands/docs/nav/contents.d.ts +13 -3
- package/dist/commands/docs/nav/contents.d.ts.map +1 -1
- package/dist/commands/docs/nav/contents.js +85 -24
- package/dist/commands/docs/nav/fumadocs.d.ts +1 -0
- package/dist/commands/docs/nav/fumadocs.d.ts.map +1 -1
- package/dist/commands/docs/nav/fumadocs.js +26 -9
- package/dist/commands/docs/nav/sync.d.ts +2 -0
- package/dist/commands/docs/nav/sync.d.ts.map +1 -1
- package/dist/commands/docs/nav/sync.js +21 -1
- package/dist/commands/docs/shared/exclusions.d.ts +37 -0
- package/dist/commands/docs/shared/exclusions.d.ts.map +1 -0
- package/dist/commands/docs/shared/exclusions.js +161 -0
- package/dist/config/oat-config.d.ts +18 -0
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +64 -3
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +5 -1
- package/package.json +2 -2
|
@@ -12,7 +12,7 @@ import { normalizeDispatchMatrix, validateDispatchRouteTarget, walkDispatchMatri
|
|
|
12
12
|
import { formatDispatchNotices, terminalReviewerNoticesForMatrix, } from '../../config/dispatch-notices.js';
|
|
13
13
|
import { dispatchPolicyModeDescription, dispatchPolicyPolicyDescription, managedDispatchPolicyValueList, } from '../../config/dispatch-policy-options.js';
|
|
14
14
|
import { parseJsonConfig } from '../../config/json.js';
|
|
15
|
-
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, readOatConfig, readOatConfigForDefaultScopeRepair, readOatConfigForDocumentationExcludesRepair, readOatConfigForInstructionPointerExcludesRepair, readOatConfigForInstructionSyncStrategyRepair, readOatConfigWithWarnings, readOatLocalConfig, readUserConfig, writeOatConfig, writeOatLocalConfig, writeUserConfig, VALID_POST_IMPLEMENT_LEGACY_SEQUENCES, } from '../../config/oat-config.js';
|
|
15
|
+
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
16
|
import { getOwnKey, setOwnKey } from '../../config/own-keys.js';
|
|
17
17
|
import { resolveEffectiveConfig, resolveEnvOverride, } from '../../config/resolve.js';
|
|
18
18
|
import { resolveAssetsRoot } from '../../fs/assets.js';
|
|
@@ -67,6 +67,9 @@ const KEY_ORDER = [
|
|
|
67
67
|
'archive.awsRegion',
|
|
68
68
|
'autoReviewAtCheckpoints',
|
|
69
69
|
'lastPausedProject',
|
|
70
|
+
'documentation.ia',
|
|
71
|
+
'documentation.nonReaderPaths',
|
|
72
|
+
'documentation.navOwner',
|
|
70
73
|
'documentation.guidance',
|
|
71
74
|
'documentation.root',
|
|
72
75
|
'documentation.tooling',
|
|
@@ -239,6 +242,28 @@ const CONFIG_CATALOG = [
|
|
|
239
242
|
description: 'Deprecated compatibility alias for workflow.autoReviewAtHillCheckpoints. Prefer `oat config set workflow.autoReviewAtHillCheckpoints <true|false>`.',
|
|
240
243
|
deprecated: { supersededBy: 'workflow.autoReviewAtHillCheckpoints' },
|
|
241
244
|
},
|
|
245
|
+
{
|
|
246
|
+
key: 'documentation.ia',
|
|
247
|
+
group: 'Shared Repo (.oat/config.json)',
|
|
248
|
+
scope: 'shared repo',
|
|
249
|
+
file: '.oat/config.json',
|
|
250
|
+
type: 'JSON object',
|
|
251
|
+
defaultValue: 'null (no recorded IA)',
|
|
252
|
+
mutability: 'read/write',
|
|
253
|
+
owningCommand: 'oat config set documentation.ia <JSON>',
|
|
254
|
+
description: 'Repository mirror of authored IA: preset, repo-relative decision, optional tracks [{path, principle}] and verification (triad|agent-only|none). Authored records remain authoritative.',
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
key: 'documentation.navOwner',
|
|
258
|
+
group: 'Shared Repo (.oat/config.json)',
|
|
259
|
+
scope: 'shared repo',
|
|
260
|
+
file: '.oat/config.json',
|
|
261
|
+
type: 'nav-sync | hand-authored',
|
|
262
|
+
defaultValue: 'null (undeclared)',
|
|
263
|
+
mutability: 'read/write',
|
|
264
|
+
owningCommand: 'oat config set documentation.navOwner <value>',
|
|
265
|
+
description: 'Sidebar owner for framework docs only. Unset is undeclared and authorizes no automatic navigation generation. Markdown ignores this key.',
|
|
266
|
+
},
|
|
242
267
|
{
|
|
243
268
|
key: 'documentation.guidance',
|
|
244
269
|
group: 'Documentation Guidance (shared > user)',
|
|
@@ -283,6 +308,17 @@ const CONFIG_CATALOG = [
|
|
|
283
308
|
owningCommand: 'oat config set documentation.config <value>',
|
|
284
309
|
description: 'Repository-relative path to the primary documentation tool config file.',
|
|
285
310
|
},
|
|
311
|
+
{
|
|
312
|
+
key: 'documentation.nonReaderPaths',
|
|
313
|
+
group: 'Shared Repo (.oat/config.json)',
|
|
314
|
+
file: '.oat/config.json',
|
|
315
|
+
scope: 'shared repo',
|
|
316
|
+
type: 'string[]',
|
|
317
|
+
defaultValue: 'unset',
|
|
318
|
+
mutability: 'read/write',
|
|
319
|
+
owningCommand: 'oat config set documentation.nonReaderPaths <glob[,glob...]>',
|
|
320
|
+
description: 'Content-root-relative globs excluded from reader navigation, manifest and supported framework rendering. Empty clears the key.',
|
|
321
|
+
},
|
|
286
322
|
{
|
|
287
323
|
key: 'documentation.excludes',
|
|
288
324
|
group: 'Shared Repo (.oat/config.json)',
|
|
@@ -1784,17 +1820,36 @@ async function listConfigKeys(repoRoot, userConfigDir, dependencies) {
|
|
|
1784
1820
|
async function setConfigValue(repoRoot, userConfigDir, key, rawValue, surface, dependencies, warn) {
|
|
1785
1821
|
validateSurfaceForKey(key, surface);
|
|
1786
1822
|
const effectiveSurface = surface === 'auto' ? defaultSurfaceForKey(key) : surface;
|
|
1787
|
-
if (key === 'documentation.
|
|
1823
|
+
if (key === 'documentation.nonReaderPaths' ||
|
|
1824
|
+
key === 'documentation.guidance' ||
|
|
1825
|
+
key === 'documentation.ia' ||
|
|
1826
|
+
key === 'documentation.navOwner') {
|
|
1788
1827
|
const configPath = effectiveSurface === 'user'
|
|
1789
1828
|
? join(userConfigDir, 'config.json')
|
|
1790
1829
|
: join(repoRoot, '.oat', 'config.json');
|
|
1830
|
+
const field = key.slice('documentation.'.length);
|
|
1791
1831
|
const trimmed = rawValue.trim();
|
|
1792
|
-
let
|
|
1832
|
+
let value;
|
|
1793
1833
|
try {
|
|
1794
|
-
|
|
1834
|
+
if (key === 'documentation.nonReaderPaths') {
|
|
1835
|
+
const paths = parseDocumentationExcludes(rawValue);
|
|
1836
|
+
value = paths.length > 0 ? paths : undefined;
|
|
1837
|
+
}
|
|
1838
|
+
else if (key === 'documentation.ia') {
|
|
1839
|
+
const parsed = JSON.parse(trimmed);
|
|
1840
|
+
if (parsed === null)
|
|
1841
|
+
throw new Error('Expected an IA JSON object.');
|
|
1842
|
+
value = normalizeDocumentationIa(parsed, configPath);
|
|
1843
|
+
}
|
|
1844
|
+
else {
|
|
1845
|
+
value =
|
|
1846
|
+
key === 'documentation.navOwner'
|
|
1847
|
+
? normalizeDocumentationNavOwner(trimmed, configPath)
|
|
1848
|
+
: normalizeDocumentationGuidance(trimmed.startsWith('[') ? JSON.parse(trimmed) : trimmed, configPath, effectiveSurface === 'user' ? 'user' : 'shared');
|
|
1849
|
+
}
|
|
1795
1850
|
}
|
|
1796
1851
|
catch {
|
|
1797
|
-
throw new Error(
|
|
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'}.`);
|
|
1798
1853
|
}
|
|
1799
1854
|
let raw = { version: 1 };
|
|
1800
1855
|
try {
|
|
@@ -1818,18 +1873,18 @@ async function setConfigValue(repoRoot, userConfigDir, key, rawValue, surface, d
|
|
|
1818
1873
|
throw new Error(`Expected a documentation object in ${configPath}`);
|
|
1819
1874
|
}
|
|
1820
1875
|
// Patch only the declared input; do not normalize away unrelated or future fields.
|
|
1821
|
-
if (!isDeepStrictEqual(documentation?.
|
|
1876
|
+
if (!isDeepStrictEqual(documentation?.[field], value)) {
|
|
1822
1877
|
await dependencies.atomicWriteJson(configPath, {
|
|
1823
1878
|
...raw,
|
|
1824
1879
|
documentation: {
|
|
1825
1880
|
...documentation,
|
|
1826
|
-
|
|
1881
|
+
[field]: value,
|
|
1827
1882
|
},
|
|
1828
1883
|
});
|
|
1829
1884
|
}
|
|
1830
1885
|
return {
|
|
1831
1886
|
key,
|
|
1832
|
-
value:
|
|
1887
|
+
value: value ?? null,
|
|
1833
1888
|
source: effectiveSurface,
|
|
1834
1889
|
};
|
|
1835
1890
|
}
|
|
@@ -2393,7 +2448,10 @@ async function unsetConfigValue(repoRoot, userConfigDir, key, surface, dependenc
|
|
|
2393
2448
|
* runs only when the normalized pass found nothing to remove.
|
|
2394
2449
|
*/
|
|
2395
2450
|
async function removeFromSurface(repoRoot, userConfigDir, key, effectiveSurface, path, dependencies) {
|
|
2396
|
-
if (key === 'documentation.
|
|
2451
|
+
if (key === 'documentation.nonReaderPaths' ||
|
|
2452
|
+
key === 'documentation.guidance' ||
|
|
2453
|
+
key === 'documentation.ia' ||
|
|
2454
|
+
key === 'documentation.navOwner') {
|
|
2397
2455
|
const configPath = effectiveSurface === 'user'
|
|
2398
2456
|
? join(userConfigDir, 'config.json')
|
|
2399
2457
|
: join(repoRoot, '.oat', 'config.json');
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
export { createExclusionMatcher } from '../../docs/shared/exclusions.js';
|
|
2
|
+
export type { ExclusionMatcher } from '../../docs/shared/exclusions.js';
|
|
1
3
|
export interface IndexEntry {
|
|
2
4
|
title: string;
|
|
3
5
|
description?: string;
|
|
4
6
|
path: string;
|
|
5
7
|
children?: IndexEntry[];
|
|
8
|
+
/** Present Contents did not list this direct reader entry. */
|
|
9
|
+
unlisted?: boolean;
|
|
6
10
|
}
|
|
7
11
|
export interface GenerateIndexOptions {
|
|
8
12
|
/**
|
|
@@ -12,40 +16,6 @@ export interface GenerateIndexOptions {
|
|
|
12
16
|
*/
|
|
13
17
|
excludes?: string[];
|
|
14
18
|
}
|
|
15
|
-
/**
|
|
16
|
-
* A compiled exclusion list.
|
|
17
|
-
*
|
|
18
|
-
* Files and directories are asked separately so a trailing-slash pattern can
|
|
19
|
-
* mean "directories only" while every other pattern applies to both.
|
|
20
|
-
*/
|
|
21
|
-
export interface ExclusionMatcher {
|
|
22
|
-
excludesFile: (relativePath: string) => boolean;
|
|
23
|
-
excludesDirectory: (relativePath: string) => boolean;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Compile exclusion globs matched against **docs-root-relative POSIX paths**
|
|
27
|
-
* (`api/auth.md`, `api/nested`), never against absolute or CWD-relative ones.
|
|
28
|
-
*
|
|
29
|
-
* Grammar, defined once and documented in
|
|
30
|
-
* `apps/oat-docs/docs/reference/oat-directory-structure.md`:
|
|
31
|
-
*
|
|
32
|
-
* - `*` matches any run of characters inside a single path segment.
|
|
33
|
-
* - `**` spans `/` only as a whole segment, where it covers zero or more
|
|
34
|
-
* segments: `**\/CLAUDE.md` matches `CLAUDE.md` and `api/CLAUDE.md`. Inside a
|
|
35
|
-
* segment (`a**b`) it is an ordinary single-segment wildcard.
|
|
36
|
-
* - Patterns are anchored at both ends against the whole relative path, so a
|
|
37
|
-
* bare `CLAUDE.md` matches only the root-level file. Use `**\/CLAUDE.md` for
|
|
38
|
-
* every depth.
|
|
39
|
-
* - A trailing `/` restricts a pattern to directories: `drafts/` prunes the
|
|
40
|
-
* `drafts` directory and everything beneath it, and never matches a file.
|
|
41
|
-
* Without it, a pattern that matches a directory path prunes it too.
|
|
42
|
-
* - Matching is case-sensitive, `/` is the separator on every platform, and
|
|
43
|
-
* `*` is the only metacharacter — `.`, `+`, and friends are literal.
|
|
44
|
-
*
|
|
45
|
-
* Entries are trimmed; a leading `./` or `/` is stripped so both spellings
|
|
46
|
-
* anchor at the docs root. Blank entries are ignored.
|
|
47
|
-
*/
|
|
48
|
-
export declare function createExclusionMatcher(patterns: readonly string[]): ExclusionMatcher;
|
|
49
19
|
export declare function generateIndex(docsDir: string, options?: GenerateIndexOptions): Promise<IndexEntry[]>;
|
|
50
20
|
export declare function renderIndex(entries: IndexEntry[]): string;
|
|
51
21
|
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/index-generate/generator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/index-generate/generator.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,YAAY,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzE,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC;IACxB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAgLD,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,UAAU,EAAE,CAAC,CAMvB;AAuBD,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAMzD"}
|
|
@@ -1,155 +1,9 @@
|
|
|
1
1
|
import { readdir, readFile } from 'node:fs/promises';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* Match one path segment against one pattern segment, where `*` is the only
|
|
9
|
-
* metacharacter and never crosses `/`.
|
|
10
|
-
*
|
|
11
|
-
* This is the classic greedy two-pointer wildcard match, deliberately not a
|
|
12
|
-
* compiled regular expression: a pattern like `*a*a*a...` translates to
|
|
13
|
-
* nested-quantifier alternatives that backtrack exponentially, and exclusion
|
|
14
|
-
* patterns come from config and flags where a typo should not hang generation.
|
|
15
|
-
* Restarting from the last `*` instead bounds the work at O(pattern x text).
|
|
16
|
-
*/
|
|
17
|
-
function matchSegment(pattern, text) {
|
|
18
|
-
let patternIndex = 0;
|
|
19
|
-
let textIndex = 0;
|
|
20
|
-
let starPatternIndex = -1;
|
|
21
|
-
let starTextIndex = 0;
|
|
22
|
-
while (textIndex < text.length) {
|
|
23
|
-
if (pattern[patternIndex] === '*') {
|
|
24
|
-
// Collapse a run of stars: within a segment they are all equivalent.
|
|
25
|
-
while (pattern[patternIndex] === '*') {
|
|
26
|
-
patternIndex += 1;
|
|
27
|
-
}
|
|
28
|
-
if (patternIndex === pattern.length) {
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
starPatternIndex = patternIndex;
|
|
32
|
-
starTextIndex = textIndex;
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
if (patternIndex < pattern.length &&
|
|
36
|
-
pattern[patternIndex] === text[textIndex]) {
|
|
37
|
-
patternIndex += 1;
|
|
38
|
-
textIndex += 1;
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
if (starPatternIndex === -1) {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
// Give the last star one more character and retry from just after it.
|
|
45
|
-
starTextIndex += 1;
|
|
46
|
-
patternIndex = starPatternIndex;
|
|
47
|
-
textIndex = starTextIndex;
|
|
48
|
-
}
|
|
49
|
-
while (pattern[patternIndex] === '*') {
|
|
50
|
-
patternIndex += 1;
|
|
51
|
-
}
|
|
52
|
-
return patternIndex === pattern.length;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Match a docs-root-relative path against a pattern, segment by segment, where
|
|
56
|
-
* a whole-segment `**` spans zero or more path segments.
|
|
57
|
-
*
|
|
58
|
-
* Same greedy-restart shape as {@link matchSegment}, one level up, so a pattern
|
|
59
|
-
* full of `**` segments stays bounded too.
|
|
60
|
-
*/
|
|
61
|
-
function matchPath(patternSegments, pathSegments) {
|
|
62
|
-
let patternIndex = 0;
|
|
63
|
-
let pathIndex = 0;
|
|
64
|
-
let starPatternIndex = -1;
|
|
65
|
-
let starPathIndex = 0;
|
|
66
|
-
while (pathIndex < pathSegments.length) {
|
|
67
|
-
if (patternSegments[patternIndex] === '**') {
|
|
68
|
-
while (patternSegments[patternIndex] === '**') {
|
|
69
|
-
patternIndex += 1;
|
|
70
|
-
}
|
|
71
|
-
if (patternIndex === patternSegments.length) {
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
starPatternIndex = patternIndex;
|
|
75
|
-
starPathIndex = pathIndex;
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
if (patternIndex < patternSegments.length &&
|
|
79
|
-
matchSegment(patternSegments[patternIndex], pathSegments[pathIndex])) {
|
|
80
|
-
patternIndex += 1;
|
|
81
|
-
pathIndex += 1;
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
if (starPatternIndex === -1) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
starPathIndex += 1;
|
|
88
|
-
patternIndex = starPatternIndex;
|
|
89
|
-
pathIndex = starPathIndex;
|
|
90
|
-
}
|
|
91
|
-
while (patternSegments[patternIndex] === '**') {
|
|
92
|
-
patternIndex += 1;
|
|
93
|
-
}
|
|
94
|
-
return patternIndex === patternSegments.length;
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Compile exclusion globs matched against **docs-root-relative POSIX paths**
|
|
98
|
-
* (`api/auth.md`, `api/nested`), never against absolute or CWD-relative ones.
|
|
99
|
-
*
|
|
100
|
-
* Grammar, defined once and documented in
|
|
101
|
-
* `apps/oat-docs/docs/reference/oat-directory-structure.md`:
|
|
102
|
-
*
|
|
103
|
-
* - `*` matches any run of characters inside a single path segment.
|
|
104
|
-
* - `**` spans `/` only as a whole segment, where it covers zero or more
|
|
105
|
-
* segments: `**\/CLAUDE.md` matches `CLAUDE.md` and `api/CLAUDE.md`. Inside a
|
|
106
|
-
* segment (`a**b`) it is an ordinary single-segment wildcard.
|
|
107
|
-
* - Patterns are anchored at both ends against the whole relative path, so a
|
|
108
|
-
* bare `CLAUDE.md` matches only the root-level file. Use `**\/CLAUDE.md` for
|
|
109
|
-
* every depth.
|
|
110
|
-
* - A trailing `/` restricts a pattern to directories: `drafts/` prunes the
|
|
111
|
-
* `drafts` directory and everything beneath it, and never matches a file.
|
|
112
|
-
* Without it, a pattern that matches a directory path prunes it too.
|
|
113
|
-
* - Matching is case-sensitive, `/` is the separator on every platform, and
|
|
114
|
-
* `*` is the only metacharacter — `.`, `+`, and friends are literal.
|
|
115
|
-
*
|
|
116
|
-
* Entries are trimmed; a leading `./` or `/` is stripped so both spellings
|
|
117
|
-
* anchor at the docs root. Blank entries are ignored.
|
|
118
|
-
*/
|
|
119
|
-
export function createExclusionMatcher(patterns) {
|
|
120
|
-
const filePatterns = [];
|
|
121
|
-
const directoryPatterns = [];
|
|
122
|
-
for (const rawPattern of patterns) {
|
|
123
|
-
const trimmedPattern = rawPattern.trim();
|
|
124
|
-
if (!trimmedPattern) {
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
const directoryOnly = trimmedPattern.endsWith('/');
|
|
128
|
-
const normalized = trimmedPattern
|
|
129
|
-
.replace(/\/+$/, '')
|
|
130
|
-
.replace(/^\.\//, '')
|
|
131
|
-
.replace(/^\/+/, '');
|
|
132
|
-
if (!normalized) {
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
const segments = normalized.split('/');
|
|
136
|
-
directoryPatterns.push(segments);
|
|
137
|
-
if (!directoryOnly) {
|
|
138
|
-
filePatterns.push(segments);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
if (directoryPatterns.length === 0) {
|
|
142
|
-
return NO_EXCLUSIONS;
|
|
143
|
-
}
|
|
144
|
-
const matches = (compiled, relativePath) => {
|
|
145
|
-
const pathSegments = relativePath.split('/');
|
|
146
|
-
return compiled.some((segments) => matchPath(segments, pathSegments));
|
|
147
|
-
};
|
|
148
|
-
return {
|
|
149
|
-
excludesFile: (relativePath) => matches(filePatterns, relativePath),
|
|
150
|
-
excludesDirectory: (relativePath) => matches(directoryPatterns, relativePath),
|
|
151
|
-
};
|
|
152
|
-
}
|
|
2
|
+
import { join, relative, resolve } from 'node:path';
|
|
3
|
+
import { hasIndexContents, parseIndexContents, } from '../../docs/nav/contents.js';
|
|
4
|
+
import { resolveFolderTitle } from '../../docs/nav/fumadocs.js';
|
|
5
|
+
import { createExclusionMatcher, } from '../../docs/shared/exclusions.js';
|
|
6
|
+
export { createExclusionMatcher } from '../../docs/shared/exclusions.js';
|
|
153
7
|
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---/;
|
|
154
8
|
const HEADING_RE = /^#\s+(.+)$/m;
|
|
155
9
|
function fileNameToTitle(fileName) {
|
|
@@ -206,17 +60,18 @@ function sortEntries(entries) {
|
|
|
206
60
|
function prefixEntryPath(entry, prefix) {
|
|
207
61
|
return {
|
|
208
62
|
...entry,
|
|
209
|
-
path:
|
|
63
|
+
path: relativeKey(prefix, entry.path),
|
|
210
64
|
children: entry.children?.map((child) => prefixEntryPath(child, prefix)),
|
|
211
65
|
};
|
|
212
66
|
}
|
|
213
|
-
/**
|
|
67
|
+
/** Relative POSIX path used for matching and manifests, never for file IO. */
|
|
214
68
|
function relativeKey(base, name) {
|
|
215
69
|
return base ? `${base}/${name}` : name;
|
|
216
70
|
}
|
|
217
71
|
async function collectEntries(docsDir, relativeBase, matcher) {
|
|
218
72
|
const entries = [];
|
|
219
73
|
const subdirs = [];
|
|
74
|
+
let indexMarkdown;
|
|
220
75
|
const dirEntries = await readdir(docsDir, { withFileTypes: true });
|
|
221
76
|
for (const entry of dirEntries) {
|
|
222
77
|
const relativePath = relativeKey(relativeBase, entry.name);
|
|
@@ -231,6 +86,8 @@ async function collectEntries(docsDir, relativeBase, matcher) {
|
|
|
231
86
|
}
|
|
232
87
|
const filePath = join(docsDir, entry.name);
|
|
233
88
|
const content = await readFile(filePath, 'utf8');
|
|
89
|
+
if (entry.name === 'index.md')
|
|
90
|
+
indexMarkdown = content;
|
|
234
91
|
const { title, description } = resolveTitle(content, entry.name);
|
|
235
92
|
entries.push({
|
|
236
93
|
title,
|
|
@@ -246,13 +103,50 @@ async function collectEntries(docsDir, relativeBase, matcher) {
|
|
|
246
103
|
// them, and it composes upward through the recursion.
|
|
247
104
|
if (children.length > 0) {
|
|
248
105
|
entries.push({
|
|
249
|
-
title:
|
|
106
|
+
title: children.find((child) => child.path === 'index.md')
|
|
107
|
+
? (resolveFolderTitle(await readFile(join(docsDir, subdir, 'index.md'), 'utf8')) ?? fileNameToTitle(subdir))
|
|
108
|
+
: fileNameToTitle(subdir),
|
|
250
109
|
path: subdir,
|
|
251
110
|
children: children.map((child) => prefixEntryPath(child, subdir)),
|
|
252
111
|
});
|
|
253
112
|
}
|
|
254
113
|
}
|
|
255
|
-
|
|
114
|
+
const fallback = sortEntries(entries);
|
|
115
|
+
if (indexMarkdown === undefined || !hasIndexContents(indexMarkdown))
|
|
116
|
+
return fallback;
|
|
117
|
+
const contents = parseIndexContents(indexMarkdown, join(docsDir, 'index.md'), {
|
|
118
|
+
allowEmpty: true,
|
|
119
|
+
});
|
|
120
|
+
// Contents only orders surviving inventory. Looking up captured paths avoids
|
|
121
|
+
// probing missing, excluded or outside-root targets with nav's strict resolver.
|
|
122
|
+
const inventory = new Map();
|
|
123
|
+
const recordPaths = (entry, direct) => {
|
|
124
|
+
inventory.set(entry.path, direct);
|
|
125
|
+
for (const child of entry.children ?? [])
|
|
126
|
+
recordPaths(child, direct);
|
|
127
|
+
};
|
|
128
|
+
for (const entry of entries)
|
|
129
|
+
recordPaths(entry, entry);
|
|
130
|
+
const ordered = [];
|
|
131
|
+
const add = (entry) => {
|
|
132
|
+
if (entry && !ordered.includes(entry))
|
|
133
|
+
ordered.push(entry);
|
|
134
|
+
};
|
|
135
|
+
add(entries.find((entry) => entry.path === 'index.md'));
|
|
136
|
+
for (const entry of contents) {
|
|
137
|
+
const href = entry.href.split('#', 1)[0]?.trim() ?? '';
|
|
138
|
+
if (!href || /^[a-z][a-z0-9+.-]*:/i.test(href) || href.startsWith('//'))
|
|
139
|
+
continue;
|
|
140
|
+
const local = relative(docsDir, resolve(docsDir, href)).replaceAll('\\', '/');
|
|
141
|
+
if (local === '..' || local.startsWith('../'))
|
|
142
|
+
continue;
|
|
143
|
+
add(inventory.get(local));
|
|
144
|
+
}
|
|
145
|
+
for (const entry of fallback) {
|
|
146
|
+
if (!ordered.includes(entry))
|
|
147
|
+
ordered.push({ ...entry, unlisted: true });
|
|
148
|
+
}
|
|
149
|
+
return ordered;
|
|
256
150
|
}
|
|
257
151
|
export async function generateIndex(docsDir, options = {}) {
|
|
258
152
|
return collectEntries(docsDir, '', createExclusionMatcher(options.excludes ?? []));
|
|
@@ -262,12 +156,12 @@ function renderEntries(entries, indent) {
|
|
|
262
156
|
const prefix = ' '.repeat(indent);
|
|
263
157
|
for (const entry of entries) {
|
|
264
158
|
if (entry.children) {
|
|
265
|
-
lines.push(`${prefix}- ${entry.title}`);
|
|
159
|
+
lines.push(`${prefix}- ${entry.title}${entry.unlisted ? ' [unlisted in Contents]' : ''}`);
|
|
266
160
|
lines.push(...renderEntries(entry.children, indent + 1));
|
|
267
161
|
}
|
|
268
162
|
else {
|
|
269
163
|
const desc = entry.description ? ` — ${entry.description}` : '';
|
|
270
|
-
lines.push(`${prefix}- [${entry.title}](${entry.path})${desc}`);
|
|
164
|
+
lines.push(`${prefix}- [${entry.title}](${entry.path})${desc}${entry.unlisted ? ' [unlisted in Contents]' : ''}`);
|
|
271
165
|
}
|
|
272
166
|
}
|
|
273
167
|
return lines;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type CommandContext, type GlobalOptions } from '../../../app/command-context.js';
|
|
2
2
|
import { type OatConfig } from '../../../config/oat-config.js';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
|
-
export declare const GENERATED_INDEX_WARNING = "<!-- AUTOGENERATED by `oat docs generate-index`. Do not hand-edit;
|
|
4
|
+
export declare const GENERATED_INDEX_WARNING = "<!-- AUTOGENERATED by `oat docs generate-index`. Do not hand-edit; run `oat docs generate-index` to regenerate. -->";
|
|
5
5
|
interface IndexGenerateFileDependencies {
|
|
6
6
|
generateIndex: (docsDir: string, options: import('./generator.js').GenerateIndexOptions) => Promise<import('./generator.js').IndexEntry[]>;
|
|
7
7
|
renderIndex: (entries: import('./generator.js').IndexEntry[]) => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/index-generate/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAI5C,eAAO,MAAM,uBAAuB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/index-generate/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAI5C,eAAO,MAAM,uBAAuB,wHACmF,CAAC;AA2BxH,UAAU,6BAA6B;IACrC,aAAa,EAAE,CACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,aAAa,EAAE,oBAAoB,KAChD,OAAO,CAAC,OAAO,aAAa,EAAE,UAAU,EAAE,CAAC,CAAC;IACjD,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,aAAa,EAAE,UAAU,EAAE,KAAK,MAAM,CAAC;IACrE,SAAS,EAAE,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,cAAc,KACrB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC7D;AAED,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,QAAQ,EAAE,6BAA6B,CAAC;CACzC;AAmrBD,wBAAgB,8BAA8B,CAC5C,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAgCT"}
|
|
@@ -8,7 +8,9 @@ import { dirExists } from '../../../fs/io.js';
|
|
|
8
8
|
import { normalizeToPosixPath, resolveProjectRoot } from '../../../fs/paths.js';
|
|
9
9
|
import { Command, Option } from 'commander';
|
|
10
10
|
import { generateIndex, renderIndex } from './generator.js';
|
|
11
|
-
export const GENERATED_INDEX_WARNING = '<!-- AUTOGENERATED by `oat docs generate-index`. Do not hand-edit;
|
|
11
|
+
export const GENERATED_INDEX_WARNING = '<!-- AUTOGENERATED by `oat docs generate-index`. Do not hand-edit; run `oat docs generate-index` to regenerate. -->';
|
|
12
|
+
// Released before the tooling-aware regeneration instructions were introduced.
|
|
13
|
+
const LEGACY_GENERATED_INDEX_WARNING = '<!-- AUTOGENERATED by `oat docs generate-index`. Do not hand-edit; changes are clobbered on every `predev` / `prebuild`. -->';
|
|
12
14
|
const YAML_EXTENSIONS = ['.yml', '.yaml'];
|
|
13
15
|
/**
|
|
14
16
|
* Exit codes, per the `packages/cli/AGENTS.md` taxonomy.
|
|
@@ -59,11 +61,19 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
59
61
|
buildCommandContext,
|
|
60
62
|
fileDeps: DEFAULT_FILE_DEPS,
|
|
61
63
|
};
|
|
62
|
-
function buildGeneratedIndexOutput(content) {
|
|
64
|
+
function buildGeneratedIndexOutput(content, tooling) {
|
|
65
|
+
const regeneration = tooling === 'markdown'
|
|
66
|
+
? 'Markdown has no automatic manifest hooks; regenerate explicitly after source changes.'
|
|
67
|
+
: tooling === 'fumadocs'
|
|
68
|
+
? 'Fresh Fumadocs apps regenerate this manifest in predev/prebuild.'
|
|
69
|
+
: tooling === 'mkdocs'
|
|
70
|
+
? 'MkDocs manifests are optional; regenerate explicitly or configure a build hook.'
|
|
71
|
+
: 'Regenerate after source changes, or configure a dev/build hook.';
|
|
72
|
+
const header = `${GENERATED_INDEX_WARNING}\n<!-- ${regeneration} -->`;
|
|
63
73
|
if (!content) {
|
|
64
|
-
return
|
|
74
|
+
return header;
|
|
65
75
|
}
|
|
66
|
-
return `${
|
|
76
|
+
return `${header}\n\n${content}`;
|
|
67
77
|
}
|
|
68
78
|
/**
|
|
69
79
|
* True when the relative path escapes its base. A bare `startsWith('..')` test
|
|
@@ -171,10 +181,11 @@ function collectExclude(value, previous) {
|
|
|
171
181
|
* repository deliberately excluded. Entries are trimmed, blanks are dropped,
|
|
172
182
|
* and duplicates collapse while preserving first-seen order.
|
|
173
183
|
*/
|
|
174
|
-
function resolveExcludes(config, flagValues) {
|
|
184
|
+
function resolveExcludes(config, flagValues, nonReaderPaths = []) {
|
|
175
185
|
const merged = [];
|
|
176
186
|
for (const value of [
|
|
177
187
|
...(config.documentation?.excludes ?? []),
|
|
188
|
+
...nonReaderPaths,
|
|
178
189
|
...(flagValues ?? []),
|
|
179
190
|
]) {
|
|
180
191
|
const entry = value.trim();
|
|
@@ -252,7 +263,13 @@ async function resolveIndexGeneratePaths(context, options, deps) {
|
|
|
252
263
|
docsDirSource,
|
|
253
264
|
outputPath,
|
|
254
265
|
outputIsExplicit,
|
|
255
|
-
excludes: resolveExcludes(config, options.exclude
|
|
266
|
+
excludes: resolveExcludes(config, options.exclude, configuredRoot &&
|
|
267
|
+
docsDir ===
|
|
268
|
+
(!isMarkdown && (await deps.dirExists(join(configuredRoot, 'docs')))
|
|
269
|
+
? join(configuredRoot, 'docs')
|
|
270
|
+
: configuredRoot)
|
|
271
|
+
? config.documentation?.nonReaderPaths
|
|
272
|
+
: []),
|
|
256
273
|
};
|
|
257
274
|
}
|
|
258
275
|
/** `canonicalize`, but an unresolvable path yields null instead of throwing. */
|
|
@@ -359,7 +376,8 @@ async function assertOutputIsSafe(resolved, canonical, deps) {
|
|
|
359
376
|
return;
|
|
360
377
|
}
|
|
361
378
|
const existing = await deps.readFileIfPresent(outputPath);
|
|
362
|
-
if (existing !== null &&
|
|
379
|
+
if (existing !== null &&
|
|
380
|
+
![GENERATED_INDEX_WARNING, LEGACY_GENERATED_INDEX_WARNING].some((marker) => existing.includes(marker))) {
|
|
363
381
|
throw new CliError(`Refusing to overwrite ${outputPath}: the file exists and is not a generated index ` +
|
|
364
382
|
'(it has no `oat docs generate-index` AUTOGENERATED header). ' +
|
|
365
383
|
'Move or delete it, or pass --output to name it explicitly.', REFUSAL_EXIT_CODE);
|
|
@@ -412,7 +430,7 @@ async function runIndexGenerate(context, options, deps) {
|
|
|
412
430
|
const entries = await deps.generateIndex(docsDir, {
|
|
413
431
|
excludes: resolved.excludes,
|
|
414
432
|
});
|
|
415
|
-
const content = buildGeneratedIndexOutput(deps.renderIndex(entries));
|
|
433
|
+
const content = buildGeneratedIndexOutput(deps.renderIndex(entries), resolved.config.documentation?.tooling);
|
|
416
434
|
await deps.writeFile(outputPath, content, 'utf8');
|
|
417
435
|
if (isFumadocsManifestTransition(resolved, canonical)) {
|
|
418
436
|
const indexPath = buildDocumentationIndexValue(resolved, canonical);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/index.ts"],"names":[],"mappings":"
|
|
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;AA2MD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAoC7E;AA0QD,wBAAgB,qBAAqB,CACnC,SAAS,GAAE,OAAO,CAAC,oBAAoB,CAAM,GAC5C,OAAO,CAiET"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
1
2
|
import { join } from 'node:path';
|
|
2
3
|
import { buildCommandContext, } from '../../../app/command-context.js';
|
|
4
|
+
import { syncDocsNavigation } from '../../docs/nav/sync.js';
|
|
3
5
|
import { formatAgentsMdGuidanceResult, formatAgentsMdMutationFailure, previewAgentsMdSection, upsertAgentsMdSection, } from '../../shared/agents-md.js';
|
|
4
6
|
import { confirmAction, inputWithDefault, selectWithAbort, } from '../../shared/shared.prompts.js';
|
|
5
7
|
import { readGlobalOptions } from '../../shared/shared.utils.js';
|
|
6
8
|
import { readOatConfig, writeOatConfig, } from '../../../config/oat-config.js';
|
|
7
9
|
import { resolveAssetsRoot } from '../../../fs/assets.js';
|
|
10
|
+
import { atomicWriteJson, fileExists } from '../../../fs/io.js';
|
|
8
11
|
import { Command, Option } from 'commander';
|
|
9
12
|
import { buildDocsCommands } from './docs-commands.js';
|
|
10
13
|
import { applyMarkdownDocsPlan, MarkdownDocsWriteError, planMarkdownDocs, validateMarkdownConfig, validateMarkdownTarget, } from './markdown.js';
|
|
@@ -146,7 +149,24 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
146
149
|
...config.documentation,
|
|
147
150
|
...result.documentationConfig,
|
|
148
151
|
};
|
|
149
|
-
|
|
152
|
+
// Fresh app creation replaces only the seeded documentation keys. Keep
|
|
153
|
+
// unknown repository and documentation siblings for other consumers.
|
|
154
|
+
const configPath = join(context.cwd, '.oat/config.json');
|
|
155
|
+
const raw = (await fileExists(configPath))
|
|
156
|
+
? JSON.parse(await readFile(configPath, 'utf8'))
|
|
157
|
+
: config;
|
|
158
|
+
await atomicWriteJson(configPath, {
|
|
159
|
+
...raw,
|
|
160
|
+
documentation: {
|
|
161
|
+
...raw.documentation,
|
|
162
|
+
...result.documentationConfig,
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
await syncDocsNavigation({
|
|
166
|
+
appRoot: result.appRoot,
|
|
167
|
+
configuredTooling: options.framework,
|
|
168
|
+
nonReaderPaths: config.documentation.nonReaderPaths,
|
|
169
|
+
});
|
|
150
170
|
if (!context.json) {
|
|
151
171
|
context.logger.info(`Scaffolded docs app at ${options.targetDir}`);
|
|
152
172
|
context.logger.info(` Framework: ${options.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;AAMjE,OAAO,KAAK,EAEV,aAAa,EACb,uBAAuB,EAExB,MAAM,mBAAmB,CAAC;AAsF3B,MAAM,WAAW,sBAAuB,SAAQ,uBAAuB;IACrE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mBAAmB,EAAE,sBAAsB,CAAC;CAC7C;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAED,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAEtC,MAAM,WAAW,2BAA2B;IAC1C,iBAAiB,EAAE,MAAM,YAAY,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACjE,0BAA0B,EAAE,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,KACZ,YAAY,CAAC,OAAO,CAAC,CAAC;CAC5B;AAUD,eAAO,MAAM,aAAa,YAAY,CAAC;AAEvC,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOxE;AAgDD,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC,CAaxB;
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/scaffold.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAMjE,OAAO,KAAK,EAEV,aAAa,EACb,uBAAuB,EAExB,MAAM,mBAAmB,CAAC;AAsF3B,MAAM,WAAW,sBAAuB,SAAQ,uBAAuB;IACrE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mBAAmB,EAAE,sBAAsB,CAAC;CAC7C;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAED,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAEtC,MAAM,WAAW,2BAA2B;IAC1C,iBAAiB,EAAE,MAAM,YAAY,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACjE,0BAA0B,EAAE,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,KACZ,YAAY,CAAC,OAAO,CAAC,CAAC;CAC5B;AAUD,eAAO,MAAM,aAAa,YAAY,CAAC;AAEvC,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOxE;AAgDD,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC,CAaxB;AAmND;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,MAAM,GAChB,sBAAsB,CAwBxB;AA6CD,wBAAsB,eAAe,CACnC,OAAO,EAAE,sBAAsB,EAC/B,SAAS,GAAE,OAAO,CAAC,2BAA2B,CAAM,GACnD,OAAO,CAAC,qBAAqB,CAAC,CAwDhC"}
|