@open-agent-toolkit/cli 0.3.11 → 0.3.12
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/reference/docs-index-contract.md +1 -0
- package/assets/docs/workflows/skills/recon.md +4 -1
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/recon/SKILL.md +1 -1
- package/assets/skills/recon/scripts/render-packet.mjs +40 -13
- package/dist/commands/docs/nav/fumadocs.d.ts +7 -0
- package/dist/commands/docs/nav/fumadocs.d.ts.map +1 -1
- package/dist/commands/docs/nav/fumadocs.js +28 -3
- package/package.json +2 -2
|
@@ -63,6 +63,7 @@ Fumadocs generated behavior:
|
|
|
63
63
|
- `pages` follows the order of the directory's `## Contents` links. The root list starts with `index`; a child directory appears by its folder name, and its own `index.md` becomes that folder's landing page. A folder whose `meta.json` keeps `root: true` also lists `index` first, because Fumadocs gives a root folder no implicit landing page.
|
|
64
64
|
- Navigation is strict: there is no `"..."` rest entry. A page or folder that no `## Contents` map lists stays out of the sidebar, and the command reports it by path in its human output and in `--json` (`unlisted`). Add the page to its directory's `## Contents` map to show it.
|
|
65
65
|
- A `## Contents` link to a page in another directory is written as a Fumadocs link entry such as `[Writing Skills](/contributing/skills)`, so each page belongs to exactly one folder.
|
|
66
|
+
- A page or folder whose name Fumadocs would read as a `pages` directive, such as `!hidden`, `z...a`, `...name`, or `---`, is written in the local-path form `./!hidden` so it stays a page entry.
|
|
66
67
|
- The folder `title` comes from the `index.md` frontmatter `title`, falling back to its first `#` heading.
|
|
67
68
|
- Keys nav sync does not own, such as `icon` or `defaultOpen`, are kept.
|
|
68
69
|
- Existing files are compared by meaning, not bytes, so a second run with no docs changes writes nothing, even after a formatter rewrites the files.
|
|
@@ -304,7 +304,10 @@ scoped to it or global to its review, a coverage finding that names it, or a
|
|
|
304
304
|
non-affirming disposition) is listed under Review Downgrades with the review's
|
|
305
305
|
own text, even when it is not a key claim, so a `complete` packet cannot hide a
|
|
306
306
|
downgraded claim. A claim that a required review left without a disposition stays
|
|
307
|
-
`unresolved
|
|
307
|
+
`unresolved`. Any claim below `verified` that an incorporated assurance review,
|
|
308
|
+
core or thorough, listed in its brief but left without a disposition is listed
|
|
309
|
+
there as not reviewed by that review; a claim outside a review's brief is never
|
|
310
|
+
reported as its omission. A review's
|
|
308
311
|
`unresolvedIssues` entry may name the claim IDs it affects or apply to the
|
|
309
312
|
whole review; a legacy plain-string entry is read as review-wide. A material
|
|
310
313
|
coverage gap does not fail publication by itself: the claims it affects stay
|
|
@@ -9,9 +9,9 @@ import { isDirectExecution } from './lib/cli-entry.mjs';
|
|
|
9
9
|
import {
|
|
10
10
|
affirmingDispositionByReviewKind,
|
|
11
11
|
classifyUnresolvedIssue,
|
|
12
|
-
requiredReviewKinds,
|
|
13
12
|
unresolvedIssuesBlockClaim,
|
|
14
13
|
} from './lib/contracts.mjs';
|
|
14
|
+
import { reviewBriefEntries } from './lib/review-binding.mjs';
|
|
15
15
|
import {
|
|
16
16
|
assertSafeExistingPath,
|
|
17
17
|
assertSafeOutputPath,
|
|
@@ -121,17 +121,34 @@ function intendedRoutingSection(manifest, routing) {
|
|
|
121
121
|
];
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
//
|
|
124
|
+
const assuranceReviewKinds = Object.keys(affirmingDispositionByReviewKind);
|
|
125
|
+
|
|
126
|
+
// The claim IDs a review was briefed on: the entries of the immutable brief
|
|
127
|
+
// its exact reference resolves to, read the way the validator reads them.
|
|
128
|
+
function briefedClaimIds(review, artifacts) {
|
|
129
|
+
const brief = artifacts.find(
|
|
130
|
+
({ reference, value }) =>
|
|
131
|
+
value.kind === 'recon.review-brief' &&
|
|
132
|
+
reference.path === review.brief?.path &&
|
|
133
|
+
reference.digest === review.brief?.digest,
|
|
134
|
+
)?.value;
|
|
135
|
+
return new Set(
|
|
136
|
+
reviewBriefEntries(brief, review.reviewKind).map((entry) => entry.id),
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Every incorporated assurance review, core or thorough, whose brief listed
|
|
141
|
+
// `claimId` but which gave it no disposition. Such a claim is listed as not
|
|
142
|
+
// reviewed. A claim outside a review's brief was never that review's to
|
|
143
|
+
// dispose of, so it is not an omission.
|
|
127
144
|
function omittedReviews(claimId, reviews) {
|
|
128
|
-
return
|
|
129
|
-
.map((kind) => reviews.find((review) => review.reviewKind === kind))
|
|
145
|
+
return reviews
|
|
130
146
|
.filter(
|
|
131
|
-
(
|
|
132
|
-
|
|
133
|
-
!(
|
|
134
|
-
)
|
|
147
|
+
({ value, briefed }) =>
|
|
148
|
+
briefed.has(claimId) &&
|
|
149
|
+
!(value.dispositions ?? []).some((item) => item.claimId === claimId),
|
|
150
|
+
)
|
|
151
|
+
.map(({ value }) => value);
|
|
135
152
|
}
|
|
136
153
|
|
|
137
154
|
function issueText(entry) {
|
|
@@ -140,8 +157,8 @@ function issueText(entry) {
|
|
|
140
157
|
|
|
141
158
|
// Every claim an incorporated review kept below `verified` (an unresolved
|
|
142
159
|
// issue that applies to it, a coverage finding that names it, a
|
|
143
|
-
// non-affirming disposition, or
|
|
144
|
-
// disposition), with the review's own words. Key-claim status
|
|
160
|
+
// non-affirming disposition, or an assurance review that left a briefed claim
|
|
161
|
+
// without a disposition), with the review's own words. Key-claim status
|
|
145
162
|
// alone would let a `complete` packet hide a downgraded non-key claim.
|
|
146
163
|
function reviewDowngradeLines(validatedRun) {
|
|
147
164
|
const { ledger, artifacts, assuranceReviewIds } = validatedRun;
|
|
@@ -152,6 +169,16 @@ function reviewDowngradeLines(validatedRun) {
|
|
|
152
169
|
(value) =>
|
|
153
170
|
value.kind === 'recon.review-result' && assurance.has(value.id),
|
|
154
171
|
);
|
|
172
|
+
// Claim-bearing assurance reviews in table order, each with its brief
|
|
173
|
+
// membership.
|
|
174
|
+
const briefedReviews = reviews
|
|
175
|
+
.filter((review) => assuranceReviewKinds.includes(review.reviewKind))
|
|
176
|
+
.map((value) => ({ value, briefed: briefedClaimIds(value, artifacts) }))
|
|
177
|
+
.sort(
|
|
178
|
+
(left, right) =>
|
|
179
|
+
assuranceReviewKinds.indexOf(left.value.reviewKind) -
|
|
180
|
+
assuranceReviewKinds.indexOf(right.value.reviewKind),
|
|
181
|
+
);
|
|
155
182
|
const lines = [];
|
|
156
183
|
for (const claim of ledger.claims) {
|
|
157
184
|
if (claim.status === 'verified') continue;
|
|
@@ -182,7 +209,7 @@ function reviewDowngradeLines(validatedRun) {
|
|
|
182
209
|
}
|
|
183
210
|
}
|
|
184
211
|
}
|
|
185
|
-
for (const review of omittedReviews(claim.id,
|
|
212
|
+
for (const review of omittedReviews(claim.id, briefedReviews)) {
|
|
186
213
|
reasons.push(
|
|
187
214
|
`${review.reviewKind} review: not reviewed (no disposition)`,
|
|
188
215
|
);
|
|
@@ -35,6 +35,13 @@ export interface SyncFumadocsNavigationResult {
|
|
|
35
35
|
export declare function stripInlineMarkdown(text: string): string;
|
|
36
36
|
/** Folder title: frontmatter `title`, else the first H1 outside code fences. */
|
|
37
37
|
export declare function resolveFolderTitle(markdown: string): string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* The `pages` item for a page or folder in the same directory. A name the
|
|
40
|
+
* builder would read as a directive (`!hidden`, `z...a`, `---`, ...) is
|
|
41
|
+
* written in the local-path form `./name`, which its path join resolves to
|
|
42
|
+
* the same file; every other name is written as is.
|
|
43
|
+
*/
|
|
44
|
+
export declare function toFumadocsPageItem(name: string): string;
|
|
38
45
|
/**
|
|
39
46
|
* Write one strict `meta.json` per docs directory that has an index.md,
|
|
40
47
|
* derived from that index's Contents map, and report every page the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fumadocs.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/nav/fumadocs.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,mEAAmE;IACnE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;OAGG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;OAGG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"fumadocs.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/nav/fumadocs.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,mEAAmE;IACnE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;OAGG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;OAGG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAyDD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQxD;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAoCvE;AA8BD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAoLD;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACpD,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAkExC"}
|
|
@@ -6,6 +6,13 @@ import { fileExists } from '../../../fs/io.js';
|
|
|
6
6
|
import { parseIndexContents, resolveEntryTarget } from './contents.js';
|
|
7
7
|
const PAGE_EXTENSIONS = ['.md', '.mdx'];
|
|
8
8
|
const GROUP_FOLDER = /^\(.+\)$/;
|
|
9
|
+
// The `pages` item grammar of the fumadocs-core 16.10.2 page-tree builder
|
|
10
|
+
// (`resolveFolderItem`): exact rest entries, separators, links, and the
|
|
11
|
+
// exclude and extract prefixes are checked before an item is read as a path.
|
|
12
|
+
const FUMADOCS_REST_ITEMS = new Set(['...', 'z...a']);
|
|
13
|
+
const FUMADOCS_SEPARATOR = /^---(?:\[(?<icon>[^\]]+)])?(?<name>.+)---|^---$/;
|
|
14
|
+
const FUMADOCS_LINK = /^(?<external>external:)?(?:\[(?<icon>[^\]]+)])?\[(?<name>[^\]]+)]\((?<url>[^)]+)\)$/;
|
|
15
|
+
const FUMADOCS_PREFIXES = ['!', '...'];
|
|
9
16
|
const H1 = /^#\s+(.+?)\s*#*\s*$/;
|
|
10
17
|
const FENCE = /^\s*(```|~~~)/;
|
|
11
18
|
function parentDir(path) {
|
|
@@ -105,6 +112,22 @@ function pageUrl(pagePath) {
|
|
|
105
112
|
}
|
|
106
113
|
return `/${slugs.join('/')}`;
|
|
107
114
|
}
|
|
115
|
+
/** Whether the Fumadocs page-tree builder reads `item` as a directive, not a path. */
|
|
116
|
+
function isFumadocsDirective(item) {
|
|
117
|
+
return (FUMADOCS_REST_ITEMS.has(item) ||
|
|
118
|
+
FUMADOCS_SEPARATOR.test(item) ||
|
|
119
|
+
FUMADOCS_LINK.test(item) ||
|
|
120
|
+
FUMADOCS_PREFIXES.some((prefix) => item.startsWith(prefix)));
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* The `pages` item for a page or folder in the same directory. A name the
|
|
124
|
+
* builder would read as a directive (`!hidden`, `z...a`, `---`, ...) is
|
|
125
|
+
* written in the local-path form `./name`, which its path join resolves to
|
|
126
|
+
* the same file; every other name is written as is.
|
|
127
|
+
*/
|
|
128
|
+
export function toFumadocsPageItem(name) {
|
|
129
|
+
return isFumadocsDirective(name) ? `./${name}` : name;
|
|
130
|
+
}
|
|
108
131
|
function hrefFragment(href) {
|
|
109
132
|
const hashIndex = href.indexOf('#');
|
|
110
133
|
return hashIndex >= 0 ? href.slice(hashIndex) : '';
|
|
@@ -150,10 +173,10 @@ async function buildFolderPages(docsRoot, relativeDir, markdown, implicitIndex)
|
|
|
150
173
|
}
|
|
151
174
|
else if (target.kind === 'section' &&
|
|
152
175
|
parentDir(targetDir) === relativeDir) {
|
|
153
|
-
item = basename(targetDir);
|
|
176
|
+
item = toFumadocsPageItem(basename(targetDir));
|
|
154
177
|
}
|
|
155
178
|
else if (target.kind === 'page' && targetDir === relativeDir) {
|
|
156
|
-
item = basename(target.path, extname(target.path));
|
|
179
|
+
item = toFumadocsPageItem(basename(target.path, extname(target.path)));
|
|
157
180
|
}
|
|
158
181
|
else {
|
|
159
182
|
item = `[${entry.title}](${pageUrl(target.path)}${hrefFragment(entry.href)})`;
|
|
@@ -209,7 +232,9 @@ function collectUnlisted(inventory, metas, implicitIndexDirs) {
|
|
|
209
232
|
reachablePages.add(index);
|
|
210
233
|
}
|
|
211
234
|
for (const item of meta.pages) {
|
|
212
|
-
|
|
235
|
+
// Read items the way the loader does: a directive (including a link
|
|
236
|
+
// entry) names no local page, and `./name` joins to `name`.
|
|
237
|
+
if (isFumadocsDirective(item)) {
|
|
213
238
|
continue;
|
|
214
239
|
}
|
|
215
240
|
const itemPath = posix.join(relativeDir, item);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-agent-toolkit/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.12",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Open Agent Toolkit CLI",
|
|
6
6
|
"homepage": "https://github.com/voxmedia/open-agent-toolkit/tree/main/packages/cli",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"ora": "^9.0.0",
|
|
35
35
|
"yaml": "2.8.2",
|
|
36
36
|
"zod": "^3.25.76",
|
|
37
|
-
"@open-agent-toolkit/control-plane": "0.3.
|
|
37
|
+
"@open-agent-toolkit/control-plane": "0.3.12"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^22.10.0",
|