diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a67dc9f7f..bd7f1e75d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,6 +4,14 @@ updates: directory: / schedule: interval: weekly + groups: + # website/ pins @rspress/core and @rspress/shared to the same exact + # version: plugins/mirror-api-locale.ts imports the slugger Rspress runs + # from @rspress/shared/github-slugger so heading ids match byte for byte, + # which only holds while the two move together. One PR per release. + rspress: + patterns: + - '@rspress/*' ignore: # typescript@7.0.x is a native compiler: import('typescript') is only # { version, versionMajorMinor }. website/rspress.config.ts, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 26ce5caed..9b36f3452 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -499,6 +499,9 @@ importers: '@rspress/plugin-typedoc': specifier: 2.0.21 version: 2.0.21(@rspress/core@2.0.21(patch_hash=555fe9cee718693c8c981e2ae0e282cb514a1808af1744dfab977ed7ca90fa2c)(@rspack/core@2.2.2(@swc/helpers@0.5.23))(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0))(supports-color@7.2.0))(typescript@6.0.3) + '@rspress/shared': + specifier: 2.0.21 + version: 2.0.21(supports-color@7.2.0) '@shikijs/transformers': specifier: 4.4.3 version: 4.4.3 diff --git a/website/docs/en/api/_meta.json b/website/docs/en/api/_meta.json index 7e39760cd..ac6fe7651 100644 --- a/website/docs/en/api/_meta.json +++ b/website/docs/en/api/_meta.json @@ -1,39 +1,82 @@ [ - "index", { - "type": "dir", - "name": "modules", - "label": "Modules", - "collapsed": true + "type": "file", + "name": "index", + "label": "agent-bundle" }, { - "type": "dir", - "name": "functions", - "label": "Functions", - "collapsed": true + "type": "file", + "name": "index-1", + "label": "index" }, { - "type": "dir", - "name": "classes", - "label": "Classes", - "collapsed": true + "type": "file", + "name": "config", + "label": "config" }, { - "type": "dir", - "name": "interfaces", - "label": "Interfaces", - "collapsed": true + "type": "file", + "name": "api", + "label": "api" }, { - "type": "dir", - "name": "types", - "label": "Type aliases", - "collapsed": true + "type": "file", + "name": "app", + "label": "app" }, { - "type": "dir", - "name": "variables", - "label": "Variables", - "collapsed": true + "type": "file", + "name": "routes/public", + "label": "routes/public" + }, + { + "type": "file", + "name": "test", + "label": "test" + }, + { + "type": "file", + "name": "test/browser", + "label": "test/browser" + }, + { + "type": "file", + "name": "eval", + "label": "eval" + }, + { + "type": "file", + "name": "rstest", + "label": "rstest" + }, + { + "type": "file", + "name": "mcp-apps", + "label": "mcp-apps" + }, + { + "type": "file", + "name": "mcp-entry", + "label": "mcp-entry" + }, + { + "type": "file", + "name": "cli-entry", + "label": "cli-entry" + }, + { + "type": "file", + "name": "serve-app-command", + "label": "serve-app-command" + }, + { + "type": "file", + "name": "launch-env", + "label": "launch-env" + }, + { + "type": "file", + "name": "meta", + "label": "meta" } ] diff --git a/website/docs/en/guide/authoring/index.mdx b/website/docs/en/guide/authoring/index.mdx index 67e350793..d946d6aca 100644 --- a/website/docs/en/guide/authoring/index.mdx +++ b/website/docs/en/guide/authoring/index.mdx @@ -102,7 +102,7 @@ handlers only. The adapter-owned fields are: | `claude` (`ClaudeHostConfig`) | `bin`, `channels`, `defaultEnabled`, `dependencies`, `displayName`, `lspServers`, `marketplace`, `metadata`, `monitors`, `outputStyles`, `settings`, `themes`, `userConfig`, `workflows` | `bin`, `outputStyles`, and `workflows` are project directories copied to the plugin-root conventions of the same name; `channels`, `dependencies`, `defaultEnabled`, `displayName`, `metadata`, and `userConfig` are validated into `.claude-plugin/plugin.json` (`channels` must name servers in the emitted `.mcp.json`); `marketplace` enriches the generated marketplace entry; `monitors` and `themes` are experimental and emit `monitors/monitors.json` and one `themes/.json` per key; `lspServers` and `settings` are described below. | | `codex` (`CodexHostConfig`) | `apps`, `author`, `homepage`, `interface`, `keywords`, `license`, `marketplace`, `repository` | `author`, `homepage`, `keywords`, `license`, and `repository` are publisher metadata in `.codex-plugin/plugin.json`; `interface` (brand color, category, capabilities, composer icon, default prompts, developer name, …) is merged over the compiler's generated install-surface defaults; `apps` maps registered MCP connection ids into the root `.app.json` compatibility document; `marketplace` authors the emitted `.agents/plugins/marketplace.json` entry — `category` (defaults to the interface category), `displayName` (defaults to the plugin name), and `policy` with `installation` (`AVAILABLE`, `INSTALLED_BY_DEFAULT`, `NOT_AVAILABLE`) and `authentication` (`ON_INSTALL`, `ON_USE`); the source always stays the local plugin root, and any other key is an error rather than a silently shipped field. | | `cursor` (`CursorHostConfig`) | `author`, `category`, `homepage`, `keywords`, `license`, `minClientVersions`, `publisher`, `repository`, `tags` | Manifest metadata layered onto the generated `.cursor-plugin/plugin.json`, every field admitted by the pinned Cursor plugin schema. `author` is a closed `{ name, email? }` object (no `url`); `minClientVersions` maps client identifiers to strict `X.Y.Z` semver strings, e.g. `{ cursor: '3.13.0' }`, and anything else is an error. Cursor documents no `nativeHooks` surface, so `cursor` does not extend `AgentBundleHostConfig`. | -| `portable` ([`PortableManifestConfig`](../../api/interfaces/index.PortableManifestConfig.md)) | `author`, `extensions`, `homepage`, `keywords`, `license`, `repository` | Agent Plugins 1.0.0 §5.4 metadata layered onto the emitted root `plugin.json`; `extensions` maps reverse-domain client namespaces to opaque object payloads (§8). Omitted fields are omitted from the manifest. | +| `portable` ([`PortableManifestConfig`](../../api/index-1.md#portablemanifestconfig)) | `author`, `extensions`, `homepage`, `keywords`, `license`, `repository` | Agent Plugins 1.0.0 §5.4 metadata layered onto the emitted root `plugin.json`; `extensions` maps reverse-domain client namespaces to opaque object payloads (§8). Omitted fields are omitted from the manifest. | Everything else about a Cursor plugin is derived from the cross-host model. The host capability tables in the [host reference](../../reference/hosts.md) record which of these surfaces each pinned diff --git a/website/docs/en/guide/concepts/architecture.mdx b/website/docs/en/guide/concepts/architecture.mdx index 0c638087f..4508963b9 100644 --- a/website/docs/en/guide/concepts/architecture.mdx +++ b/website/docs/en/guide/concepts/architecture.mdx @@ -387,7 +387,7 @@ session identity the host did not supply. The writer is `build/build.ts` `manifestFor`. It assembles an `ArtifactManifest` (`build/manifest.ts`; TypeDoc: -[`ArtifactManifest`](../../api/interfaces/index.ArtifactManifest.md)) and +[`ArtifactManifest`](../../api/index-1.md#artifactmanifest)) and `writeManifest` serializes it with `assembleArtifactManifest`: canonical `stableJson` plus a trailing newline. `parseArtifactManifest` rejects any other byte sequence, duplicate keys, unknown keys, missing keys, unsorted arrays, and a file entry that diff --git a/website/docs/en/guide/development/evaluations.mdx b/website/docs/en/guide/development/evaluations.mdx index a366631df..3f1de4630 100644 --- a/website/docs/en/guide/development/evaluations.mdx +++ b/website/docs/en/guide/development/evaluations.mdx @@ -51,9 +51,9 @@ npx agent-bundle eval compare resolved relative to the suite file and must not climb out of the suite directory (`../` past it is rejected; the check is on the path, so a symlink inside the suite is followed wherever it points). `agent-bundle/eval` -exports its contract: [`EvalGraderFunction`](../../api/types/eval.EvalGraderFunction.md) takes an -[`EvalGraderContext`](../../api/interfaces/eval.EvalGraderContext.md) and returns an -[`EvalScriptOutcome`](../../api/interfaces/eval.EvalScriptOutcome.md), synchronously or as a +exports its contract: [`EvalGraderFunction`](../../api/eval.md#evalgraderfunction) takes an +[`EvalGraderContext`](../../api/eval.md#evalgradercontext) and returns an +[`EvalScriptOutcome`](../../api/eval.md#evalscriptoutcome), synchronously or as a promise. This is `examples/skills-starter/evals/graders/release-result.ts` verbatim; the suite above names `./graders/status-result.ts`, which has the same shape in `examples/mcp-app`: diff --git a/website/docs/en/reference/api.mdx b/website/docs/en/reference/api.mdx index 31c29c070..1ae31c4b7 100644 --- a/website/docs/en/reference/api.mdx +++ b/website/docs/en/reference/api.mdx @@ -1,5 +1,5 @@ --- -description: 'The generated agent-bundle type API: which entry points it covers, how it is produced, and why generated symbol documentation is language-neutral.' +description: 'The generated agent-bundle type API: one page per public entry point, how members are addressed, and why generated symbol documentation is language-neutral.' --- # Type API @@ -9,36 +9,53 @@ The symbol-level reference is **generated from the source**, not written by hand ## What it covers -Every public entry point is documented from its declarations: - -| Entry point | Contents | -| --- | --- | -| `agent-bundle` | The authoring and orchestration surface: `defineSkill`, `canonicalAgentEvents`, `startDevServer`, `runEvals`, `compareEvals`, the eval harness factories, and the artifact-manifest helpers. | -| `agent-bundle/api` | The programmatic compiler: `build`, `validate`, `inspect`, `prepack`, their option and result types, the `AgentComponentKind` / `componentKindCapability` component-kind helpers, and the artifact operations `listMcp`, `invokeMcp`, `runMcp`, `serveApp` (a built MCP App served standalone in a browser — a host-process API for scripts and tests; a routed CLI command inside the artifact uses `spawnServeApp` from `agent-bundle/serve-app-command` instead, see [Serving an App standalone](../guide/authoring/mcp.mdx#serving-an-app-standalone)), `listHooks`, and `simulateHook`; plus the Rspack stats formatters `rspackStatsErrors`, `describeRspackStatsError`, and `formatRspackStatsError`, which render a compile error as the same `::: ` line the compiler's `AB4770` carries, for tools that drive their own Rsbuild compile. | -| `agent-bundle/app` | The browser-safe MCP App client: `createAppClient`, the `AppClient` lifecycle (`connect`, `call`, `request`, `onToolInput`, `onToolResult`, `onToolError`, `onToolCancelled`, `rebind`, `dispose`), `AppClientError` and its `code` union for every wire and lifecycle failure (option misuse is a plain `TypeError` or `RangeError`), the `AppRegister` interface the generated `.agent-bundle/routes.d.ts` augments with the project's `tool:/` contracts, `AppRouteId` / `AppRouteInput` / `AppRouteResult`, the injectable `AppWindow` / `AppMessageTarget` ports, and `APP_PROTOCOL_VERSION`. Imports nothing from Zod, Node, or the compiler; for App views only. | -| `agent-bundle/config` | `defineConfig` and the configuration types. | -| `agent-bundle/test` | The route-testing harness, matchers, and contract matrices. | -| `agent-bundle/test/browser` | The MCP App bridge harness for browser-rendered views. | -| `agent-bundle/eval` | Eval suite definitions, assertions, and run comparison. | -| `agent-bundle/rstest` | The Rstest configuration helper. | -| `agent-bundle/meta` | The build-time project identity constant, replaced by the compiler in every compiled surface. | -| `agent-bundle/mcp-apps` | The MCP App resource registry contract, replaced by the compiler in local MCP servers. | -| `agent-bundle/cli-entry` | The routed-CLI shell every generated CLI executable is built on. | -| `agent-bundle/mcp-entry` | The stdio MCP entry shell every generated MCP server is wrapped in. | -| `agent-bundle/launch-env` | The operator `.env` layer every emitted shell applies at launch (`applyOperatorEnv`, `parseOperatorEnv`, `AGENT_BUNDLE_ENV_FILE`), for hand-rolled entries that want the same behavior. | -| `agent-bundle/serve-app-command` | Plain Node, no dependencies: `spawnServeApp`, `serveAppArgv`, `locateFrameworkCli`, `parseServeAppReadyLine`, `serveAppAllowCapabilities`, `ServeAppCommandError`, and their types — a routed CLI command (or any other generated executable) serves a built MCP App by spawning `agent-bundle serve-app` instead of importing `serveApp`. | -| `agent-bundle/routes` | The route-module authoring types (`AgentEventRouteProps`, `ToolRouteProps`, `CliRouteProps`, the `config` shapes) and `appResourceUri`, the static reference to a sibling MCP App the compiler resolves to its `resourceUri`. | +Every public entry point is documented from its declarations, one page per entry point: + +| Entry point | Module page | Contents | +| --- | --- | --- | +| `agent-bundle` | [index](/api/index-1) | The authoring and orchestration surface: `defineSkill`, `canonicalAgentEvents`, `startDevServer`, `runEvals`, `compareEvals`, the eval harness factories, and the artifact-manifest helpers. | +| `agent-bundle/api` | [api](/api/api) | The programmatic compiler: `build`, `validate`, `inspect`, `prepack`, their option and result types, the `AgentComponentKind` / `componentKindCapability` component-kind helpers, and the artifact operations `listMcp`, `invokeMcp`, `runMcp`, `serveApp` (a built MCP App served standalone in a browser — a host-process API for scripts and tests; a routed CLI command inside the artifact uses `spawnServeApp` from `agent-bundle/serve-app-command` instead, see [Serving an App standalone](../guide/authoring/mcp.mdx#serving-an-app-standalone)), `listHooks`, and `simulateHook`; plus the Rspack stats formatters `rspackStatsErrors`, `describeRspackStatsError`, and `formatRspackStatsError`, which render a compile error as the same `::: ` line the compiler's `AB4770` carries, for tools that drive their own Rsbuild compile. | +| `agent-bundle/app` | [app](/api/app) | The browser-safe MCP App client: `createAppClient`, the `AppClient` lifecycle (`connect`, `call`, `request`, `onToolInput`, `onToolResult`, `onToolError`, `onToolCancelled`, `rebind`, `dispose`), `AppClientError` and its `code` union for every wire and lifecycle failure (option misuse is a plain `TypeError` or `RangeError`), the `AppRegister` interface the generated `.agent-bundle/routes.d.ts` augments with the project's `tool:/` contracts, `AppRouteId` / `AppRouteInput` / `AppRouteResult`, the injectable `AppWindow` / `AppMessageTarget` ports, and `APP_PROTOCOL_VERSION`. Imports nothing from Zod, Node, or the compiler; for App views only. | +| `agent-bundle/config` | [config](/api/config) | `defineConfig` and the configuration types. | +| `agent-bundle/test` | [test](/api/test) | The route-testing harness, matchers, and contract matrices. | +| `agent-bundle/test/browser` | [test/browser](/api/test/browser) | The MCP App bridge harness for browser-rendered views. | +| `agent-bundle/eval` | [eval](/api/eval) | Eval suite definitions, assertions, and run comparison. | +| `agent-bundle/rstest` | [rstest](/api/rstest) | The Rstest configuration helpers `agentBundleRstest` and `agentBundleBrowserRstest`. | +| `agent-bundle/meta` | [meta](/api/meta) | The build-time project identity constant, replaced by the compiler in every compiled surface. | +| `agent-bundle/mcp-apps` | [mcp-apps](/api/mcp-apps) | The MCP App resource registry contract, replaced by the compiler in local MCP servers. | +| `agent-bundle/cli-entry` | [cli-entry](/api/cli-entry) | The routed-CLI shell every generated CLI executable is built on. | +| `agent-bundle/mcp-entry` | [mcp-entry](/api/mcp-entry) | The stdio MCP entry shell every generated MCP server is wrapped in. | +| `agent-bundle/launch-env` | [launch-env](/api/launch-env) | The operator `.env` layer every emitted shell applies at launch — `applyOperatorEnv`, `parseOperatorEnv`, and the `OPERATOR_ENV_FILE_*` constants behind the `AGENT_BUNDLE_ENV_FILE` variable — for hand-rolled entries that want the same behavior. | +| `agent-bundle/serve-app-command` | [serve-app-command](/api/serve-app-command) | Plain Node, no dependencies: `spawnServeApp`, `serveAppArgv`, `locateFrameworkCli`, `parseServeAppReadyLine`, `serveAppAllowCapabilities`, `ServeAppCommandError`, and their types — a routed CLI command (or any other generated executable) serves a built MCP App by spawning `agent-bundle serve-app` instead of importing `serveApp`. | +| `agent-bundle/routes` | [routes/public](/api/routes/public) | The route-module authoring types (`AgentEventRouteProps`, `ToolRouteProps`, `CliRouteProps`, the `config` shapes) and `appResourceUri`, the static reference to a sibling MCP App the compiler resolves to its `resourceUri`. | Because it is generated, it always matches the shipped types: signatures, unions, defaults, and the error classes each surface can throw. When this Reference section and the generated pages disagree, the generated pages are correct. +## How the pages are organized + +[/api/](/api/) lists the modules. Each module page is named after the entry point's source file +(`agent-bundle/routes` is compiled from `routes/public.ts`, so its page is `routes/public`; the +root `agent-bundle` export is `index`, served at `/api/index-1` because `/api/` is the module +index itself) and groups its members under `Classes`, `Interfaces`, `Type Aliases`, `Variables`, +and `Functions`. A name an entry point re-exports from another entry point is listed under +`References` with a link to the page that documents it — `runEvals` on `index` points to +[`runEvals`](/api/api#runevals) on `api`. + +Every member is a heading, so it has a URL: `/api/#`, the fragment being the name +lowercased with `()` dropped — [`/api/eval#defineevalsuite`](/api/eval#defineevalsuite) documents +`defineEvalSuite`. Ids are unique per page: when the same text already appears higher up — a +property named `build`, or `AgentEventPayloadFields` beside `agentEventPayloadFields` — the later +heading is suffixed, so `build` in `agent-bundle/api` is [`#build-2`](/api/api#build-2). The `#` +link beside each heading carries its exact id. + ## Generated pages are language-neutral The site mirrors the generated reference under both locales, so [/api/](/api/) and [/zh/api/](/zh/api/) resolve for readers of either language. The **content** is not translated: -the symbol documentation is extracted from source comments and stays in the language it was -authored in. +the Chinese copy is the English Markdown with a notice under each page title saying so, and the +symbol documentation stays in the language it was authored in. That is deliberate. A translated copy of generated output would drift from the source on the first refactor, and a symbol reference whose types are current but whose prose is stale is worse than @@ -47,8 +64,8 @@ this Reference — are complete translations. ## Where to start -- Compiling from a script: `build` and `validate` in `agent-bundle/api`. +- Compiling from a script: [`build`](/api/api#build-2) and [`validate`](/api/api#validate-1) in `agent-bundle/api`. - Calling typed tools from an MCP App: `createAppClient` in `agent-bundle/app`, explained in [The typed App client](../guide/authoring/mcp.mdx#the-typed-app-client). -- Writing tests: `renderRoute`, `expectDocument`, and the matrices in `agent-bundle/test`, explained in [Testing](../guide/development/testing.mdx). -- Writing evals: `defineEvalSuite` and the assertions in `agent-bundle/eval`, explained in [Evaluations](../guide/development/evaluations.mdx). +- Writing tests: [`renderRoute`](/api/test#renderroute), [`expectDocument`](/api/test#expectdocument), and the matrices in `agent-bundle/test`, explained in [Testing](../guide/development/testing.mdx). +- Writing evals: [`defineEvalSuite`](/api/eval#defineevalsuite) and the assertions in `agent-bundle/eval`, explained in [Evaluations](../guide/development/evaluations.mdx). diff --git a/website/docs/en/reference/configuration.mdx b/website/docs/en/reference/configuration.mdx index 445b02a98..45a9e9180 100644 --- a/website/docs/en/reference/configuration.mdx +++ b/website/docs/en/reference/configuration.mdx @@ -62,15 +62,15 @@ as `EVAL_CONFIG_INVALID`, `EVAL_INCLUDE_INVALID`, or `EVAL_RUNS_DIR_INVALID` err | Field | Type definition | | --- | --- | -| whole config | [`AgentBundleConfig`](../api/types/index.AgentBundleConfig.md) · [`defineConfig`](../api/functions/index.defineConfig.md) · [`ConfigFactory`](../api/types/index.ConfigFactory.md) · [`ConfigFactoryContext`](../api/interfaces/index.ConfigFactoryContext.md) | -| `mcp` | [`AgentBundleMcpConfig`](../api/interfaces/index.AgentBundleMcpConfig.md) · [`AgentBundleMcpServer`](../api/interfaces/index.AgentBundleMcpServer.md) · [`AgentBundleMcpApp`](../api/interfaces/index.AgentBundleMcpApp.md) · [`McpTransport`](../api/types/index.McpTransport.md) | -| `payload` | [`AgentBundlePayloadConfig`](../api/types/index.AgentBundlePayloadConfig.md) · [`AgentBundlePayloadEntry`](../api/interfaces/index.AgentBundlePayloadEntry.md) · [`AgentBundlePrebuiltEntry`](../api/interfaces/index.AgentBundlePrebuiltEntry.md) | -| `output` | [`AgentBundleOutputConfig`](../api/interfaces/config.AgentBundleOutputConfig.md) | -| `runtime` | [`AgentBundleRuntimeConfig`](../api/interfaces/index.AgentBundleRuntimeConfig.md) | -| `notices` | [`AgentBundleNoticesConfig`](../api/interfaces/index.AgentBundleNoticesConfig.md) · [`AgentBundleNoticeRetentionConfig`](../api/interfaces/index.AgentBundleNoticeRetentionConfig.md) | -| `dev` | [`AgentBundleDevConfig`](../api/interfaces/index.AgentBundleDevConfig.md) · [`AgentBundleDevContractsConfig`](../api/interfaces/index.AgentBundleDevContractsConfig.md) · [`AgentBundleDevRuntimeConfig`](../api/interfaces/api.AgentBundleDevRuntimeConfig.md) | -| host extensions | [`AgentBundleConfigExtensions`](../api/interfaces/index.AgentBundleConfigExtensions.md) · [`AgentBundlePortableConfig`](../api/interfaces/config.AgentBundlePortableConfig.md) | -| validation | [`validateSource`](../api/functions/config.validateSource.md) · [`validateModel`](../api/functions/config.validateModel.md) · [`loadConfig`](../api/functions/config.loadConfig.md) | +| whole config | [`AgentBundleConfig`](../api/index-1.md#agentbundleconfig) · [`defineConfig`](../api/index-1.md#defineconfig) · [`ConfigFactory`](../api/index-1.md#configfactory) · [`ConfigFactoryContext`](../api/index-1.md#configfactorycontext) | +| `mcp` | [`AgentBundleMcpConfig`](../api/index-1.md#agentbundlemcpconfig) · [`AgentBundleMcpServer`](../api/index-1.md#agentbundlemcpserver) · [`AgentBundleMcpApp`](../api/index-1.md#agentbundlemcpapp) · [`McpTransport`](../api/index-1.md#mcptransport) | +| `payload` | [`AgentBundlePayloadConfig`](../api/index-1.md#agentbundlepayloadconfig) · [`AgentBundlePayloadEntry`](../api/index-1.md#agentbundlepayloadentry) · [`AgentBundlePrebuiltEntry`](../api/index-1.md#agentbundleprebuiltentry) | +| `output` | [`AgentBundleOutputConfig`](../api/config.md#agentbundleoutputconfig) | +| `runtime` | [`AgentBundleRuntimeConfig`](../api/index-1.md#agentbundleruntimeconfig) | +| `notices` | [`AgentBundleNoticesConfig`](../api/index-1.md#agentbundlenoticesconfig) · [`AgentBundleNoticeRetentionConfig`](../api/index-1.md#agentbundlenoticeretentionconfig) | +| `dev` | [`AgentBundleDevConfig`](../api/index-1.md#agentbundledevconfig) · [`AgentBundleDevContractsConfig`](../api/index-1.md#agentbundledevcontractsconfig) · [`AgentBundleDevRuntimeConfig`](../api/api.md#agentbundledevruntimeconfig) | +| host extensions | [`AgentBundleConfigExtensions`](../api/index-1.md#agentbundleconfigextensions) · [`AgentBundlePortableConfig`](../api/config.md#agentbundleportableconfig) | +| validation | [`validateSource`](../api/config.md#validatesource) · [`validateModel`](../api/config.md#validatemodel) · [`loadConfig`](../api/config.md#loadconfig) | ## plugin @@ -190,7 +190,7 @@ Development-only settings that never become part of a built artifact. | `dev.agentApi` | Exposes the authenticated, loopback-only Agent API from `agent-bundle dev`. The `--agent-api` / `--no-agent-api` flags override it. | | `dev.contracts.fixtures` | **Required when `dev.contracts` is set.** Project-relative module whose default export maps route ids to contract fixtures. Declaring `dev.contracts` switches `agent-bundle dev` from adopting every epoch directly to gating host-facing adoption on the development contract matrix: an epoch whose checks fail still publishes to the Workbench playground, but live host connections and development installs keep the last passing epoch (`AB7211`). A malformed block, a fixtures module that escapes the project root, cannot load, or exports the wrong shape is `AB7210`. | | `dev.contracts.server` | The MCP server the matrix checks. Optional only when the project compiles exactly one server. | -| `dev.runtime.provider` | The development runtime provider module: it exports `createDevRuntimeProvider` ([`CreateDevRuntimeProvider`](../api/types/api.CreateDevRuntimeProvider.md)), returning a [`DevRuntimeProvider`](../api/interfaces/api.DevRuntimeProvider.md) whose `start` takes a [`DevRuntimeStartContext`](../api/interfaces/api.DevRuntimeStartContext.md) and returns a [`DevRuntimeSession`](../api/interfaces/api.DevRuntimeSession.md). The whole protocol a provider implements ships from `agent-bundle/api` — the inspection envelope ([`DevRuntimeInspectionEnvelope`](../api/interfaces/api.DevRuntimeInspectionEnvelope.md)), the MCP server descriptor ([`DevRuntimeMcpServerDescriptor`](../api/interfaces/api.DevRuntimeMcpServerDescriptor.md)), the errors it throws ([`DevRuntimeUnavailableError`](../api/classes/api.DevRuntimeUnavailableError.md), [`DevRuntimeGenerationConflictError`](../api/classes/api.DevRuntimeGenerationConflictError.md)), and the generation store and MCP registry a session drives, as contracts ([`DevRuntimeGenerationStore`](../api/interfaces/api.DevRuntimeGenerationStore.md), [`DevRuntimeProviderMcpRegistry`](../api/interfaces/api.DevRuntimeProviderMcpRegistry.md)) with their constructors ([`createRuntimeGenerationStore`](../api/functions/api.createRuntimeGenerationStore.md), [`createRuntimeMcpRegistry`](../api/functions/api.createRuntimeMcpRegistry.md)). | +| `dev.runtime.provider` | The development runtime provider module: it exports `createDevRuntimeProvider` ([`CreateDevRuntimeProvider`](../api/api.md#createdevruntimeprovider)), returning a [`DevRuntimeProvider`](../api/api.md#devruntimeprovider) whose `start` takes a [`DevRuntimeStartContext`](../api/api.md#devruntimestartcontext) and returns a [`DevRuntimeSession`](../api/api.md#devruntimesession). The whole protocol a provider implements ships from `agent-bundle/api` — the inspection envelope ([`DevRuntimeInspectionEnvelope`](../api/api.md#devruntimeinspectionenvelope)), the MCP server descriptor ([`DevRuntimeMcpServerDescriptor`](../api/api.md#devruntimemcpserverdescriptor)), the errors it throws ([`DevRuntimeUnavailableError`](../api/api.md#devruntimeunavailableerror), [`DevRuntimeGenerationConflictError`](../api/api.md#devruntimegenerationconflicterror)), and the generation store and MCP registry a session drives, as contracts ([`DevRuntimeGenerationStore`](../api/api.md#devruntimegenerationstore), [`DevRuntimeProviderMcpRegistry`](../api/api.md#devruntimeprovidermcpregistry)) with their constructors ([`createRuntimeGenerationStore`](../api/api.md#createruntimegenerationstore), [`createRuntimeMcpRegistry`](../api/api.md#createruntimemcpregistry)). | ## tools diff --git a/website/docs/zh/api/_meta.json b/website/docs/zh/api/_meta.json index f8739133e..ac6fe7651 100644 --- a/website/docs/zh/api/_meta.json +++ b/website/docs/zh/api/_meta.json @@ -1,39 +1,82 @@ [ - "index", { - "type": "dir", - "name": "modules", - "label": "模块", - "collapsed": true + "type": "file", + "name": "index", + "label": "agent-bundle" }, { - "type": "dir", - "name": "functions", - "label": "函数", - "collapsed": true + "type": "file", + "name": "index-1", + "label": "index" }, { - "type": "dir", - "name": "classes", - "label": "类", - "collapsed": true + "type": "file", + "name": "config", + "label": "config" }, { - "type": "dir", - "name": "interfaces", - "label": "接口", - "collapsed": true + "type": "file", + "name": "api", + "label": "api" }, { - "type": "dir", - "name": "types", - "label": "类型别名", - "collapsed": true + "type": "file", + "name": "app", + "label": "app" }, { - "type": "dir", - "name": "variables", - "label": "变量", - "collapsed": true + "type": "file", + "name": "routes/public", + "label": "routes/public" + }, + { + "type": "file", + "name": "test", + "label": "test" + }, + { + "type": "file", + "name": "test/browser", + "label": "test/browser" + }, + { + "type": "file", + "name": "eval", + "label": "eval" + }, + { + "type": "file", + "name": "rstest", + "label": "rstest" + }, + { + "type": "file", + "name": "mcp-apps", + "label": "mcp-apps" + }, + { + "type": "file", + "name": "mcp-entry", + "label": "mcp-entry" + }, + { + "type": "file", + "name": "cli-entry", + "label": "cli-entry" + }, + { + "type": "file", + "name": "serve-app-command", + "label": "serve-app-command" + }, + { + "type": "file", + "name": "launch-env", + "label": "launch-env" + }, + { + "type": "file", + "name": "meta", + "label": "meta" } ] diff --git a/website/docs/zh/guide/authoring/index.mdx b/website/docs/zh/guide/authoring/index.mdx index 3eb57f193..866a7411d 100644 --- a/website/docs/zh/guide/authoring/index.mdx +++ b/website/docs/zh/guide/authoring/index.mdx @@ -96,7 +96,7 @@ shell 形式的 `command` 处理器。各适配器拥有的字段如下: | `claude`(`ClaudeHostConfig`) | `bin`、`channels`、`defaultEnabled`、`dependencies`、`displayName`、`lspServers`、`marketplace`、`metadata`、`monitors`、`outputStyles`、`settings`、`themes`、`userConfig`、`workflows` | `bin`、`outputStyles` 与 `workflows` 是被复制到插件根同名约定目录的项目目录;`channels`、`dependencies`、`defaultEnabled`、`displayName`、`metadata` 与 `userConfig` 经校验后写入 `.claude-plugin/plugin.json`(`channels` 必须指向输出的 `.mcp.json` 中的服务器);`marketplace` 丰富生成的 marketplace 条目;`monitors` 与 `themes` 属于实验特性,分别输出 `monitors/monitors.json` 与每个键一份的 `themes/.json`;`lspServers` 与 `settings` 见下文。 | | `codex`(`CodexHostConfig`) | `apps`、`author`、`homepage`、`interface`、`keywords`、`license`、`marketplace`、`repository` | `author`、`homepage`、`keywords`、`license` 与 `repository` 是 `.codex-plugin/plugin.json` 中的发布者元数据;`interface`(品牌色、分类、能力、composer 图标、默认提示、开发者名称……)会合并覆盖编译器生成的安装表面默认值;`apps` 把已注册的 MCP 连接 id 映射进根目录的 `.app.json` 兼容文档;`marketplace` 编写输出的 `.agents/plugins/marketplace.json` 条目——`category`(默认为 interface 的分类)、`displayName`(默认为插件名)以及 `policy`,其中 `installation` 取 `AVAILABLE`、`INSTALLED_BY_DEFAULT` 或 `NOT_AVAILABLE`,`authentication` 取 `ON_INSTALL` 或 `ON_USE`;来源始终是本地插件根目录,任何其他键都会报错,而不是被悄悄输出。 | | `cursor`(`CursorHostConfig`) | `author`、`category`、`homepage`、`keywords`、`license`、`minClientVersions`、`publisher`、`repository`、`tags` | 叠加到生成的 `.cursor-plugin/plugin.json` 上的清单元数据,每个字段都被固定的 Cursor 插件 schema 接纳。`author` 是封闭的 `{ name, email? }` 对象(没有 `url`);`minClientVersions` 把客户端标识映射为严格的 `X.Y.Z` semver 字符串,例如 `{ cursor: '3.13.0' }`,其他任何写法都是错误。Cursor 没有文档化的 `nativeHooks` 表面,因此 `cursor` 不扩展 `AgentBundleHostConfig`。 | -| `portable`([`PortableManifestConfig`](../../api/interfaces/index.PortableManifestConfig.md)) | `author`、`extensions`、`homepage`、`keywords`、`license`、`repository` | 叠加到输出的根 `plugin.json` 上的 Agent Plugins 1.0.0 §5.4 元数据;`extensions` 把反向域名的客户端命名空间映射为不透明对象载荷(§8)。省略的字段不会出现在清单中。 | +| `portable`([`PortableManifestConfig`](../../api/index-1.md#portablemanifestconfig)) | `author`、`extensions`、`homepage`、`keywords`、`license`、`repository` | 叠加到输出的根 `plugin.json` 上的 Agent Plugins 1.0.0 §5.4 元数据;`extensions` 把反向域名的客户端命名空间映射为不透明对象载荷(§8)。省略的字段不会出现在清单中。 | Cursor 插件的其余一切都从跨宿主模型推导。[宿主参考](../../reference/hosts.md)中的宿主能力表 记录了每个被固定的宿主版本实际认可其中哪些表面。 diff --git a/website/docs/zh/guide/concepts/architecture.mdx b/website/docs/zh/guide/concepts/architecture.mdx index 9927053de..a2784db62 100644 --- a/website/docs/zh/guide/concepts/architecture.mdx +++ b/website/docs/zh/guide/concepts/architecture.mdx @@ -340,7 +340,7 @@ prompt 路由则返回经校验的协议结果(来自 `document.value`)。CL 写入器是 `build/build.ts` 的 `manifestFor`。它组装出一个 `ArtifactManifest` (`build/manifest.ts`;TypeDoc: -[`ArtifactManifest`](../../api/interfaces/index.ArtifactManifest.md)),`writeManifest` +[`ArtifactManifest`](../../api/index-1.md#artifactmanifest)),`writeManifest` 再用 `assembleArtifactManifest` 将其序列化:规范的 `stableJson` 加一个末尾换行。`parseArtifactManifest` 拒绝任何其他字节序列、重复键、未知键、 缺失键、未排序的数组,以及指向清单自身的文件条目。 diff --git a/website/docs/zh/guide/development/evaluations.mdx b/website/docs/zh/guide/development/evaluations.mdx index 03a2242cd..4ffdeec07 100644 --- a/website/docs/zh/guide/development/evaluations.mdx +++ b/website/docs/zh/guide/development/evaluations.mdx @@ -45,9 +45,9 @@ npx agent-bundle eval compare ### 编写一个结果 grader `expectOutcome({ script })` 指名一个默认导出一个 grader 函数的模块。路径相对套件文件解析,且不得越出套件 -目录(越过它的 `../` 会被拒绝;这项检查针对的是路径本身,因此套件内的符号链接会被跟随到它所指向的任何位置)。`agent-bundle/eval` 导出了它的契约:[`EvalGraderFunction`](../../api/types/eval.EvalGraderFunction.md) -接收一个 [`EvalGraderContext`](../../api/interfaces/eval.EvalGraderContext.md),并同步或以 promise 形式返回一个 -[`EvalScriptOutcome`](../../api/interfaces/eval.EvalScriptOutcome.md)。下面是 +目录(越过它的 `../` 会被拒绝;这项检查针对的是路径本身,因此套件内的符号链接会被跟随到它所指向的任何位置)。`agent-bundle/eval` 导出了它的契约:[`EvalGraderFunction`](../../api/eval.md#evalgraderfunction) +接收一个 [`EvalGraderContext`](../../api/eval.md#evalgradercontext),并同步或以 promise 形式返回一个 +[`EvalScriptOutcome`](../../api/eval.md#evalscriptoutcome)。下面是 `examples/skills-starter/evals/graders/release-result.ts` 的原文;上面的套件指名的 `./graders/status-result.ts` 在 `examples/mcp-app` 中具有同样的形状: diff --git a/website/docs/zh/reference/api.mdx b/website/docs/zh/reference/api.mdx index d50c7c093..012cd0fe7 100644 --- a/website/docs/zh/reference/api.mdx +++ b/website/docs/zh/reference/api.mdx @@ -1,5 +1,5 @@ --- -description: '生成的 agent-bundle 类型 API:它覆盖哪些入口点、如何产生,以及为什么生成式符号文档与语言无关。' +description: '生成的 agent-bundle 类型 API:每个公开入口点一页、成员如何寻址,以及为什么生成式符号文档与语言无关。' --- # 类型 API @@ -8,41 +8,58 @@ description: '生成的 agent-bundle 类型 API:它覆盖哪些入口点、如 ## 它覆盖什么 -每个公开入口点都由其声明生成文档: - -| 入口点 | 内容 | -| --- | --- | -| `agent-bundle` | 编写与编排表面:`defineSkill`、`canonicalAgentEvents`、`startDevServer`、`runEvals`、`compareEvals`、eval harness 工厂,以及产物清单辅助函数。 | -| `agent-bundle/api` | 程序化编译器:`build`、`validate`、`inspect`、`prepack`,及其选项与结果类型,`AgentComponentKind` / `componentKindCapability` 组件类型辅助,以及产物操作 `listMcp`、`invokeMcp`、`runMcp`、`serveApp`(在浏览器里独立提供一个已构建的 MCP App——面向脚本与测试的宿主进程 API;产物内部的路由式 CLI 命令则改用 `agent-bundle/serve-app-command` 中的 `spawnServeApp`,见[独立提供 App](../guide/authoring/mcp.mdx#独立提供-app))、`listHooks` 与 `simulateHook`;另有 Rspack stats 格式化工具 `rspackStatsErrors`、`describeRspackStatsError` 与 `formatRspackStatsError`,把一条编译错误渲染成与编译器 `AB4770` 相同的 `::: ` 行,供自行驱动 Rsbuild 编译的工具使用。 | -| `agent-bundle/app` | 浏览器安全且不携带编译器的 MCP App 客户端:`createAppClient`;`AppClient` 的 `connect`、`call`、`request`、`onToolInput`、`onToolResult`、`onToolError`、`onToolCancelled`、`rebind` 与 `dispose` 生命周期;`AppClientError` 与恰好八种 `code`;由 `.agent-bundle/routes.d.ts` 使用项目 `tool:/` 契约扩充的 `AppRegister`;`AppRouteContract` / `AppRoutes` / `AppRouteId` / `AppRouteInput` / `AppRouteResult`;连接、请求、初始化、实现与 listener 类型;可注入的 `AppWindow` / `AppMessageTarget` port;以及 `APP_PROTOCOL_VERSION`。该入口不导入 Zod、Node 或编译器,只用于 App 视图。 | -| `agent-bundle/config` | `defineConfig` 与配置类型。 | -| `agent-bundle/test` | 路由测试 harness、匹配器与契约矩阵。 | -| `agent-bundle/test/browser` | 面向浏览器渲染视图的 MCP App bridge harness。 | -| `agent-bundle/eval` | eval 套件定义、断言与运行对比。 | -| `agent-bundle/rstest` | Rstest 配置助手。 | -| `agent-bundle/meta` | 构建期项目标识常量,编译器会在每个被编译的表面中替换它。 | -| `agent-bundle/mcp-apps` | MCP App 资源注册表契约,编译器会在本地 MCP 服务器中替换它。 | -| `agent-bundle/cli-entry` | 每个生成的 CLI 可执行文件所基于的路由式 CLI 外壳。 | -| `agent-bundle/mcp-entry` | 每个生成的 MCP 服务器所包裹的 stdio MCP 入口外壳。 | -| `agent-bundle/launch-env` | 每个输出外壳在启动时应用的操作者 `.env` 层(`applyOperatorEnv`、`parseOperatorEnv`、`AGENT_BUNDLE_ENV_FILE`),供希望获得同样行为的手写入口使用。 | -| `agent-bundle/serve-app-command` | 纯 Node、无依赖:`spawnServeApp`、`serveAppArgv`、`locateFrameworkCli`、`parseServeAppReadyLine`、`serveAppAllowCapabilities`、`ServeAppCommandError` 及其类型——路由式 CLI 命令(或任何其他生成的可执行文件)通过启动 `agent-bundle serve-app` 来提供一个已构建的 MCP App,而不是导入 `serveApp`。 | -| `agent-bundle/routes` | 路由模块的编写类型(`AgentEventRouteProps`、`ToolRouteProps`、`CliRouteProps` 与各类 `config` 形状),以及 `appResourceUri`——对同级 MCP App 的静态引用,编译器会把它解析为该 App 的 `resourceUri`。 | +每个公开入口点都由其声明生成文档,每个入口点一页: + +| 入口点 | 模块页 | 内容 | +| --- | --- | --- | +| `agent-bundle` | [index](/zh/api/index-1) | 编写与编排表面:`defineSkill`、`canonicalAgentEvents`、`startDevServer`、`runEvals`、`compareEvals`、eval harness 工厂,以及产物清单辅助函数。 | +| `agent-bundle/api` | [api](/zh/api/api) | 程序化编译器:`build`、`validate`、`inspect`、`prepack`,及其选项与结果类型,`AgentComponentKind` / `componentKindCapability` 组件类型辅助,以及产物操作 `listMcp`、`invokeMcp`、`runMcp`、`serveApp`(在浏览器里独立提供一个已构建的 MCP App——面向脚本与测试的宿主进程 API;产物内部的路由式 CLI 命令则改用 `agent-bundle/serve-app-command` 中的 `spawnServeApp`,见[独立提供 App](../guide/authoring/mcp.mdx#独立提供-app))、`listHooks` 与 `simulateHook`;另有 Rspack stats 格式化工具 `rspackStatsErrors`、`describeRspackStatsError` 与 `formatRspackStatsError`,把一条编译错误渲染成与编译器 `AB4770` 相同的 `::: ` 行,供自行驱动 Rsbuild 编译的工具使用。 | +| `agent-bundle/app` | [app](/zh/api/app) | 浏览器安全的 MCP App 客户端:`createAppClient`;`AppClient` 的 `connect`、`call`、`request`、`onToolInput`、`onToolResult`、`onToolError`、`onToolCancelled`、`rebind` 与 `dispose` 生命周期;`AppClientError` 及其覆盖所有 wire 与生命周期故障的 `code` 联合(选项误用则是普通的 `TypeError` 或 `RangeError`);由 `.agent-bundle/routes.d.ts` 使用项目 `tool:/` 契约扩充的 `AppRegister`;`AppRouteId` / `AppRouteInput` / `AppRouteResult`;可注入的 `AppWindow` / `AppMessageTarget` port;以及 `APP_PROTOCOL_VERSION`。该入口不导入 Zod、Node 或编译器,只用于 App 视图。 | +| `agent-bundle/config` | [config](/zh/api/config) | `defineConfig` 与配置类型。 | +| `agent-bundle/test` | [test](/zh/api/test) | 路由测试 harness、匹配器与契约矩阵。 | +| `agent-bundle/test/browser` | [test/browser](/zh/api/test/browser) | 面向浏览器渲染视图的 MCP App bridge harness。 | +| `agent-bundle/eval` | [eval](/zh/api/eval) | eval 套件定义、断言与运行对比。 | +| `agent-bundle/rstest` | [rstest](/zh/api/rstest) | Rstest 配置助手 `agentBundleRstest` 与 `agentBundleBrowserRstest`。 | +| `agent-bundle/meta` | [meta](/zh/api/meta) | 构建期项目标识常量,编译器会在每个被编译的表面中替换它。 | +| `agent-bundle/mcp-apps` | [mcp-apps](/zh/api/mcp-apps) | MCP App 资源注册表契约,编译器会在本地 MCP 服务器中替换它。 | +| `agent-bundle/cli-entry` | [cli-entry](/zh/api/cli-entry) | 每个生成的 CLI 可执行文件所基于的路由式 CLI 外壳。 | +| `agent-bundle/mcp-entry` | [mcp-entry](/zh/api/mcp-entry) | 每个生成的 MCP 服务器所包裹的 stdio MCP 入口外壳。 | +| `agent-bundle/launch-env` | [launch-env](/zh/api/launch-env) | 每个输出外壳在启动时应用的操作者 `.env` 层——`applyOperatorEnv`、`parseOperatorEnv`,以及 `AGENT_BUNDLE_ENV_FILE` 变量背后的 `OPERATOR_ENV_FILE_*` 常量——供希望获得同样行为的手写入口使用。 | +| `agent-bundle/serve-app-command` | [serve-app-command](/zh/api/serve-app-command) | 纯 Node、无依赖:`spawnServeApp`、`serveAppArgv`、`locateFrameworkCli`、`parseServeAppReadyLine`、`serveAppAllowCapabilities`、`ServeAppCommandError` 及其类型——路由式 CLI 命令(或任何其他生成的可执行文件)通过启动 `agent-bundle serve-app` 来提供一个已构建的 MCP App,而不是导入 `serveApp`。 | +| `agent-bundle/routes` | [routes/public](/zh/api/routes/public) | 路由模块的编写类型(`AgentEventRouteProps`、`ToolRouteProps`、`CliRouteProps` 与各类 `config` 形状),以及 `appResourceUri`——对同级 MCP App 的静态引用,编译器会把它解析为该 App 的 `resourceUri`。 | 因为它是生成的,所以它始终与已交付的类型一致:签名、联合类型、默认值,以及各表面可能抛出的错误类。 当本参考章节与生成页面不一致时,以生成页面为准。 +## 页面如何组织 + +[/zh/api/](/zh/api/) 列出了所有模块。每个模块页以入口点的源文件命名(`agent-bundle/routes` 由 +`routes/public.ts` 编译而来,因此其页面是 `routes/public`;根导出 `agent-bundle` 是 `index`,位于 +`/zh/api/index-1`,因为 `/zh/api/` 本身就是模块索引),并把成员归入 `Classes`、`Interfaces`、 +`Type Aliases`、`Variables` 与 `Functions` 之下。一个入口点从另一个入口点重新导出的名称会列在 +`References` 下,并链接到实际记录它的页面——`index` 页上的 `runEvals` 指向 +`api` 页上的 [`runEvals`](/zh/api/api#runevals)。 + +每个成员都是一个标题,因此都有自己的 URL:`/api/#`(中文站点下为 +`/zh/api/#`),片段是小写后的成员名,函数名去掉 `()`—— +[`/zh/api/eval#defineevalsuite`](/zh/api/eval#defineevalsuite) 记录的是 `defineEvalSuite`。id 在页面内 +唯一:当同样的文本已在更靠前的位置出现过——比如名为 `build` 的属性,或与 `agentEventPayloadFields` +并存的 `AgentEventPayloadFields`——靠后的标题会加上后缀,因此 `agent-bundle/api` 中的 `build` 是 +[`#build-2`](/zh/api/api#build-2)。每个标题旁边的 `#` 链接带有它的确切 id。 + ## 生成页面与语言无关 站点在两个语言下都镜像了这份生成式参考,因此[/api/](/api/)与[/zh/api/](/zh/api/)对两种语言的读者都能 -解析。但其**内容**未被翻译:符号文档提取自源码注释,并保持在其被编写时所用的语言。 +解析。但其**内容**未被翻译:中文副本就是英文 Markdown,只在每页标题下加了一条说明这一点的提示, +符号文档保持在其被编写时所用的语言。 这是刻意的。生成输出的翻译副本会在第一次重构时就与源码脱节,而一份类型是最新的、散文却已过期的符号参考, 比一份诚实地只用一种语言的参考更糟。手写页面——指南以及本参考的其余部分——则是完整翻译。 ## 从哪里开始 -- 从脚本中编译:`agent-bundle/api` 中的 `build` 与 `validate`。 +- 从脚本中编译:`agent-bundle/api` 中的 [`build`](/zh/api/api#build-2) 与 [`validate`](/zh/api/api#validate-1)。 - 在 MCP App 中调用带类型的工具:`agent-bundle/app` 中的 `createAppClient`,详见 [带类型的 App 客户端](../guide/authoring/mcp.mdx#带类型的-app-客户端)。 -- 编写测试:`agent-bundle/test` 中的 `renderRoute`、`expectDocument` 与那些矩阵,在[测试](../guide/development/testing.mdx)中介绍。 -- 编写 eval:`agent-bundle/eval` 中的 `defineEvalSuite` 与那些断言,在[评测](../guide/development/evaluations.mdx)中介绍。 +- 编写测试:`agent-bundle/test` 中的 [`renderRoute`](/zh/api/test#renderroute)、[`expectDocument`](/zh/api/test#expectdocument) 与那些矩阵,在[测试](../guide/development/testing.mdx)中介绍。 +- 编写 eval:`agent-bundle/eval` 中的 [`defineEvalSuite`](/zh/api/eval#defineevalsuite) 与那些断言,在[评测](../guide/development/evaluations.mdx)中介绍。 diff --git a/website/docs/zh/reference/configuration.mdx b/website/docs/zh/reference/configuration.mdx index 511e17d01..a0b2919b1 100644 --- a/website/docs/zh/reference/configuration.mdx +++ b/website/docs/zh/reference/configuration.mdx @@ -56,15 +56,15 @@ export default defineConfig({ | 字段 | 类型定义 | | --- | --- | -| 整个配置 | [`AgentBundleConfig`](../api/types/index.AgentBundleConfig.md) · [`defineConfig`](../api/functions/index.defineConfig.md) · [`ConfigFactory`](../api/types/index.ConfigFactory.md) · [`ConfigFactoryContext`](../api/interfaces/index.ConfigFactoryContext.md) | -| `mcp` | [`AgentBundleMcpConfig`](../api/interfaces/index.AgentBundleMcpConfig.md) · [`AgentBundleMcpServer`](../api/interfaces/index.AgentBundleMcpServer.md) · [`AgentBundleMcpApp`](../api/interfaces/index.AgentBundleMcpApp.md) · [`McpTransport`](../api/types/index.McpTransport.md) | -| `payload` | [`AgentBundlePayloadConfig`](../api/types/index.AgentBundlePayloadConfig.md) · [`AgentBundlePayloadEntry`](../api/interfaces/index.AgentBundlePayloadEntry.md) · [`AgentBundlePrebuiltEntry`](../api/interfaces/index.AgentBundlePrebuiltEntry.md) | -| `output` | [`AgentBundleOutputConfig`](../api/interfaces/config.AgentBundleOutputConfig.md) | -| `runtime` | [`AgentBundleRuntimeConfig`](../api/interfaces/index.AgentBundleRuntimeConfig.md) | -| `notices` | [`AgentBundleNoticesConfig`](../api/interfaces/index.AgentBundleNoticesConfig.md) · [`AgentBundleNoticeRetentionConfig`](../api/interfaces/index.AgentBundleNoticeRetentionConfig.md) | -| `dev` | [`AgentBundleDevConfig`](../api/interfaces/index.AgentBundleDevConfig.md) · [`AgentBundleDevContractsConfig`](../api/interfaces/index.AgentBundleDevContractsConfig.md) · [`AgentBundleDevRuntimeConfig`](../api/interfaces/api.AgentBundleDevRuntimeConfig.md) | -| 宿主扩展 | [`AgentBundleConfigExtensions`](../api/interfaces/index.AgentBundleConfigExtensions.md) · [`AgentBundlePortableConfig`](../api/interfaces/config.AgentBundlePortableConfig.md) | -| 校验 | [`validateSource`](../api/functions/config.validateSource.md) · [`validateModel`](../api/functions/config.validateModel.md) · [`loadConfig`](../api/functions/config.loadConfig.md) | +| 整个配置 | [`AgentBundleConfig`](../api/index-1.md#agentbundleconfig) · [`defineConfig`](../api/index-1.md#defineconfig) · [`ConfigFactory`](../api/index-1.md#configfactory) · [`ConfigFactoryContext`](../api/index-1.md#configfactorycontext) | +| `mcp` | [`AgentBundleMcpConfig`](../api/index-1.md#agentbundlemcpconfig) · [`AgentBundleMcpServer`](../api/index-1.md#agentbundlemcpserver) · [`AgentBundleMcpApp`](../api/index-1.md#agentbundlemcpapp) · [`McpTransport`](../api/index-1.md#mcptransport) | +| `payload` | [`AgentBundlePayloadConfig`](../api/index-1.md#agentbundlepayloadconfig) · [`AgentBundlePayloadEntry`](../api/index-1.md#agentbundlepayloadentry) · [`AgentBundlePrebuiltEntry`](../api/index-1.md#agentbundleprebuiltentry) | +| `output` | [`AgentBundleOutputConfig`](../api/config.md#agentbundleoutputconfig) | +| `runtime` | [`AgentBundleRuntimeConfig`](../api/index-1.md#agentbundleruntimeconfig) | +| `notices` | [`AgentBundleNoticesConfig`](../api/index-1.md#agentbundlenoticesconfig) · [`AgentBundleNoticeRetentionConfig`](../api/index-1.md#agentbundlenoticeretentionconfig) | +| `dev` | [`AgentBundleDevConfig`](../api/index-1.md#agentbundledevconfig) · [`AgentBundleDevContractsConfig`](../api/index-1.md#agentbundledevcontractsconfig) · [`AgentBundleDevRuntimeConfig`](../api/api.md#agentbundledevruntimeconfig) | +| 宿主扩展 | [`AgentBundleConfigExtensions`](../api/index-1.md#agentbundleconfigextensions) · [`AgentBundlePortableConfig`](../api/config.md#agentbundleportableconfig) | +| 校验 | [`validateSource`](../api/config.md#validatesource) · [`validateModel`](../api/config.md#validatemodel) · [`loadConfig`](../api/config.md#loadconfig) | ## plugin @@ -170,7 +170,7 @@ export default defineConfig({ | `dev.agentApi` | 从 `agent-bundle dev` 暴露那个经过认证、仅 loopback 的 Agent API。`--agent-api` / `--no-agent-api` 标志会覆盖它。 | | `dev.contracts.fixtures` | **设置了 `dev.contracts` 时必填。** 项目相对路径的模块,其默认导出把路由 id 映射到契约夹具。声明 `dev.contracts` 会让 `agent-bundle dev` 从直接采用每个 epoch,改为以开发契约矩阵门控面向宿主的采用:检查失败的 epoch 仍会发布到 Workbench playground,但活跃的宿主连接与开发安装会保留最后一个通过的 epoch(`AB7211`)。块本身格式错误、夹具模块逃出项目根、无法加载或导出了错误的形状,则是 `AB7210`。 | | `dev.contracts.server` | 矩阵要检查的 MCP 服务器。仅当项目恰好编译一个服务器时可省略。 | -| `dev.runtime.provider` | 开发期运行时 provider 模块:它导出 `createDevRuntimeProvider`([`CreateDevRuntimeProvider`](../api/types/api.CreateDevRuntimeProvider.md)),返回一个 [`DevRuntimeProvider`](../api/interfaces/api.DevRuntimeProvider.md),其 `start` 接收 [`DevRuntimeStartContext`](../api/interfaces/api.DevRuntimeStartContext.md) 并返回 [`DevRuntimeSession`](../api/interfaces/api.DevRuntimeSession.md)。provider 需要实现的整个协议都从 `agent-bundle/api` 发布——检视信封([`DevRuntimeInspectionEnvelope`](../api/interfaces/api.DevRuntimeInspectionEnvelope.md))、MCP 服务器描述符([`DevRuntimeMcpServerDescriptor`](../api/interfaces/api.DevRuntimeMcpServerDescriptor.md))、它要抛出的错误([`DevRuntimeUnavailableError`](../api/classes/api.DevRuntimeUnavailableError.md)、[`DevRuntimeGenerationConflictError`](../api/classes/api.DevRuntimeGenerationConflictError.md)),以及会话所驱动的 generation store 与 MCP registry——以契约([`DevRuntimeGenerationStore`](../api/interfaces/api.DevRuntimeGenerationStore.md)、[`DevRuntimeProviderMcpRegistry`](../api/interfaces/api.DevRuntimeProviderMcpRegistry.md))及其构造函数([`createRuntimeGenerationStore`](../api/functions/api.createRuntimeGenerationStore.md)、[`createRuntimeMcpRegistry`](../api/functions/api.createRuntimeMcpRegistry.md))的形式提供。 | +| `dev.runtime.provider` | 开发期运行时 provider 模块:它导出 `createDevRuntimeProvider`([`CreateDevRuntimeProvider`](../api/api.md#createdevruntimeprovider)),返回一个 [`DevRuntimeProvider`](../api/api.md#devruntimeprovider),其 `start` 接收 [`DevRuntimeStartContext`](../api/api.md#devruntimestartcontext) 并返回 [`DevRuntimeSession`](../api/api.md#devruntimesession)。provider 需要实现的整个协议都从 `agent-bundle/api` 发布——检视信封([`DevRuntimeInspectionEnvelope`](../api/api.md#devruntimeinspectionenvelope))、MCP 服务器描述符([`DevRuntimeMcpServerDescriptor`](../api/api.md#devruntimemcpserverdescriptor))、它要抛出的错误([`DevRuntimeUnavailableError`](../api/api.md#devruntimeunavailableerror)、[`DevRuntimeGenerationConflictError`](../api/api.md#devruntimegenerationconflicterror)),以及会话所驱动的 generation store 与 MCP registry——以契约([`DevRuntimeGenerationStore`](../api/api.md#devruntimegenerationstore)、[`DevRuntimeProviderMcpRegistry`](../api/api.md#devruntimeprovidermcpregistry))及其构造函数([`createRuntimeGenerationStore`](../api/api.md#createruntimegenerationstore)、[`createRuntimeMcpRegistry`](../api/api.md#createruntimemcpregistry))的形式提供。 | ## tools diff --git a/website/package.json b/website/package.json index 0c8040458..f58081bb0 100644 --- a/website/package.json +++ b/website/package.json @@ -23,6 +23,7 @@ "@rspress/plugin-sitemap": "2.0.21", "@rspress/plugin-twoslash": "2.0.21", "@rspress/plugin-typedoc": "2.0.21", + "@rspress/shared": "2.0.21", "@shikijs/transformers": "4.4.3", "@types/hast": "3.0.5", "@types/node": "26.4.1", diff --git a/website/plugins/mirror-api-locale.ts b/website/plugins/mirror-api-locale.ts index 406adb1fa..3f99087cd 100644 --- a/website/plugins/mirror-api-locale.ts +++ b/website/plugins/mirror-api-locale.ts @@ -1,6 +1,9 @@ import { copyFile, mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises'; import path from 'node:path'; import type { RspressPlugin } from '@rspress/core'; +// The slugger Rspress itself runs over headings (`@rspress/core` re-exports it +// from here for `mdx/remarkPlugins/toc.js`), so ids match byte for byte. +import GithubSlugger from '@rspress/shared/github-slugger'; const MARKDOWN_EXTENSION = '.md'; const FRONTMATTER_FENCE = '---'; @@ -33,6 +36,76 @@ async function collectMarkdownFiles(directory: string, prefix = ''): Promise|~])/g, '$1') + .trim(); +} + +interface PageAnchors { + readonly ids: Set; + readonly memberIds: Set; +} + +function collectPageAnchors(markdown: string): PageAnchors { + const slugger = new GithubSlugger(); + const ids = new Set(); + const memberIds = new Set(); + const outsideFences = markdown.replace(/^```[\s\S]*?^```[ \t]*$/gm, ''); + + for (const match of outsideFences.matchAll(/^(#{1,6}) (.+)$/gm)) { + const id = slugger.slug(headingText(match[2])); + ids.add(id); + if (match[1].length === 3) { + memberIds.add(id); + } + } + return { ids, memberIds }; +} + +/** + * TypeDoc reserves some exported names while building its reflection URLs, so + * links to those `### Member` headings receive a spurious `-1`. Rspress runs + * github-slugger over the rendered headings instead, where the member's first + * occurrence has the unsuffixed anchor, so those links are dead. Rewrite a + * `#name-N` link to `#name` only when the fragment does not exist on the + * target page (the link is actually dead — a legitimate `#protocol-v1` whose + * heading exists is never touched) and `name` is the id of a `###` member + * heading there. Anything else is left as TypeDoc wrote it for the build's + * anchor check to judge. + */ +async function alignTypeDocMemberLinks(directory: string, files: string[]): Promise { + const anchorsByPage = new Map(); + + for (const relativePath of files) { + const filePath = path.resolve(directory, relativePath); + anchorsByPage.set(filePath, collectPageAnchors(await readFile(filePath, 'utf8'))); + } + + for (const relativePath of files) { + const filePath = path.resolve(directory, relativePath); + const markdown = await readFile(filePath, 'utf8'); + const aligned = markdown.replace( + /(\]\()([^)\s#]*#)([^)\s#]+?)-\d+(\))/g, + (link, opening: string, target: string, base: string, closing: string) => { + const linkedPath = target.slice(0, -1); + const targetPath = linkedPath ? path.resolve(path.dirname(filePath), linkedPath) : filePath; + const anchors = anchorsByPage.get(targetPath); + const fragment = link.slice(opening.length + target.length, -closing.length); + if (!anchors || anchors.ids.has(fragment) || !anchors.memberIds.has(base)) { + return link; + } + return `${opening}${target}${base}${closing}`; + }, + ); + + if (aligned !== markdown) { + await writeFile(filePath, aligned); + } + } +} + async function prunePlaceholderDirectories(directory: string): Promise { const entries = await readDirectory(directory); let isEmpty = true; @@ -137,6 +210,7 @@ export function mirrorApiLocale(options: MirrorApiLocaleOptions): RspressPlugin const source = path.join(docsRoot, sourceDir); const generatedFiles = await collectMarkdownFiles(source); + await alignTypeDocMemberLinks(source, generatedFiles); for (const { dir, notice } of targets) { const target = path.join(docsRoot, dir); diff --git a/website/rspress.config.ts b/website/rspress.config.ts index 95fd79dac..76d5a9b0c 100644 --- a/website/rspress.config.ts +++ b/website/rspress.config.ts @@ -141,7 +141,7 @@ export default defineConfig({ cleanUrls: true, localeRedirect: 'never', }, - // Renders the ~900 routes across a tinypool of worker threads instead of one + // Renders the routes across a tinypool of worker threads instead of one // process; output is identical. ssg: { experimentalWorker: true, @@ -202,18 +202,17 @@ export default defineConfig({ outDir: generatedApiDir, setup: async app => { await cleanGeneratedApiMarkdown(path.join(docsDir, generatedApiDir)); - // Rspress derives sidebar and prev/next labels from the raw `# ` line, - // so typedoc-plugin-markdown's escaped underscores (`FOO\_BAR`) would - // surface verbatim. Intraword underscores are not emphasis in - // CommonMark, so the member title is safe to emit unescaped. // `includeVersion` is unset, so `{version}` would only leave a // trailing space in the title. app.options.setValue('pageTitleTemplates', { index: '{projectName}', module: '{kind}: {name}', - member: ({ kind, name }: { kind: string; name: string }) => - `${kind}: ${name.replace(/\\_/g, '_')}`, }); + // One page per entry point instead of one per exported symbol (#590): + // the plugin's default `kind` router emitted 916 pages per locale whose + // SSR'd sidebar was 93 % of the HTML. Members become headings on their + // module page; authored links use `/api/#`. + app.options.setValue('router', 'module'); return app; }, }), diff --git a/website/scripts/check-built-links.mjs b/website/scripts/check-built-links.mjs index fb62b4bec..e97697a34 100644 --- a/website/scripts/check-built-links.mjs +++ b/website/scripts/check-built-links.mjs @@ -10,7 +10,11 @@ // (plus `og:url`/`og:image` content, canonical/alternate links, and sitemap // ``s) to a file under doc_build honouring `cleanUrls`, and requires every // `#fragment` on an HTML target to name an `id` in that file. The llms.txt and -// `.md` copies are build assets that resolve like any other file. No dependencies. +// `.md` copies are build assets that resolve like any other file. An authored +// link into `/api/#` whose label is a bare identifier must also +// name the heading it lands on: TypeDoc member ids are github-slugger ids +// suffixed in document order (`#build-2`), so a new same-named heading upstream +// would leave the old id valid but pointing elsewhere. No dependencies. // // Usage: node scripts/check-built-links.mjs [--dir ] [--help] @@ -24,6 +28,10 @@ const TAG = /<(a|link|script|img|source|iframe|meta)\b([^>]*)>/gi; const ATTRIBUTE = /([a-zA-Z:-]+)\s*=\s*"([^"]*)"/g; const ID = /\s(?:id|name)="([^"]*)"/g; const SKIPPED_SCHEMES = /^(?:mailto:|javascript:|tel:|data:|https?:\/\/|\/\/)/i; +const ANCHOR_ELEMENT = /]*)>([\s\S]*?)<\/a>/gi; +const API_MEMBER_LINK = new RegExp(`^${BASE.replace(/[/]/g, '\\/')}(?:zh\\/)?api\\/[^#?]+#(.+)$`); +const IDENTIFIER = /^[A-Za-z_$][\w$]*$/; +const visibleText = html => unescapeHtml(html.replace(/<[^>]*>/g, '')).replace(/\(\)$/, '').trim(); const usage = `Usage: node scripts/check-built-links.mjs [--dir ] --dir built site to walk (default: website/doc_build) @@ -100,6 +108,7 @@ const main = () => { const broken = new Map(); let links = 0; let anchors = 0; + let members = 0; for (const file of files) { const html = fs.readFileSync(file, 'utf8'); const pagePath = `/${path.relative(options.dir, file).split(path.sep).join('/')}`; @@ -128,6 +137,24 @@ const main = () => { anchors += 1; if (!idsOf(target).has(fragment)) report(`no id="${fragment}" in ${path.relative(options.dir, target)}`); } + if (file.endsWith('.html') && !/^\/(?:zh\/)?api\//.test(pagePath)) { + for (const [, rawAttributes, inner] of html.matchAll(ANCHOR_ELEMENT)) { + const href = unescapeHtml(/\shref="([^"]*)"/.exec(rawAttributes)?.[1] ?? ''); + const member = API_MEMBER_LINK.exec(href.startsWith(ORIGIN) ? href.slice(ORIGIN.length) : href); + const label = member ? visibleText(inner) : ''; + if (!member || !IDENTIFIER.test(label)) continue; + const target = resolveTarget(href.replace(/#.*$/, '').replace(ORIGIN, '')); + if (target === null) continue; + members += 1; + const fragment = decode(member[1]); + const heading = new RegExp(`]*\\sid="${fragment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}"[^>]*>([\\s\\S]*?)`).exec(fs.readFileSync(target, 'utf8')); + if (heading === null) continue; + const headingLabel = visibleText(heading[1]).replace(/^#/, '').trim(); + if (headingLabel.toLowerCase() !== label.toLowerCase()) { + if (!broken.has(href)) broken.set(href, `${href} — labelled "${label}" but #${fragment} is the heading "${headingLabel}" (e.g. in ${pagePath})`); + } + } + } } // Sitemap `lastmod` (plugins/sitemap-lastmod.ts) comes from git history, or is // omitted on a shallow clone. Whatever is present must parse, must not be in @@ -141,7 +168,7 @@ const main = () => { else if (stamps.length > 10 && new Set(stamps).size < 2) broken.set('sitemap:lastmod', `sitemap.xml — every is ${stamps[0]}; dates are not coming from git history`); } for (const line of [...broken.values()].sort()) console.log(line); - console.log(`${broken.size} broken links / ${anchors} anchors checked (${links} internal links across ${files.length} files under ${options.dir})`); + console.log(`${broken.size} broken links / ${anchors} anchors checked, ${members} authored API member links matched against their headings (${links} internal links across ${files.length} files under ${options.dir})`); if (broken.size > 0) process.exitCode = 1; };