diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 49457378b..8c3078530 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -27,7 +27,7 @@ ## Tool Contract Impact - + ## Related Issues diff --git a/AGENTS.md b/AGENTS.md index fc8505ae7..89a92d735 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,7 +26,7 @@ See [docs/architecture.mermaid](docs/architecture.mermaid) for a visual architec - `src/cli.ts`: one-shot CLI adapter for setup, diagnostics, analysis, and decompilation. - `src/config.ts`: Zod-validated parsing of environment configuration into `AppConfig`. - `src/domain/`: pure, side-effect-free modules. `errors.ts` owns the tagged error algebra; `result.ts` owns `Result`/`ok`/`err`; `hopperValues.ts` owns shared function-dossier values plus Hopper boundary parsers; `symbolAnalysis.ts` parses Swift/ObjC names; `javascriptApplicationGraph.ts` validates and canonically commits the provider-neutral JavaScript Application Graph; `javascriptStaticAnalysis.ts` performs bounded AST-only JavaScript structure recovery. -- `src/contracts/`: caller-visible schemas for 33 direct, 10 enhanced, 5 native, 2 artifact, 6 managed, 8 browser, 4 Electron, 3 application, and 18 session tools; `enhancedInputs.ts` owns enhanced input parsing. +- `src/contracts/`: caller-visible tool schemas and catalog metadata; `toolContracts.ts` owns the canonical inventory and `enhancedInputs.ts` owns enhanced input parsing. - `src/process/`: provider-neutral process ownership and lifecycle primitives. It owns private runtime roots, absolute startup deadlines, correlated request waits, bounded output capture, and TERM-to-KILL cleanup without defining any provider wire protocol. - `src/replay/`: Linux x64 controlled-JavaScript-replay adapter. It owns exact runtime closure inspection, Bubblewrap/seccomp/cgroup admission, the disposable worker, strict parent/worker protocol validation, and complete cleanup observation. - `src/browser/`: loopback CDP discovery, bounded WebSocket transport, exact-origin target authorization, and passive browser observation normalization. @@ -47,13 +47,14 @@ See [docs/architecture.mermaid](docs/architecture.mermaid) for a visual architec ## Build, Test, and Development Commands - `npm ci`: install exact lockfile dependencies. +- `npm run deps:check`: verify that installed direct dependency versions match the root lockfile; on failure, run `npm ci`, then retry. - `npm run build`: compile `src/` into `dist/`. - `npm test`: build, then run the Vitest suite once. - `npm run typecheck`: run strict TypeScript checks without emitting files. - `npm run lint`: apply oxlint rules (complexity, max-lines, unused vars, and TypeScript-specific checks). - `npm run lint:fix`: auto-fix oxlint violations where possible. - `npm run format:check`: verify Prettier formatting. -- `npm run check`: run typecheck, lint, format:check, and tests. +- `npm run check`: run typecheck, lint, format:check, generated-document freshness checks, and tests. - `npm run knip`: detect unused files, dependencies, and exports. - `npm run jscpd`: detect duplicate code blocks. - `npm run scan:todos`: scan for TODO, FIXME, and HACK markers. @@ -62,7 +63,7 @@ See [docs/architecture.mermaid](docs/architecture.mermaid) for a visual architec - `npm run verify:browser`: build and run the real Chrome verifier against `REA_BROWSER_EXECUTABLE` or a platform-default Chrome-family executable. - `npm run verify:managed`: build and run the source-owned managed PE/CLI conformance verifier for artifact triage, member inspection, managed/native boundary declarations, token drift comparison, malformed metadata, and non-managed degradation. - `npm run verify:replay`: build and run the real Linux Bubblewrap/seccomp/cgroup verifier against source-owned replay fixtures; set `REA_REPLAY_INPUT_PATH` to verify an operator-local manifest. -- `npm run verify:package`: pack and test the CLI, setup transaction, skill, and 89-tool target-free MCP server in an isolated environment. +- `npm run verify:package`: pack and test the CLI, setup transaction, skill, and canonical target-free MCP catalog in an isolated environment. - `npm run docs:generate`: generate API documentation from JSDoc comments into `docs/api/` using TypeDoc. - `npm run docs:check`: verify generated package metadata, the canonical product catalog, caller-visible documentation facts, TypeDoc output, and the error JSON schema without rewriting them. - `npm run config:print -- /path/to/binary`: print an MCP server config with absolute paths. @@ -96,7 +97,9 @@ Use ESM TypeScript, two-space indentation, and Prettier defaults. Keep compiler ## Testing Guidelines -Name tests `*.test.ts`. Use Vitest and production seams (`tests/fixtures/`) rather than module mocks. Domain tests assert pure behavior; adapter tests use fake launcher/socket seams; MCP tests connect with the beta.3 client. Preserve the 33 direct, 10 enhanced, 5 native, 2 artifact, 6 managed, 8 browser, 4 Electron, 3 application, and 18 session tool inventory (89 total). Cover malformed input, cancellation, timeouts, process exit, concurrency, limits, and clean shutdown. Real Hopper, Ghidra, browser, JavaScript replay, managed conformance, and any real managed-tool claims cannot be replaced by mocks; use the corresponding `verify:*` command. +Name tests `*.test.ts`. Use Vitest and production seams (`tests/fixtures/`) rather than module mocks. Domain tests assert pure behavior; adapter tests use fake launcher/socket seams; MCP tests connect with the client SDK version pinned in `package.json`. Preserve the canonical tool inventory defined by `TOOL_CONTRACTS` and verified through `CATALOG_IDENTITY` and generated product metadata. Cover malformed input, cancellation, timeouts, process exit, concurrency, limits, and clean shutdown. Real Hopper, Ghidra, browser, JavaScript replay, managed conformance, and any real managed-tool claims cannot be replaced by mocks; use the corresponding `verify:*` command. + +MCP tool catalogs must remain complete and self-describing. Prefer capability- and session-scoped tool advertisement over schema truncation. Do not impose arbitrary serialized-byte ceilings on tool schemas or `tools/list`; assess model-context cost only against a named client's actual model-facing projection and tokenizer. ## Commit & Pull Request Guidelines diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 666caaedf..36bfddcbe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,7 +17,7 @@ the package `prepare` lifecycle, and prepares the Husky hook. Run `npm run build` again after source changes when you need the standalone CLI or MCP server without running the test prebuild. -Keep dependencies flowing inward through the existing domain, contracts, provider, application, server, and adapter layers. Parse unknown values at process and protocol boundaries, model expected failures with `Result`, and preserve the 33 direct, 10 enhanced, 5 native, 2 artifact, 8 browser, 4 Electron, 2 application workflow, and 18 session tools (82 total) unless a deliberate contract change updates every verifier and snapshot. +Keep dependencies flowing inward through the existing domain, contracts, provider, application, server, and adapter layers. Parse unknown values at process and protocol boundaries, model expected failures with `Result`, and preserve the canonical tool inventory defined by `TOOL_CONTRACTS` unless a deliberate contract change updates every verifier, generated catalog artifact, and snapshot. Prefer capability- and session-scoped tool advertisement over schema truncation. Before submitting a pull request, run: @@ -75,7 +75,7 @@ Publish the public package: npm publish --access public ``` -After npm registry propagation, verify the published CLI and connect a beta.3 MCP client to the published server to confirm all 82 tools: +After npm registry propagation, verify the published CLI and connect the client SDK version pinned in `package.json` to the published server to confirm the canonical tool catalog: ```bash npx -y rea-agents --help diff --git a/docs/mcp-schema-report.json b/docs/mcp-schema-report.json deleted file mode 100644 index edd6f7449..000000000 --- a/docs/mcp-schema-report.json +++ /dev/null @@ -1,539 +0,0 @@ -{ - "generated_from": "@modelcontextprotocol/server 2.0.0-beta.4 wire registration", - "tool_count": 88, - "tools_list_bytes": 517143, - "budgets": { - "tools_list_bytes": 524288, - "per_tool_bytes": 65536 - }, - "tools": [ - { - "name": "address_name", - "bytes": 1133, - "input_schema_bytes": 401, - "output_schema_bytes": 313 - }, - { - "name": "analyze_function", - "bytes": 8935, - "input_schema_bytes": 2037, - "output_schema_bytes": 6421 - }, - { - "name": "analyze_javascript_application", - "bytes": 17446, - "input_schema_bytes": 2633, - "output_schema_bytes": 14172 - }, - { - "name": "analyze_swift_types", - "bytes": 1321, - "input_schema_bytes": 62, - "output_schema_bytes": 852 - }, - { - "name": "analyze_web_bundle", - "bytes": 14276, - "input_schema_bytes": 6550, - "output_schema_bytes": 7221 - }, - { - "name": "batch_decompile", - "bytes": 10638, - "input_schema_bytes": 226, - "output_schema_bytes": 10011 - }, - { - "name": "binary_overview", - "bytes": 1620, - "input_schema_bytes": 250, - "output_schema_bytes": 954 - }, - { - "name": "binary_session", - "bytes": 11822, - "input_schema_bytes": 367, - "output_schema_bytes": 10955 - }, - { - "name": "build_call_path", - "bytes": 10235, - "input_schema_bytes": 6850, - "output_schema_bytes": 2913 - }, - { - "name": "capture_process_scenario", - "bytes": 19830, - "input_schema_bytes": 10303, - "output_schema_bytes": 8773 - }, - { - "name": "capture_web_screenshot", - "bytes": 5389, - "input_schema_bytes": 771, - "output_schema_bytes": 4182 - }, - { - "name": "close_binary", - "bytes": 1073, - "input_schema_bytes": 214, - "output_schema_bytes": 379 - }, - { - "name": "comment", - "bytes": 1082, - "input_schema_bytes": 401, - "output_schema_bytes": 313 - }, - { - "name": "compare_application_versions", - "bytes": 24888, - "input_schema_bytes": 9296, - "output_schema_bytes": 15024 - }, - { - "name": "compare_artifacts", - "bytes": 3869, - "input_schema_bytes": 759, - "output_schema_bytes": 2625 - }, - { - "name": "compare_bundles", - "bytes": 4169, - "input_schema_bytes": 928, - "output_schema_bytes": 2742 - }, - { - "name": "compare_functions", - "bytes": 4356, - "input_schema_bytes": 725, - "output_schema_bytes": 3139 - }, - { - "name": "compare_managed_members", - "bytes": 7583, - "input_schema_bytes": 960, - "output_schema_bytes": 6099 - }, - { - "name": "compare_process_captures", - "bytes": 3311, - "input_schema_bytes": 565, - "output_schema_bytes": 2161 - }, - { - "name": "compare_web_captures", - "bytes": 29996, - "input_schema_bytes": 27683, - "output_schema_bytes": 1873 - }, - { - "name": "compare_web_screenshots", - "bytes": 3351, - "input_schema_bytes": 1412, - "output_schema_bytes": 1546 - }, - { - "name": "correlate_static_and_runtime", - "bytes": 12426, - "input_schema_bytes": 8307, - "output_schema_bytes": 3626 - }, - { - "name": "current_address", - "bytes": 938, - "input_schema_bytes": 282, - "output_schema_bytes": 285 - }, - { - "name": "current_document", - "bytes": 842, - "input_schema_bytes": 219, - "output_schema_bytes": 285 - }, - { - "name": "current_procedure", - "bytes": 952, - "input_schema_bytes": 282, - "output_schema_bytes": 285 - }, - { - "name": "demangle_swift", - "bytes": 2276, - "input_schema_bytes": 221, - "output_schema_bytes": 1717 - }, - { - "name": "discover_webmcp_tools", - "bytes": 6797, - "input_schema_bytes": 1087, - "output_schema_bytes": 5306 - }, - { - "name": "export_evidence_bundle", - "bytes": 11008, - "input_schema_bytes": 196, - "output_schema_bytes": 10384 - }, - { - "name": "extract_artifact", - "bytes": 6212, - "input_schema_bytes": 1321, - "output_schema_bytes": 4499 - }, - { - "name": "find_changed_behavior", - "bytes": 12036, - "input_schema_bytes": 8540, - "output_schema_bytes": 2968 - }, - { - "name": "find_xrefs_to_name", - "bytes": 1346, - "input_schema_bytes": 128, - "output_schema_bytes": 763 - }, - { - "name": "get_call_graph", - "bytes": 10619, - "input_schema_bytes": 361, - "output_schema_bytes": 9786 - }, - { - "name": "get_objc_classes", - "bytes": 1141, - "input_schema_bytes": 127, - "output_schema_bytes": 606 - }, - { - "name": "get_objc_protocols", - "bytes": 1079, - "input_schema_bytes": 62, - "output_schema_bytes": 610 - }, - { - "name": "goto_address", - "bytes": 1094, - "input_schema_bytes": 424, - "output_schema_bytes": 285 - }, - { - "name": "import_evidence_bundle", - "bytes": 882, - "input_schema_bytes": 142, - "output_schema_bytes": 321 - }, - { - "name": "inline_comment", - "bytes": 1064, - "input_schema_bytes": 401, - "output_schema_bytes": 313 - }, - { - "name": "inspect_electron_page", - "bytes": 9514, - "input_schema_bytes": 1936, - "output_schema_bytes": 7118 - }, - { - "name": "inspect_macho", - "bytes": 7672, - "input_schema_bytes": 62, - "output_schema_bytes": 7237 - }, - { - "name": "inspect_managed_artifact", - "bytes": 11489, - "input_schema_bytes": 1251, - "output_schema_bytes": 9754 - }, - { - "name": "inspect_managed_members", - "bytes": 13925, - "input_schema_bytes": 2048, - "output_schema_bytes": 11387 - }, - { - "name": "inspect_managed_native_boundaries", - "bytes": 9704, - "input_schema_bytes": 1267, - "output_schema_bytes": 7912 - }, - { - "name": "inspect_plist", - "bytes": 2769, - "input_schema_bytes": 189, - "output_schema_bytes": 2206 - }, - { - "name": "inspect_signature", - "bytes": 2793, - "input_schema_bytes": 62, - "output_schema_bytes": 2366 - }, - { - "name": "inspect_web_page", - "bytes": 21829, - "input_schema_bytes": 5042, - "output_schema_bytes": 16277 - }, - { - "name": "inventory_artifact", - "bytes": 9791, - "input_schema_bytes": 1885, - "output_schema_bytes": 7519 - }, - { - "name": "list_architectures", - "bytes": 2555, - "input_schema_bytes": 62, - "output_schema_bytes": 2160 - }, - { - "name": "list_bookmarks", - "bytes": 1091, - "input_schema_bytes": 282, - "output_schema_bytes": 437 - }, - { - "name": "list_browser_targets", - "bytes": 2950, - "input_schema_bytes": 658, - "output_schema_bytes": 1844 - }, - { - "name": "list_documents", - "bytes": 883, - "input_schema_bytes": 219, - "output_schema_bytes": 310 - }, - { - "name": "list_electron_targets", - "bytes": 2869, - "input_schema_bytes": 636, - "output_schema_bytes": 1810 - }, - { - "name": "list_names", - "bytes": 2786, - "input_schema_bytes": 594, - "output_schema_bytes": 1762 - }, - { - "name": "list_procedures", - "bytes": 2683, - "input_schema_bytes": 475, - "output_schema_bytes": 1762 - }, - { - "name": "list_segments", - "bytes": 2656, - "input_schema_bytes": 282, - "output_schema_bytes": 1967 - }, - { - "name": "list_strings", - "bytes": 2781, - "input_schema_bytes": 594, - "output_schema_bytes": 1762 - }, - { - "name": "list_unknowns", - "bytes": 4279, - "input_schema_bytes": 358, - "output_schema_bytes": 3512 - }, - { - "name": "next_address", - "bytes": 1039, - "input_schema_bytes": 401, - "output_schema_bytes": 285 - }, - { - "name": "observe_web_session", - "bytes": 5976, - "input_schema_bytes": 765, - "output_schema_bytes": 4746 - }, - { - "name": "open_binary", - "bytes": 1702, - "input_schema_bytes": 386, - "output_schema_bytes": 696 - }, - { - "name": "plan_managed_runtime_correlation", - "bytes": 7556, - "input_schema_bytes": 2128, - "output_schema_bytes": 4768 - }, - { - "name": "prev_address", - "bytes": 1045, - "input_schema_bytes": 401, - "output_schema_bytes": 285 - }, - { - "name": "procedure_address", - "bytes": 1082, - "input_schema_bytes": 383, - "output_schema_bytes": 285 - }, - { - "name": "procedure_assembly", - "bytes": 1096, - "input_schema_bytes": 383, - "output_schema_bytes": 285 - }, - { - "name": "procedure_callees", - "bytes": 1121, - "input_schema_bytes": 383, - "output_schema_bytes": 310 - }, - { - "name": "procedure_callers", - "bytes": 1085, - "input_schema_bytes": 383, - "output_schema_bytes": 310 - }, - { - "name": "procedure_info", - "bytes": 1982, - "input_schema_bytes": 383, - "output_schema_bytes": 1216 - }, - { - "name": "procedure_pseudo_code", - "bytes": 1172, - "input_schema_bytes": 383, - "output_schema_bytes": 313 - }, - { - "name": "procedure_references", - "bytes": 4192, - "input_schema_bytes": 798, - "output_schema_bytes": 2927 - }, - { - "name": "reconcile_javascript_runtime", - "bytes": 27214, - "input_schema_bytes": 8993, - "output_schema_bytes": 17696 - }, - { - "name": "record_unknown", - "bytes": 6527, - "input_schema_bytes": 2646, - "output_schema_bytes": 3487 - }, - { - "name": "resolve_containing_procedure", - "bytes": 2185, - "input_schema_bytes": 424, - "output_schema_bytes": 1280 - }, - { - "name": "run_controlled_replay", - "bytes": 19234, - "input_schema_bytes": 5922, - "output_schema_bytes": 12725 - }, - { - "name": "search_procedures", - "bytes": 2215, - "input_schema_bytes": 812, - "output_schema_bytes": 941 - }, - { - "name": "search_strings", - "bytes": 2224, - "input_schema_bytes": 812, - "output_schema_bytes": 941 - }, - { - "name": "set_address_name", - "bytes": 1141, - "input_schema_bytes": 478, - "output_schema_bytes": 286 - }, - { - "name": "set_addresses_names", - "bytes": 1175, - "input_schema_bytes": 427, - "output_schema_bytes": 361 - }, - { - "name": "set_bookmark", - "bytes": 1118, - "input_schema_bytes": 471, - "output_schema_bytes": 286 - }, - { - "name": "set_comment", - "bytes": 1148, - "input_schema_bytes": 487, - "output_schema_bytes": 286 - }, - { - "name": "set_current_document", - "bytes": 1003, - "input_schema_bytes": 298, - "output_schema_bytes": 285 - }, - { - "name": "set_inline_comment", - "bytes": 1142, - "input_schema_bytes": 487, - "output_schema_bytes": 286 - }, - { - "name": "swift_classes", - "bytes": 1135, - "input_schema_bytes": 127, - "output_schema_bytes": 606 - }, - { - "name": "trace_application_feature", - "bytes": 24958, - "input_schema_bytes": 8688, - "output_schema_bytes": 15739 - }, - { - "name": "trace_feature", - "bytes": 3340, - "input_schema_bytes": 555, - "output_schema_bytes": 2299 - }, - { - "name": "unset_bookmark", - "bytes": 1055, - "input_schema_bytes": 424, - "output_schema_bytes": 286 - }, - { - "name": "update_unknown", - "bytes": 7572, - "input_schema_bytes": 3696, - "output_schema_bytes": 3487 - }, - { - "name": "verify_reconstruction", - "bytes": 6161, - "input_schema_bytes": 2455, - "output_schema_bytes": 3212 - }, - { - "name": "verify_unknown_resolution", - "bytes": 4283, - "input_schema_bytes": 177, - "output_schema_bytes": 3668 - }, - { - "name": "xrefs", - "bytes": 1112, - "input_schema_bytes": 401, - "output_schema_bytes": 310 - } - ] -} diff --git a/package.json b/package.json index 761338fe2..6c39fd456 100644 --- a/package.json +++ b/package.json @@ -87,9 +87,8 @@ "verify:package": "npm run build && node scripts/verify-package.mjs", "verify:published": "node scripts/verify-published-package.mjs", "config:print": "node scripts/print-mcp-config.mjs", - "docs:generate": "npm run build && node scripts/generate-skill-metadata.mjs && node scripts/generate-mcp-schema-report.mjs && node scripts/generate-product-catalog.mjs && typedoc && node scripts/generate-error-schema.mjs", - "docs:check": "node scripts/generate-package-metadata.mjs --check && npm run build && node scripts/generate-skill-metadata.mjs --check && node scripts/generate-mcp-schema-report.mjs --check && node scripts/generate-product-catalog.mjs --check && node scripts/check-doc-facts.mjs && node scripts/check-typedoc.mjs && node scripts/generate-error-schema.mjs --check", - "schemas:report": "npm run build && node scripts/generate-mcp-schema-report.mjs", + "docs:generate": "npm run build && node scripts/generate-skill-metadata.mjs && node scripts/generate-product-catalog.mjs && typedoc && node scripts/generate-error-schema.mjs", + "docs:check": "node scripts/generate-package-metadata.mjs --check && npm run build && node scripts/generate-skill-metadata.mjs --check && node scripts/generate-product-catalog.mjs --check && node scripts/check-doc-facts.mjs && node scripts/check-typedoc.mjs && node scripts/generate-error-schema.mjs --check", "docs:error-schema": "npm run build && node scripts/generate-error-schema.mjs", "prepack": "npm run deps:check && node scripts/generate-skill-metadata.mjs --check", "prepublishOnly": "npm run deps:check && node scripts/generate-skill-metadata.mjs --check", diff --git a/scripts/generate-mcp-schema-report.mjs b/scripts/generate-mcp-schema-report.mjs deleted file mode 100644 index 808b75710..000000000 --- a/scripts/generate-mcp-schema-report.mjs +++ /dev/null @@ -1,69 +0,0 @@ -import { Buffer } from "node:buffer"; -import { dirname, join } from "node:path"; -import { fileURLToPath, pathToFileURL } from "node:url"; - -import { ensureGeneratedFile } from "./lib/generated-file.mjs"; - -const arguments_ = new Set(process.argv.slice(2)); -for (const argument of arguments_) - if (argument !== "--check") - throw new Error(`Unknown MCP schema report option: ${argument}`); - -const root = join(dirname(fileURLToPath(import.meta.url)), ".."); -const cachebuster = `?${String(Date.now())}`; -const { TOOL_CONTRACTS } = await import( - `${pathToFileURL(join(root, "dist/contracts/toolContracts.js")).href}${cachebuster}` -); -const { toolRegistrationOptions } = await import( - `${pathToFileURL(join(root, "dist/server/toolRegistrationOptions.js")).href}${cachebuster}` -); - -const bytes = (value) => Buffer.byteLength(JSON.stringify(value), "utf8"); -const tools = TOOL_CONTRACTS.map((contract) => { - const registration = toolRegistrationOptions(contract); - const inputSchema = registration.inputSchema["~standard"].jsonSchema.input(); - const outputSchema = - registration.outputSchema["~standard"].jsonSchema.output(); - const wire = { - name: contract.name, - title: registration.title, - description: registration.description, - inputSchema, - outputSchema, - annotations: registration.annotations, - }; - return { - name: contract.name, - bytes: bytes(wire), - input_schema_bytes: bytes(inputSchema), - output_schema_bytes: bytes(outputSchema), - wire, - }; -}).sort((left, right) => left.name.localeCompare(right.name)); - -const maximumToolBytes = 64 * 1024; -const maximumListBytes = 512 * 1024; -const listBytes = bytes({ tools: tools.map(({ wire }) => wire) }); -const oversized = tools.filter((tool) => tool.bytes > maximumToolBytes); -if (oversized.length > 0 || listBytes > maximumListBytes) - throw new Error( - `MCP schema budget exceeded: tools/list=${String(listBytes)}, oversized=${oversized.map(({ name, bytes: size }) => `${name}:${String(size)}`).join(",")}`, - ); - -const report = { - generated_from: "@modelcontextprotocol/server 2.0.0-beta.4 wire registration", - tool_count: tools.length, - tools_list_bytes: listBytes, - budgets: { - tools_list_bytes: maximumListBytes, - per_tool_bytes: maximumToolBytes, - }, - tools: tools.map(({ wire: _wire, ...tool }) => tool), -}; - -await ensureGeneratedFile({ - path: join(root, "docs/mcp-schema-report.json"), - source: `${JSON.stringify(report, null, 2)}\n`, - check: arguments_.has("--check"), - generateCommand: "npm run docs:generate", -}); diff --git a/scripts/lib/docs-facts.mjs b/scripts/lib/docs-facts.mjs index 3c14951b2..0aed20f37 100644 --- a/scripts/lib/docs-facts.mjs +++ b/scripts/lib/docs-facts.mjs @@ -8,8 +8,6 @@ const README_PATHS = [ "README_ko.md", "README_ar.md", ]; -const familyLabel = (id) => (id === "electron" ? "Electron" : id); - const tableCounts = (content, path, expectedCounts) => { const lines = content.split(/\r?\n/u); for (const [index, line] of lines.entries()) { @@ -50,37 +48,11 @@ export const documentationFactIssues = async (root, catalog) => { } } - const inventory = catalog.tools.families - .map(({ id, count }) => `${String(count)} ${familyLabel(id)}`) - .join(", ") - .replace(/, ([^,]+)$/u, ", and $1"); - const plusInventory = catalog.tools.families - .map(({ id, count }) => `${String(count)} ${familyLabel(id)}`) - .join(" + "); const agents = await readFile(join(root, "AGENTS.md"), "utf8"); - requireText(issues, "AGENTS.md", agents, inventory); - requireText( - issues, - "AGENTS.md", - agents, - `(${String(catalog.tools.total)} total)`, - ); - requireText( - issues, - "AGENTS.md", - agents, - `${String(catalog.tools.total)}-tool target-free MCP server`, - ); requireText(issues, "AGENTS.md", agents, "docs/product-catalog.json"); const templatePath = ".github/pull_request_template.md"; const template = await readFile(join(root, templatePath), "utf8"); - requireText( - issues, - templatePath, - template, - `current inventory is ${String(catalog.tools.total)} tools (${plusInventory})`, - ); requireText(issues, templatePath, template, "docs/product-catalog.json"); const english = await readFile(join(root, "README.md"), "utf8"); diff --git a/tests/createServer.test.ts b/tests/createServer.test.ts index d1eb97334..219a2e1a0 100644 --- a/tests/createServer.test.ts +++ b/tests/createServer.test.ts @@ -8,7 +8,7 @@ const analysis = { execute: () => Promise.resolve(ok(null)), }; -describe("beta.3 server composition", () => { +describe("MCP server composition", () => { it("constructs independent MCP server instances", () => { expect(createServer(analysis)).not.toBe(createServer(analysis)); }); diff --git a/tests/productCatalog.test.ts b/tests/productCatalog.test.ts index c8fbd6f10..d34ced48b 100644 --- a/tests/productCatalog.test.ts +++ b/tests/productCatalog.test.ts @@ -170,11 +170,19 @@ describe("canonical product catalog", () => { } }); - it("reports tool, setup-client, and schema fact drift", async () => { + it("reports tool-family, setup-client, and schema fact drift", async () => { const catalog = await createProductCatalog(root); + const firstFamily = catalog.tools.families[0]; + if (firstFamily === undefined) throw new TypeError("Missing tool family"); const drifted = { ...catalog, - tools: { ...catalog.tools, total: catalog.tools.total + 1 }, + tools: { + ...catalog.tools, + families: [ + { ...firstFamily, count: firstFamily.count + 1 }, + ...catalog.tools.families.slice(1), + ], + }, setup_clients: [ ...catalog.setup_clients, { @@ -191,11 +199,9 @@ describe("canonical product catalog", () => { ), }; const issues = await documentationFactIssues(root, drifted); - expect( - issues.some((issue) => - issue.includes(`${String(catalog.tools.total + 1)}-tool`), - ), - ).toBe(true); + expect(issues.some((issue) => issue.includes("tool family counts"))).toBe( + true, + ); expect(issues.some((issue) => issue.includes("Future Client"))).toBe(true); expect(issues.some((issue) => issue.includes("Process Capture v5"))).toBe( true,