@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.
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "oatVersion": "0.3.11"
3
+ "oatVersion": "0.3.12"
4
4
  }
@@ -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` and is listed there as not reviewed. A review's
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
@@ -1,6 +1,6 @@
1
1
  {
2
- "cli": "0.3.11",
3
- "docs-config": "0.3.11",
4
- "docs-theme": "0.3.11",
5
- "docs-transforms": "0.3.11"
2
+ "cli": "0.3.12",
3
+ "docs-config": "0.3.12",
4
+ "docs-theme": "0.3.12",
5
+ "docs-transforms": "0.3.12"
6
6
  }
@@ -6,7 +6,7 @@ disable-model-invocation: true
6
6
  user-invocable: true
7
7
  allowed-tools: Read, Write, Glob, Grep, Bash, AskUserQuestion, Agent, mcp__*
8
8
  metadata:
9
- version: 1.1.6
9
+ version: 1.1.7
10
10
  ---
11
11
 
12
12
  # Recon
@@ -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
- // The required reviews that gave `claimId` no disposition at all. Such a
125
- // claim stays below `verified`, like an uncertain one, and is listed as not
126
- // reviewed.
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 requiredReviewKinds
129
- .map((kind) => reviews.find((review) => review.reviewKind === kind))
145
+ return reviews
130
146
  .filter(
131
- (review) =>
132
- review &&
133
- !(review.dispositions ?? []).some((item) => item.claimId === claimId),
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 a required review that left it without a
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, reviews)) {
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;AAiDD;;;;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;AAoMD;;;;;;;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"}
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
- if (item.startsWith('[')) {
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.11",
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.11"
37
+ "@open-agent-toolkit/control-plane": "0.3.12"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/node": "^22.10.0",