@open-agent-toolkit/cli 0.3.31 → 0.3.33
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/check.md +54 -30
- package/assets/docs/docs-tooling/commands.md +21 -2
- package/assets/docs/docs-tooling/workflows.md +14 -6
- package/assets/docs/reference/cli-reference.md +2 -2
- package/assets/docs/reference/config-and-local-state.md +1 -1
- package/assets/docs/reference/configuration.md +2 -2
- package/assets/docs/reference/docs-index-contract.md +3 -2
- package/assets/docs/reference/oat-directory-structure.md +1 -1
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-agent-instructions-analyze/SKILL.md +2 -2
- package/assets/skills/oat-docs-analyze/SKILL.md +63 -25
- package/assets/skills/oat-docs-analyze/references/analysis-artifact-template.md +9 -6
- package/assets/skills/oat-docs-analyze/references/quality-checklist.md +2 -2
- package/assets/skills/oat-docs-analyze/scripts/package-drift.mjs +358 -40
- package/assets/skills/oat-docs-apply/SKILL.md +22 -12
- package/assets/skills/oat-docs-apply/references/apply-plan-template.md +3 -2
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +47 -9
- package/dist/commands/docs/check/check.d.ts.map +1 -1
- package/dist/commands/docs/check/check.js +1 -0
- package/dist/commands/docs/check/checker.d.ts +2 -0
- package/dist/commands/docs/check/checker.d.ts.map +1 -1
- package/dist/commands/docs/check/checker.js +2 -0
- package/dist/commands/docs/check/commands.d.ts.map +1 -1
- package/dist/commands/docs/check/commands.js +74 -30
- package/dist/commands/docs/check/files.d.ts +2 -0
- package/dist/commands/docs/check/files.d.ts.map +1 -1
- package/dist/commands/docs/check/files.js +16 -0
- package/dist/commands/docs/check/navigation.d.ts +7 -1
- package/dist/commands/docs/check/navigation.d.ts.map +1 -1
- package/dist/commands/docs/check/navigation.js +19 -68
- package/dist/commands/docs/check/reader-rules.d.ts.map +1 -1
- package/dist/commands/docs/check/reader-rules.js +8 -3
- package/dist/commands/docs/index-generate/generator.d.ts +9 -1
- package/dist/commands/docs/index-generate/generator.d.ts.map +1 -1
- package/dist/commands/docs/index-generate/generator.js +17 -6
- 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 +24 -12
- package/dist/commands/docs/init/content.d.ts +2 -3
- package/dist/commands/docs/init/content.d.ts.map +1 -1
- package/dist/commands/docs/init/content.js +3 -10
- package/dist/commands/docs/nav/fumadocs.d.ts +29 -0
- package/dist/commands/docs/nav/fumadocs.d.ts.map +1 -1
- package/dist/commands/docs/nav/fumadocs.js +8 -5
- package/dist/commands/docs/nav/membership.d.ts +37 -0
- package/dist/commands/docs/nav/membership.d.ts.map +1 -0
- package/dist/commands/docs/nav/membership.js +475 -0
- package/dist/commands/docs/nav/sync.d.ts +26 -2
- package/dist/commands/docs/nav/sync.d.ts.map +1 -1
- package/dist/commands/docs/nav/sync.js +160 -43
- package/dist/config/documentation-ia.d.ts +19 -0
- package/dist/config/documentation-ia.d.ts.map +1 -0
- package/dist/config/documentation-ia.js +42 -0
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +5 -1
- package/package.json +3 -3
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Read-only, offline comparison used by oat-docs-analyze.
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
// Read-only, offline comparison used by oat-docs-analyze. It reads installed
|
|
3
|
+
// package manifests the way Node resolves packages (the app's node_modules,
|
|
4
|
+
// then each ancestor's) and never installs, fetches or executes anything.
|
|
5
|
+
import { access, open, readFile, realpath } from 'node:fs/promises';
|
|
6
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
5
7
|
import { parseArgs } from 'node:util';
|
|
6
8
|
|
|
7
9
|
const shellQuote = (value) =>
|
|
8
10
|
`'${value.replaceAll("'", String.fromCharCode(39, 92, 39, 39))}'`;
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
'Provide --cli with the installed oat executable or --versions with its bundled public-package-versions.json.',
|
|
14
|
-
);
|
|
15
|
-
let directory = dirname(await realpath(executable));
|
|
12
|
+
// Walk up from a real file to the installed CLI package root.
|
|
13
|
+
async function cliPackageFor(file) {
|
|
14
|
+
let directory = dirname(file);
|
|
16
15
|
for (;;) {
|
|
17
16
|
try {
|
|
18
17
|
const pkg = JSON.parse(
|
|
@@ -24,14 +23,302 @@ async function versionsForCli(executable) {
|
|
|
24
23
|
if (error.code !== 'ENOENT') throw error;
|
|
25
24
|
}
|
|
26
25
|
const parent = dirname(directory);
|
|
27
|
-
if (parent === directory)
|
|
28
|
-
throw new Error(
|
|
29
|
-
'Cannot locate the running CLI bundle through this wrapper; supply --versions from that installed CLI.',
|
|
30
|
-
);
|
|
26
|
+
if (parent === directory) return null;
|
|
31
27
|
directory = parent;
|
|
32
28
|
}
|
|
33
29
|
}
|
|
34
30
|
|
|
31
|
+
// Package-manager shims (pnpm, cmd-shim) are POSIX shell scripts. Parse them as
|
|
32
|
+
// text and never execute them: the `# cmd-shim-target=` comment names the
|
|
33
|
+
// absolute entry; `exec` lines name it relative to the shim's real directory.
|
|
34
|
+
async function shimTargets(file) {
|
|
35
|
+
const handle = await open(file, 'r');
|
|
36
|
+
let text;
|
|
37
|
+
try {
|
|
38
|
+
const { size } = await handle.stat();
|
|
39
|
+
if (size > 65536) return [];
|
|
40
|
+
text = await handle.readFile('utf8');
|
|
41
|
+
} finally {
|
|
42
|
+
await handle.close();
|
|
43
|
+
}
|
|
44
|
+
const [shebang = ''] = text.split(/\r?\n/, 1);
|
|
45
|
+
if (!/^#!.*\b(?:sh|bash|dash|ksh|zsh)\b/.test(shebang)) return [];
|
|
46
|
+
const base = dirname(file);
|
|
47
|
+
const targets = [];
|
|
48
|
+
for (const match of text.matchAll(/^#\s*cmd-shim-target=(.+?)\s*$/gm))
|
|
49
|
+
targets.push(isAbsolute(match[1]) ? match[1] : resolve(base, match[1]));
|
|
50
|
+
for (const match of text.matchAll(/"\$basedir\/([^"$`\\]+\.(?:c|m)?js)"/g))
|
|
51
|
+
targets.push(resolve(base, match[1]));
|
|
52
|
+
return [...new Set(targets)];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function versionsForCli(executable) {
|
|
56
|
+
if (!executable)
|
|
57
|
+
throw new Error(
|
|
58
|
+
'Provide --cli with the installed oat executable or --versions with its bundled public-package-versions.json.',
|
|
59
|
+
);
|
|
60
|
+
const file = await realpath(executable);
|
|
61
|
+
const targets = await shimTargets(file);
|
|
62
|
+
// Direct installs resolve to the bundle entry itself; shims are never walked
|
|
63
|
+
// from their own location, which can sit above an unrelated package.
|
|
64
|
+
for (const target of targets.length > 0 ? targets : [file]) {
|
|
65
|
+
let entry;
|
|
66
|
+
try {
|
|
67
|
+
entry = await realpath(target);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (error.code === 'ENOENT' || error.code === 'ENOTDIR') continue;
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
const found = await cliPackageFor(entry);
|
|
73
|
+
if (found) return found;
|
|
74
|
+
}
|
|
75
|
+
throw new Error(
|
|
76
|
+
'Cannot locate the running CLI bundle through this wrapper; supply --versions from that installed CLI.',
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function exists(path) {
|
|
81
|
+
try {
|
|
82
|
+
await access(path);
|
|
83
|
+
return true;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (error.code === 'ENOENT' || error.code === 'ENOTDIR') return false;
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function readJson(path) {
|
|
91
|
+
try {
|
|
92
|
+
return JSON.parse(await readFile(path, 'utf8'));
|
|
93
|
+
} catch (error) {
|
|
94
|
+
if (error.code === 'ENOENT' || error.code === 'ENOTDIR') return null;
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function ancestors(directory) {
|
|
100
|
+
const list = [];
|
|
101
|
+
for (let current = directory; ; current = dirname(current)) {
|
|
102
|
+
list.push(current);
|
|
103
|
+
if (dirname(current) === current) return list;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Node package lookup: <dir>/node_modules/<name> from the app upward, so
|
|
108
|
+
// hoisted installs (pnpm node-linker=hoisted, npm/yarn workspaces) resolve.
|
|
109
|
+
async function installedManifest(appPath, name) {
|
|
110
|
+
for (const directory of ancestors(appPath)) {
|
|
111
|
+
const path = join(directory, 'node_modules', name, 'package.json');
|
|
112
|
+
const manifest = await readJson(path);
|
|
113
|
+
if (manifest !== null) return { path, manifest };
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// The app's own packageManager wins, then the nearest ancestor's.
|
|
119
|
+
async function packageManagerFor(appPath) {
|
|
120
|
+
for (const directory of ancestors(appPath)) {
|
|
121
|
+
const manifest = await readJson(join(directory, 'package.json'));
|
|
122
|
+
if (typeof manifest?.packageManager === 'string')
|
|
123
|
+
return manifest.packageManager.trim();
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Remove a YAML comment: `#` at line start or after whitespace, outside quotes.
|
|
129
|
+
function stripYamlComment(line) {
|
|
130
|
+
let quote = null;
|
|
131
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
132
|
+
const char = line[index];
|
|
133
|
+
if (quote) {
|
|
134
|
+
if (char === quote) quote = null;
|
|
135
|
+
} else if (char === '"' || char === "'") quote = char;
|
|
136
|
+
else if (char === '#' && (index === 0 || /\s/.test(line[index - 1])))
|
|
137
|
+
return line.slice(0, index);
|
|
138
|
+
}
|
|
139
|
+
return line;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function unquoteYaml(value) {
|
|
143
|
+
const text = value.trim();
|
|
144
|
+
if (text.length >= 2 && text.startsWith("'") && text.endsWith("'"))
|
|
145
|
+
return text.slice(1, -1).replaceAll("''", "'");
|
|
146
|
+
if (text.length >= 2 && text.startsWith('"') && text.endsWith('"')) {
|
|
147
|
+
try {
|
|
148
|
+
return JSON.parse(text);
|
|
149
|
+
} catch {
|
|
150
|
+
return text.slice(1, -1);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return text;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Split a flow sequence body on commas outside quotes and braces.
|
|
157
|
+
function splitFlowItems(body) {
|
|
158
|
+
const items = [];
|
|
159
|
+
let quote = null;
|
|
160
|
+
let depth = 0;
|
|
161
|
+
let current = '';
|
|
162
|
+
for (const char of body) {
|
|
163
|
+
if (quote) {
|
|
164
|
+
if (char === quote) quote = null;
|
|
165
|
+
} else if (char === '"' || char === "'") quote = char;
|
|
166
|
+
else if (char === '{') depth += 1;
|
|
167
|
+
else if (char === '}') depth -= 1;
|
|
168
|
+
else if (char === ',' && depth === 0) {
|
|
169
|
+
items.push(current);
|
|
170
|
+
current = '';
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
current += char;
|
|
174
|
+
}
|
|
175
|
+
items.push(current);
|
|
176
|
+
return items;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// The `packages` list of a pnpm-workspace.yaml: an indented or unindented
|
|
180
|
+
// block sequence or a flow sequence, with quotes and comments. A file
|
|
181
|
+
// without `packages` (settings only) declares no member packages.
|
|
182
|
+
function workspacePatterns(text) {
|
|
183
|
+
const lines = text.split(/\r?\n/).map(stripYamlComment);
|
|
184
|
+
const start = lines.findIndex((line) => /^packages\s*:/.test(line));
|
|
185
|
+
if (start < 0) return [];
|
|
186
|
+
const inline = lines[start].replace(/^packages\s*:/, '').trim();
|
|
187
|
+
if (inline.startsWith('[')) {
|
|
188
|
+
let flow = inline;
|
|
189
|
+
for (
|
|
190
|
+
let index = start + 1;
|
|
191
|
+
!flow.includes(']') && index < lines.length;
|
|
192
|
+
index += 1
|
|
193
|
+
)
|
|
194
|
+
flow += ` ${lines[index].trim()}`;
|
|
195
|
+
return splitFlowItems(flow.slice(1, flow.lastIndexOf(']')))
|
|
196
|
+
.map(unquoteYaml)
|
|
197
|
+
.filter((entry) => entry.length > 0);
|
|
198
|
+
}
|
|
199
|
+
const patterns = [];
|
|
200
|
+
for (const line of lines.slice(start + 1)) {
|
|
201
|
+
if (line.trim() === '') continue;
|
|
202
|
+
const item = line.match(/^\s*-\s*(.*)$/);
|
|
203
|
+
if (!item) break;
|
|
204
|
+
patterns.push(unquoteYaml(item[1]));
|
|
205
|
+
}
|
|
206
|
+
return patterns.filter((entry) => entry.length > 0);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Expand `{a,b}` alternatives, innermost first.
|
|
210
|
+
function expandBraces(pattern) {
|
|
211
|
+
const match = pattern.match(/\{([^{}]*)\}/);
|
|
212
|
+
if (!match) return [pattern];
|
|
213
|
+
return match[1]
|
|
214
|
+
.split(',')
|
|
215
|
+
.flatMap((alternative) =>
|
|
216
|
+
expandBraces(
|
|
217
|
+
pattern.slice(0, match.index) +
|
|
218
|
+
alternative +
|
|
219
|
+
pattern.slice(match.index + match[0].length),
|
|
220
|
+
),
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Glob syntax evaluated here: `*`, `**`, `?`, braces (expanded first) and
|
|
225
|
+
// positive character classes. Extglobs, negated classes, escapes and
|
|
226
|
+
// unbalanced brackets are not, and never count as a non-match.
|
|
227
|
+
function unsupportedGlob(pattern) {
|
|
228
|
+
return (
|
|
229
|
+
/[+@!?*]\(/.test(pattern) ||
|
|
230
|
+
/\[[!^]/.test(pattern) ||
|
|
231
|
+
pattern.includes('\\') ||
|
|
232
|
+
/\[(?![^\]]*\])/.test(pattern) ||
|
|
233
|
+
/\[\]/.test(pattern)
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function globToRegExp(pattern) {
|
|
238
|
+
const source = pattern
|
|
239
|
+
.split(/(\*\*\/|\*\*|\*|\?|\[[^\]]+\])/)
|
|
240
|
+
.map((part) =>
|
|
241
|
+
part === '**/'
|
|
242
|
+
? '(?:.*/)?'
|
|
243
|
+
: part === '**'
|
|
244
|
+
? '.*'
|
|
245
|
+
: part === '*'
|
|
246
|
+
? '[^/]*'
|
|
247
|
+
: part === '?'
|
|
248
|
+
? '[^/]'
|
|
249
|
+
: part.startsWith('[') && part.endsWith(']')
|
|
250
|
+
? `(?!/)[${part.slice(1, -1).replace(/[\\\]]/g, '\\$&')}]`
|
|
251
|
+
: part.replace(/[.+^${}()|[\]\\]/g, '\\$&'),
|
|
252
|
+
)
|
|
253
|
+
.join('');
|
|
254
|
+
return new RegExp(`^${source}$`);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// pnpm finds members by globbing `<pattern>/package.json`, so a trailing
|
|
258
|
+
// globstar also matches the directory itself; negations exclude. Returns
|
|
259
|
+
// true or false, or `{ unsupported: pattern }` when a pattern whose result
|
|
260
|
+
// matters cannot be evaluated.
|
|
261
|
+
function workspaceIncludes(patterns, rel) {
|
|
262
|
+
const target = `${rel}/package.json`;
|
|
263
|
+
const evaluate = (pattern) => {
|
|
264
|
+
const expanded = expandBraces(
|
|
265
|
+
pattern.replace(/^\.\//, '').replace(/\/+$/, ''),
|
|
266
|
+
);
|
|
267
|
+
if (expanded.some(unsupportedGlob)) return { unsupported: pattern };
|
|
268
|
+
return expanded.some((glob) =>
|
|
269
|
+
globToRegExp(`${glob}/package.json`).test(target),
|
|
270
|
+
);
|
|
271
|
+
};
|
|
272
|
+
const any = (list) => {
|
|
273
|
+
let unknown = null;
|
|
274
|
+
for (const pattern of list) {
|
|
275
|
+
const result = evaluate(pattern);
|
|
276
|
+
if (result === true) return true;
|
|
277
|
+
if (result !== false && unknown === null) unknown = result;
|
|
278
|
+
}
|
|
279
|
+
return unknown ?? false;
|
|
280
|
+
};
|
|
281
|
+
const included = any(patterns.filter((pattern) => !pattern.startsWith('!')));
|
|
282
|
+
if (included !== true) return included;
|
|
283
|
+
const excluded = any(
|
|
284
|
+
patterns
|
|
285
|
+
.filter((pattern) => pattern.startsWith('!'))
|
|
286
|
+
.map((pattern) => pattern.slice(1)),
|
|
287
|
+
);
|
|
288
|
+
return excluded === true ? false : excluded === false ? true : excluded;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// The app's relation to the nearest pnpm workspace: its own root, a member of
|
|
292
|
+
// an ancestor workspace, standalone (the ancestor's `packages` globs exclude
|
|
293
|
+
// it, so installs need --ignore-workspace), or undetermined when a pattern
|
|
294
|
+
// cannot be evaluated. Lockfile presence is not evidence: a member can keep
|
|
295
|
+
// its own lockfile with shared-workspace-lockfile=false.
|
|
296
|
+
async function workspaceMembership(appPath) {
|
|
297
|
+
if (await exists(join(appPath, 'pnpm-workspace.yaml')))
|
|
298
|
+
return { root: appPath, membership: 'root', reason: null };
|
|
299
|
+
for (const directory of ancestors(dirname(appPath))) {
|
|
300
|
+
const file = join(directory, 'pnpm-workspace.yaml');
|
|
301
|
+
if (!(await exists(file))) continue;
|
|
302
|
+
const rel = relative(directory, appPath).split(sep).join('/');
|
|
303
|
+
const included = workspaceIncludes(
|
|
304
|
+
workspacePatterns(await readFile(file, 'utf8')),
|
|
305
|
+
rel,
|
|
306
|
+
);
|
|
307
|
+
if (typeof included === 'boolean')
|
|
308
|
+
return {
|
|
309
|
+
root: directory,
|
|
310
|
+
membership: included ? 'member' : 'standalone',
|
|
311
|
+
reason: null,
|
|
312
|
+
};
|
|
313
|
+
return {
|
|
314
|
+
root: directory,
|
|
315
|
+
membership: 'undetermined',
|
|
316
|
+
reason: `pnpm-workspace.yaml pattern "${included.unsupported}" uses glob syntax this helper does not evaluate; workspace membership is unknown, so the command omits --ignore-workspace. Confirm membership with pnpm -r ls before running it.`,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
return { root: null, membership: null, reason: null };
|
|
320
|
+
}
|
|
321
|
+
|
|
35
322
|
try {
|
|
36
323
|
const { values } = parseArgs({
|
|
37
324
|
options: {
|
|
@@ -41,14 +328,46 @@ try {
|
|
|
41
328
|
},
|
|
42
329
|
});
|
|
43
330
|
if (!values.app) throw new Error('Required: --app <docs-app-directory>.');
|
|
331
|
+
const appPath = resolve(values.app);
|
|
332
|
+
const manifest = await readJson(join(appPath, 'package.json'));
|
|
333
|
+
if (manifest === null) {
|
|
334
|
+
process.stdout.write(
|
|
335
|
+
`${JSON.stringify(
|
|
336
|
+
{
|
|
337
|
+
versionsPath: null,
|
|
338
|
+
appPath,
|
|
339
|
+
applicable: false,
|
|
340
|
+
reason:
|
|
341
|
+
'No package.json in the docs directory: Markdown docs have no app-package drift check.',
|
|
342
|
+
packages: [],
|
|
343
|
+
},
|
|
344
|
+
null,
|
|
345
|
+
2,
|
|
346
|
+
)}\n`,
|
|
347
|
+
);
|
|
348
|
+
process.exit(0);
|
|
349
|
+
}
|
|
44
350
|
const versionsPath = resolve(
|
|
45
351
|
values.versions ?? (await versionsForCli(values.cli)),
|
|
46
352
|
);
|
|
47
353
|
const versions = JSON.parse(await readFile(versionsPath, 'utf8'));
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
354
|
+
const packageManager = await packageManagerFor(appPath);
|
|
355
|
+
const pinned = packageManager?.match(
|
|
356
|
+
/^pnpm@(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)(?:\+.*)?$/,
|
|
51
357
|
);
|
|
358
|
+
// Run the repository's pinned pnpm rather than whatever global pnpm is on
|
|
359
|
+
// PATH: a different major can rewrite workspace settings or reject the store.
|
|
360
|
+
// npx ships with npm on every Node line; Corepack is absent from Node 25+.
|
|
361
|
+
const pnpm = pinned ? `npx --yes pnpm@${pinned[1]}` : 'pnpm';
|
|
362
|
+
const otherManager =
|
|
363
|
+
packageManager && !packageManager.startsWith('pnpm@')
|
|
364
|
+
? packageManager
|
|
365
|
+
: null;
|
|
366
|
+
// A nested app the ancestor workspace does not include must be installed
|
|
367
|
+
// with --ignore-workspace; an undetermined result never adds the flag.
|
|
368
|
+
const workspace = await workspaceMembership(appPath);
|
|
369
|
+
const ignoreWorkspace =
|
|
370
|
+
workspace.membership === 'standalone' ? ' --ignore-workspace' : '';
|
|
52
371
|
const packages = [];
|
|
53
372
|
for (const section of [
|
|
54
373
|
'dependencies',
|
|
@@ -58,6 +377,8 @@ try {
|
|
|
58
377
|
for (const [name, declared] of Object.entries(manifest[section] ?? {})) {
|
|
59
378
|
if (
|
|
60
379
|
![
|
|
380
|
+
// The app-local CLI runs generate-index in predev/prebuild.
|
|
381
|
+
'@open-agent-toolkit/cli',
|
|
61
382
|
'@open-agent-toolkit/docs-config',
|
|
62
383
|
'@open-agent-toolkit/docs-theme',
|
|
63
384
|
'@open-agent-toolkit/docs-transforms',
|
|
@@ -71,29 +392,22 @@ try {
|
|
|
71
392
|
)
|
|
72
393
|
throw new Error(`Missing/invalid bundled version for ${name}.`);
|
|
73
394
|
// Report installed package bytes when available, not just a declared range.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
join(appPath, 'node_modules', name, 'package.json'),
|
|
79
|
-
'utf8',
|
|
80
|
-
),
|
|
81
|
-
);
|
|
82
|
-
if (typeof installedManifest.version !== 'string')
|
|
83
|
-
throw new Error(`Invalid installed version for ${name}.`);
|
|
84
|
-
installed = installedManifest.version;
|
|
85
|
-
} catch (error) {
|
|
86
|
-
if (error.code !== 'ENOENT') throw error;
|
|
87
|
-
}
|
|
395
|
+
const found = await installedManifest(appPath, name);
|
|
396
|
+
if (found !== null && typeof found.manifest.version !== 'string')
|
|
397
|
+
throw new Error(`Invalid installed version for ${name}.`);
|
|
398
|
+
const installed = found?.manifest.version ?? null;
|
|
88
399
|
// Only stable numeric releases are orderable here; prereleases and other
|
|
89
400
|
// package-manager version forms need manual verification, never an upgrade.
|
|
90
401
|
const stable = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
91
402
|
let status = 'unverified';
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
403
|
+
let reason = null;
|
|
404
|
+
if (installed === null)
|
|
405
|
+
reason = `not installed: no node_modules/${name} found from the app or its ancestors; run the app install first`;
|
|
406
|
+
else if (!stable.test(installed))
|
|
407
|
+
reason = `installed version ${installed} is not a stable release; verify it manually`;
|
|
408
|
+
else if (!stable.test(bundled))
|
|
409
|
+
reason = `bundled version ${bundled} is a prerelease; verify it manually`;
|
|
410
|
+
else {
|
|
97
411
|
const left = installed.split('.').map(BigInt);
|
|
98
412
|
const right = bundled.split('.').map(BigInt);
|
|
99
413
|
const differing = left.findIndex(
|
|
@@ -106,22 +420,26 @@ try {
|
|
|
106
420
|
? 'drift'
|
|
107
421
|
: 'ahead';
|
|
108
422
|
}
|
|
423
|
+
let upgradeCommand = null;
|
|
424
|
+
if (status === 'drift' && otherManager)
|
|
425
|
+
reason = `packageManager is ${otherManager}; translate the upgrade to its add command, preserving the dependency section and exact version`;
|
|
426
|
+
else if (status === 'drift')
|
|
427
|
+
upgradeCommand = `${pnpm} --dir ${shellQuote(appPath)} add${ignoreWorkspace}${section === 'devDependencies' ? ' --save-dev' : section === 'optionalDependencies' ? ' --save-optional' : ''} ${name}@${bundled}`;
|
|
109
428
|
packages.push({
|
|
110
429
|
name,
|
|
111
430
|
section,
|
|
112
431
|
declared,
|
|
113
432
|
installed,
|
|
433
|
+
installedPath: found?.path ?? null,
|
|
114
434
|
bundled,
|
|
115
435
|
status,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
? `pnpm --dir ${shellQuote(appPath)} add${section === 'devDependencies' ? ' --save-dev' : section === 'optionalDependencies' ? ' --save-optional' : ''} ${name}@${bundled}`
|
|
119
|
-
: null,
|
|
436
|
+
reason,
|
|
437
|
+
upgradeCommand,
|
|
120
438
|
});
|
|
121
439
|
}
|
|
122
440
|
}
|
|
123
441
|
process.stdout.write(
|
|
124
|
-
`${JSON.stringify({ versionsPath, appPath, packages }, null, 2)}\n`,
|
|
442
|
+
`${JSON.stringify({ versionsPath, appPath, applicable: true, packageManager, workspace, packages }, null, 2)}\n`,
|
|
125
443
|
);
|
|
126
444
|
} catch (error) {
|
|
127
445
|
process.stderr.write(`${error.message}\n`);
|
|
@@ -5,7 +5,7 @@ disable-model-invocation: true
|
|
|
5
5
|
user-invocable: true
|
|
6
6
|
allowed-tools: Read, Write, Edit, Bash(git:*), Bash(gh:*), Bash(oat:*), Bash(pnpm:*), Bash(bash:*), Bash(jq:*), Bash(mkdir:*), Bash(date:*), Bash(echo:*), Bash(cd:*), Bash(pwd:*), Glob, Grep, AskUserQuestion
|
|
7
7
|
metadata:
|
|
8
|
-
version: '1.4.
|
|
8
|
+
version: '1.4.8'
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# Docs Apply
|
|
@@ -276,6 +276,9 @@ a conflict with config becomes `ask_user`, never a config-driven rewrite.
|
|
|
276
276
|
Mirror the accepted record using shared repo config only:
|
|
277
277
|
`oat config set documentation.ia '<JSON>'`, with exactly `{preset, decision,
|
|
278
278
|
tracks?: [{path, principle}], verification?: 'triad'|'agent-only'|'none'}`.
|
|
279
|
+
Write `preset` as the canonical ID (`product-engineering-qa`,
|
|
280
|
+
`consumer-maintainer`, `domain-engineering`, `task-type`, `toolkit-cli` or
|
|
281
|
+
`flat-small`) of the approved label.
|
|
279
282
|
`decision` is repo-relative; preserve guidance and unrelated config. For a
|
|
280
283
|
framework surface, separately record the operator's approved sidebar owner via
|
|
281
284
|
`oat config set documentation.navOwner nav-sync` or `hand-authored`. Missing
|
|
@@ -315,21 +318,28 @@ after each block, preserving residual findings instead of claiming a clean run.
|
|
|
315
318
|
#### Individually approved tooling update
|
|
316
319
|
|
|
317
320
|
A `tooling-update` recommendation has `approval: explicit`. Even with individual
|
|
318
|
-
approval, its out-of-Markdown allowance is only these
|
|
319
|
-
|
|
320
|
-
1. Bump the docs app's existing `@open-agent-toolkit/docs-*` dependencies
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
321
|
+
approval, its out-of-Markdown allowance is only these four operations:
|
|
322
|
+
|
|
323
|
+
1. Bump the docs app's existing `@open-agent-toolkit/docs-*` dependencies, and the
|
|
324
|
+
app's own `@open-agent-toolkit/cli` dependency when the app declares it, to the
|
|
325
|
+
bundled versions using the artifact's exact upgrade commands (preserve each
|
|
326
|
+
dependency section and the package manager; include the resulting lockfile only).
|
|
327
|
+
Run the pinned package-manager form the command gives; a global pnpm of another
|
|
328
|
+
major can rewrite workspace settings and break the store link.
|
|
329
|
+
Never downgrade an installed version: `ahead` or `unverified` requires CLI
|
|
330
|
+
selection/update or manual verification before re-analysis, not a tooling update.
|
|
331
|
+
2. After a CLI bump, regenerate the app's generated manifest (`index.md`) with that
|
|
332
|
+
upgraded app-local CLI, using the `oat docs generate-index` invocation from the
|
|
333
|
+
app's existing `predev`/`prebuild` scripts; inspect the diff.
|
|
334
|
+
3. Run `oat docs migrate --docs-dir <authored-root> --apply` only for its currently
|
|
326
335
|
supported admonition conversions and injected frontmatter; inspect the diff.
|
|
327
|
-
|
|
336
|
+
4. Run the docs build verifier from the app's existing scripts.
|
|
328
337
|
|
|
329
338
|
Scaffold changes the CLI cannot make (app config, routes, package scripts) are
|
|
330
339
|
`manual`: report the required change and ID without editing those files. This
|
|
331
|
-
allowance does not permit application dependencies,
|
|
332
|
-
migrations or an app-shell rebuild. Other out-of-scope
|
|
340
|
+
allowance does not permit other application dependencies, framework upgrades,
|
|
341
|
+
host settings, arbitrary migrations or an app-shell rebuild. Other out-of-scope
|
|
342
|
+
prohibitions remain.
|
|
333
343
|
|
|
334
344
|
When approved actions involve docs app creation or nav updates:
|
|
335
345
|
|
|
@@ -85,8 +85,9 @@ blocked pending a fresh analysis rather than guessed.
|
|
|
85
85
|
|
|
86
86
|
- Record IA: {adoption.state from target pjm doctor; decision command/path;
|
|
87
87
|
framework AGENTS or Markdown contributing section; shared mirror JSON}
|
|
88
|
-
- Tooling update: {individually approved ID; exact docs-app docs-\*
|
|
89
|
-
|
|
88
|
+
- Tooling update: {individually approved ID; exact docs-app docs-\* and declared
|
|
89
|
+
app-local cli upgrade commands; manifest regeneration with that cli; supported
|
|
90
|
+
migrate conversions; existing build verifier}
|
|
90
91
|
- Unsupported app config/routes/scripts: {manual required changes; no edits}
|
|
91
92
|
|
|
92
93
|
## Summary of Actions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAIhF,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"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"}
|