diff --git a/website/docs/en/guide/_meta.json b/website/docs/en/guide/_meta.json index 68529fd34..90d2081a7 100644 --- a/website/docs/en/guide/_meta.json +++ b/website/docs/en/guide/_meta.json @@ -4,6 +4,11 @@ "name": "start", "label": "Start" }, + { + "type": "dir-section-header", + "name": "concepts", + "label": "Concepts" + }, { "type": "dir-section-header", "name": "authoring", diff --git a/website/docs/en/guide/authoring/hooks.mdx b/website/docs/en/guide/authoring/hooks.mdx index 5f553c693..c5338b069 100644 --- a/website/docs/en/guide/authoring/hooks.mdx +++ b/website/docs/en/guide/authoring/hooks.mdx @@ -415,3 +415,5 @@ playground with the raw stdout, stderr, and outcome for each run. - [MCP servers and Apps](./mcp.mdx) — the other executable surface. - [Scripts and assets](./scripts-assets.mdx) — code a hook or Skill can call. +- [Compiler architecture](../concepts/architecture.mdx) — how event routes, + config hooks, and host wrappers sit in the compiler pipeline. diff --git a/website/docs/en/guide/authoring/index.mdx b/website/docs/en/guide/authoring/index.mdx index b9dd24ca8..67e350793 100644 --- a/website/docs/en/guide/authoring/index.mdx +++ b/website/docs/en/guide/authoring/index.mdx @@ -188,3 +188,7 @@ and the runtime validates with the real zod object. How a reference is resolved, - [MCP servers and Apps](./mcp.mdx) — generated route servers, handwritten stdio entries, and browser Apps. - [Scripts and assets](./scripts-assets.mdx) — artifact scripts and static files. - [Package entries](./package-entries.mdx) — `bin`, `lib`, the routed CLI, and the bundler escape hatch. + +How one route becomes MCP, CLI, and hooks — and what the compiler still +duplicates today — is in +[Compiler architecture](../concepts/architecture.mdx). diff --git a/website/docs/en/guide/authoring/mcp.mdx b/website/docs/en/guide/authoring/mcp.mdx index e0ccc2fb3..342043ed7 100644 --- a/website/docs/en/guide/authoring/mcp.mdx +++ b/website/docs/en/guide/authoring/mcp.mdx @@ -1035,3 +1035,5 @@ loopback and is never exposed beyond the local machine. - [Scripts and assets](./scripts-assets.mdx) — the non-protocol executables in an artifact. - [Package entries](./package-entries.mdx) — `bin`, `lib`, and the routed CLI. +- [Compiler architecture](../concepts/architecture.mdx) — how a generated + route sits in the application graph, a host projection, and the artifact. diff --git a/website/docs/en/guide/concepts/_meta.json b/website/docs/en/guide/concepts/_meta.json new file mode 100644 index 000000000..f9111f239 --- /dev/null +++ b/website/docs/en/guide/concepts/_meta.json @@ -0,0 +1 @@ +["architecture"] diff --git a/website/docs/en/guide/concepts/architecture.mdx b/website/docs/en/guide/concepts/architecture.mdx new file mode 100644 index 000000000..0c638087f --- /dev/null +++ b/website/docs/en/guide/concepts/architecture.mdx @@ -0,0 +1,584 @@ +--- +description: 'How agent-bundle lowers src/ conventions into a route graph, host projections, and one composite artifact, and what agent-bundle.manifest.json records today.' +--- + +# Compiler architecture + +agent-bundle compiles one project into native host plugins. This page describes +the compiler **as the code works today**: three layers of data that later +stages read, the modules that produce and consume each layer, and the +artifact manifest those stages leave behind. It is the documentation slice of +[#592](https://github.com/ScriptedAlchemy/agent-bundle/issues/592) (step 2). +Nothing here changes public behavior. + +Paths below are relative to `packages/agent-bundle/src/` unless a package +name is spelled out. Type names are the ones the compiler exports — there is +no `ApplicationIR`, `ProjectionIR`, or `ArtifactIR` type yet. + +The output layout this page describes is the **composite plugin root**: one +directory at the artifact output, with `targets` selecting which host +projections appear inside it +([#555](https://github.com/ScriptedAlchemy/agent-bundle/issues/555) Wave 1, +[PR #578](https://github.com/ScriptedAlchemy/agent-bundle/pull/578)). There +is no `artifact//` partition and no `plugin` target. + +## The three layers + +```text +src/ conventions + agent-bundle.config.ts + │ + ▼ +config/discover.ts + + routes/graph.ts (compileRouteGraph) + │ + ▼ +DiscoveredProject + (skills, commands, rules, state, routeGraph, …) + │ + ▼ +config/normalize.ts → NormalizedPlugin ← Application layer + │ + ▼ +adapters/*.ts plan() + + adapters/capabilities/*.json + │ + ▼ +TargetArtifactPlan (one per selected host) + │ + ▼ +build/compose.ts (composeProjections) ← Projection layer + │ + ▼ +CompositePlan (entries, hookEntries, identity) + │ + ▼ +build/build.ts + build/emit.ts + build/compile-stages.ts + │ + ▼ +composite plugin root + + agent-bundle.manifest.json + │ + ▼ +build/validate-artifact*.ts / AB6005 + / prepack AB7014, AB7015 ← Artifact layer +``` + +A reader who wants the filesystem conventions those arrows start from should +read [Project structure](../start/project-structure.mdx). A reader who wants +the bytes those arrows end in should read +[Targets and artifacts](../../reference/targets-artifacts.mdx). + +## Application layer + +Discovery runs once per build, then normalization freezes a host-independent +model. Two structures share that job today; they are not yet one IR. + +### What discovery produces + +`config/discover.ts` walks the project and returns a `DiscoveredProject`: + +| Collection | Source | Parser | +| --- | --- | --- | +| `skills` | `src/skills//SKILL.md` or a rendered-skill module, or explicit `skills` globs | `config/skill.ts` | +| `commands` | `src/commands/*.md` | `config/command.ts` | +| `rules` | `src/rules/*.mdc` | `config/rule.ts` | +| `state` | `src/state.ts` (opt out with `state: false`) | `config/state-extract.ts` | +| `assets` / `payloads` | `assets/` or configured `assets` / `payload` | `config/discover.ts` | +| `routeGraph` | conventional executable modules | `routes/graph.ts` | + +`compileRouteGraph` in `routes/graph.ts` is the executable-route compiler. It +globs these roots (and no others): + +```text +src/layout.{ts,tsx} +src/mcp/*/layout.{ts,tsx} +src/mcp/*/{tools,resources,prompts,apps}/*.{ts,tsx} +src/events/*/*.{ts,tsx} +src/events/stop.{ts,tsx} +src/providers/*.{ts,tsx} +src/cli/**/*.{ts,tsx} +src/scripts/**/*.{ts,tsx,jsx} +``` + +The frozen result is a `CompiledRouteGraph` (`routes/types.ts`): + +- `servers[]` — `CompiledServerSurface` (`generated` / `custom` / `command` / + `remote` / `conflict`), each holding `CompiledAgentRoute` rows of kind + `tool`, `resource`, `prompt`, or `app`. +- `cli?` — `CompiledCliSurface` (`generated` / `conventional` / `conflict`) + with `CompiledCliCommand` rows whose argv grammar comes from a bounded + `inputSchema`. +- `events[]` — `CompiledAgentRoute` rows of kind `event-route`. +- `scripts[]` — kind `script`. +- `providers[]` — `CompiledProvider` (not a route kind; they wrap execution). +- `layouts?` — `CompiledLayout` (`root` or `server` scope). Event routes and + browser Apps are never wrapped. +- `contracts?` — `RouteContract` rows (`id` = + `contract:#`), one per statically resolved `inputSchema` + declaration. Routes that import the same binding share one contract + ([#593](https://github.com/ScriptedAlchemy/agent-bundle/issues/593)). +- `digest` — sha256 over project-relative identity. +- `diagnostics` — route-graph errors (`AB48xx` and `AB494x`; `AB4838` / + `AB4839` when a schema import cannot be followed). + +Each `CompiledAgentRoute` carries `id`, `kind`, `source`, conventional +`provenance`, a statically extracted `config` (or `emptyRouteConfig`), an +optional bounded `inputSchema`, optional `contract` (the shared +`RouteContract` id), and, for MCP routes, `serverId`. Event routes also +carry `event` (`CanonicalAgentEvent` from `routes/public.ts`). + +Skills, commands, rules, hooks declared in config, handwritten MCP entries, +and native host hook documents are **not** in this graph. They stay on +`DiscoveredProject` / `NormalizedPlugin` beside it. + +### What normalization hands forward + +`config/normalize.ts` consumes `DiscoveredProject` plus the loaded config and +emits a `NormalizedPlugin` (`core/types.ts`). That is the object every later +planner reads. It does **not** retain the `CompiledRouteGraph`; +`PreparedProject` (`dev/project-service.ts`) carries `model` and +`routeGraph` as sibling fields. The plugin holds: + +- identity (`metadata`) and the selected `targets` (`NormalizedTarget[]`, + sorted unique names); +- `skills`, `commands`, `rules`, `hooks`, `nativeHooks`, `mcpServers`, + `mcpApps`, `scripts`, `assets`, `payloads`; +- `providers` and `layouts` copied off the route graph; +- `runtime.node` (the generated-executable floor); +- optional `state`, `notices`, `packageBuild`, `marketplace`, host + extensions. + +Config-declared hooks and `src/events/**` routes both land in +`NormalizedPlugin.hooks`. The event-route branch sets `eventRoute` and an +id such as `hook:event-route:tool-before` (`/` in the canonical event +replaced by `-`); the config branch does not. +Native host hook documents (Claude `hooks/hooks.json` sources, and so on) +are a third collection, `nativeHooks`. + +`config/validate.ts` runs against the same discovered project. It does not +rediscover files; it judges what discovery already found. + +### What the next layer receives + +Adapters and `build/compose.ts` receive the whole `NormalizedPlugin`. They +do not call `compileRouteGraph` again. Shared compile stages +(`build/entries.ts`, `build/cli-bins.ts`, `build/mcp-apps.ts`) also read +that model: generated MCP entries, routed CLI bins, scripts, and Apps are +planned from it once, then attributed to the composite identity. + +## Projection layer + +A **projection** is one host's representation of the same +`NormalizedPlugin`. The config key is still `targets`. After the composite +root landed, that key selects which projections are planned into the one +output directory — it does not name the artifact, the runtime, the +distribution form, or the application. + +### Where targets enter + +1. `agent-bundle.config.ts` `targets`, or CLI `--target`. Omit both and + `adapters/registry.ts` admits only the default host, `portable`. +2. `config/normalize.ts` stores the selected names on + `NormalizedPlugin.targets`. +3. `build/compose.ts` `planComposite` calls + `sortedProjections(model.targets.map((t) => t.name))` and runs + `registry.get(name).plan(model)` **only** for those names. +4. `plugin` is not a target. `targets: ['plugin']` and `--target plugin` + are `AB4100`. +5. `inspect --target` is a **display filter** on `api.ts` `inspect()`: it + keeps only that name in the printed `plans` (unknown name is `AB7004`). + It does not change `selectedTargets` or the composite identity. + `inspect --bundler` still composes the full selection. + +`adapters/composite-layout.ts` owns the selection helpers: +`sortedProjections`, `projectionIdentity` (sorted names joined by `+`, for +example `claude+codex`), `hookWrapperPath`, and +`folderDiscoveryShadowed`. + +Declaration-level `targets` on a command, rule, hook, or script still +mean "this component reaches these hosts." A component is included when that +set intersects the selection. A command or rule scoped to a subset of the +selected hosts but sitting in a directory another selected host discovers +conventionally is `AB4105`. Skills always ship to every selected host +(`skill.targets` is the selection); a per-host Skill frontmatter extension +that changes bytes is `AB4103`. + +### Who plans a projection + +Each built-in adapter implements `TargetAdapter.plan(model)` and returns a +`TargetArtifactPlan` (`adapters/types.ts`): `entries` (`write` or `copy`), +optional `hookEntries`, and `diagnostics`. + +| Host | Planner | Capability table | +| --- | --- | --- | +| `claude` | `planClaudeArtifacts` in `adapters/claude.ts` | `adapters/capabilities/claude-2.1.260.json` | +| `codex` | `planCodexArtifacts` in `adapters/codex.ts` | `adapters/capabilities/codex-0.147.0.json` | +| `cursor` | `planCursorArtifacts` in `adapters/cursor.ts` | `adapters/capabilities/cursor-2026-08-28.json` | +| `portable` | `portableAdapter.plan` in `adapters/portable.ts` | `adapters/capabilities/portable-1.0.0.json` | + +The capability JSON files are the host evidence the registry and the +generated [Hosts](../../reference/hosts.md) page read: observed versions, +manifest paths, install surfaces, path tokens, MCP transports, and +component support. Adapters consult them for what a host can express; +`compose.ts` consults `registry.hostsComponent` and +`registry.artifactLayout` when judging `AB4105`, and +`registry.noticeDelivery` when intersecting notice-delivery advertisements +across the selection. The shared MCP entries and every host's hook wrappers +are wired from that intersection so they advertise the same routes. + +`TargetRegistry` (`adapters/registry.ts`) is the only place adapters are +registered. `createDefaultRegistry` registers `portable` as the default, +then `codex`, `claude`, and `cursor`. There is no `plugin` adapter. + +### What compose hands to artifact assembly + +`composeProjections` (`build/compose.ts`) merges the selected plans: + +- Byte-identical entries at one path are kept once. Different bytes at one + path are `AB4103` (projections compared in host-name order, paths in path + order). +- `install/surface.ts` `installSurfaceEntries` is merged as a synthetic + owner (`INSTALL.md` for any built-in host; `install.mjs` when `cursor` or + `portable` is selected). +- Hook entries are concatenated; they are not merged by path. A hook that + reaches more than one selected host compiles one wrapper per host + (`hooks/..mjs`); a single-host hook keeps `hooks/.mjs` + (`hookWrapperPath`). +- Codex and Cursor hook/MCP documents live beside their manifests + (`.codex-plugin/hooks.json`, `.cursor-plugin/mcp.json`, …). When another + selected host claims the conventional `hooks/hooks.json` / `.mcp.json` / + `mcp.json` path, those projections emit an empty shield document so folder + discovery cannot load the other host's file. + +The `CompositePlan` the build stages carries `entries`, `hookEntries`, +`selected`, `identity`, `projections` (one planned host each), `cliBin` +(true when any selected host admits the routed CLI), and +`noticeDelivery`. `AB4106` is judged earlier, on the model, in +`config/validate.ts`: a selection that mixes an advanced-registry adapter +with any other target cannot share one root. + +Compiled MCP entries, scripts, routed CLI bins, and MCP Apps are **not** +re-planned per host. `build/build.ts` compiles them once with +`target: composite.identity` and writes them at the root. + +## Artifact layer + +Artifact assembly consumes the `CompositePlan` plus the compiled surfaces +and writes one tree at `artifactRoot` (CLI default `artifact/`; +`output.distPath` or `--output` moves it). + +### Writers + +| Writer | Module | What it writes | +| --- | --- | --- | +| Plan entries | `build/emit.ts` `emitPlanEntries` | Host documents, skills, commands, rules, assets, `INSTALL.md` / `install.mjs` | +| Scripts, hooks, MCP entries, CLI bins | `build/rslib.ts` `compileRslibSurfaces` via `build/entries.ts`, `build/cli-bins.ts` | `scripts/*.mjs`, `hooks/*.mjs`, `mcp/mcp--.mjs`, `bin/.mjs` (+ `-flight.mjs` workers) | +| MCP Apps | `build/mcp-apps.ts` `compileMcpApps` | `mcp-apps/.html` (inlined into the generated server as well) | +| Hook index | `build/emit.ts` `writeHookIndex` | `agent-bundle.hooks.json` over the selected hosts | +| Manifest | `build/build.ts` `manifestFor` + `build/emit.ts` `writeManifest` | `agent-bundle.manifest.json` | +| Publish | `build/emit.ts` `publishArtifact` | Atomic rename of the stage directory onto `outputRoot` | + +`build/compile-stages.ts` orders the work: MCP Apps first (the MCP entries +embed their HTML), then the node surfaces. + +### Validators + +| Check | Module | Code | +| --- | --- | --- | +| Canonical manifest parse + file digest match | `build/validate-artifact.ts` | `AB60xx` family; parse errors throw from `parseArtifactManifest` | +| Host-pack and package-build `dist` modules import only relative/`file:` specifiers or Node built-ins | `build/validate-artifact-modules.ts` | `AB6005` | +| Skills / hooks / MCP documents match the selected hosts | `build/validate-artifact-skills.ts`, `build/validate-artifact-hooks.ts`, `build/validate-artifact-mcp.ts` | per-surface `AB60xx` | +| Artifact ownership of the output root | `build/validate-artifact.ts` | `AB6014` | +| Packed tarball contains every manifest file and no unused install deps | `build/pack-inventory.ts` | `AB7010`, `AB7014`, `AB7015` | + +`AB6005` walks every emitted JavaScript module: host-pack `.mjs` rows in +`manifest.files`, and the package build's `dist` bundles (`dist/bin/*.js`, +Flight workers, the `lib` entry) before `dist` is published. A bare package +specifier fails; only Node built-ins (`node:module.isBuiltin`) may stay +external. +Prebuilt payloads (`kind: 'prebuilt'`) are hash-locked only and are not +walked. That is the same self-containment rule the generated-plugin +compiler profile enforces (`build/rslib.ts` `composeEntryLibConfig`: +`autoExternal: false`, `bundle: true`, no author-facing `externals`). + +`AB7014` / `AB7015` are the prepack gate: a `package.json` install-time +dependency must appear in packed JavaScript, declarations, `imports`, or a +consumer install script (`AB7014`), and a consumer's npm must be able to +fetch it (`AB7015`). + +### Composite root + +Built with `targets: ['claude', 'codex', 'cursor', 'portable']`, the +host-test example's root is: + +```text +artifact/ +├── .agents/plugins/marketplace.json +├── .claude-plugin/{plugin.json,marketplace.json} +├── .codex-plugin/{plugin.json,hooks.json,mcp.json} +├── .cursor-plugin/{plugin.json,marketplace.json,hooks.json,mcp.json} +├── .mcp.json +├── plugin.json, mcp.json +├── hooks/hooks.json +├── hooks/.mjs +├── hooks/.{claude,codex,cursor}.mjs +├── hooks/hooks-flight.mjs +├── mcp/mcp--.mjs (+ -flight) +├── bin/.mjs, bin/-flight.mjs +├── skills/, scripts/, commands/, rules/, assets/, mcp-apps/ +├── INSTALL.md, install.mjs +├── agent-bundle.manifest.json +└── agent-bundle.hooks.json +``` + +[Targets and artifacts](../../reference/targets-artifacts.mdx) is the +output contract: which host reads which document, the hook-wrapper naming +rule, and `AB4103` / `AB4105` / `AB4106`. This page does not repeat that +table. + +## Execution kernel and the Agent Document + +The compiler pipeline above stops at files on disk. Request time is a +separate stack. The request kernel that **does** exist is +`runAgentRequest` (`packages/rsc-runtime/src/agent-request.ts`, imported as +`@agent-bundle/runtime`). Generated MCP routes, event routes, and rendered +CLI commands call it. Config-declared hooks **bypass** it: generated +wrappers decode the host envelope and invoke the author's function +directly, with no providers, layout, or Agent Document. Native hook +documents are host JSON that adapters validate and merge; they are not +compiled wrappers and do not enter the kernel. + +| Surface | Entry | Request path | +| --- | --- | --- | +| Generated MCP stdio | `mcp-entry.ts` (lifecycle only: stdout guard, signals, shutdown) then the generated entry from `build/entry-shell.ts` | `mcp-server-runtime.ts` registers routes, runs `runAgentRequest`, renders through a warm Flight worker, and lowers tool results with `attachMcpStructuredContent` | +| Event routes | the same generated MCP server (`createEventRuntimeServer` in `events/ipc.ts`) | `events/project.ts` canonicalizes the host envelope and projects the document (`projectEventDocument`) through `runAgentRequest` | +| Config-declared hooks | generated `hooks/.mjs` from `adapters/hook-contract.ts` | host-native codec in the wrapper; **does not** call `runAgentRequest` | +| Native hook documents | adapter-declared host JSON (`nativeHooks`) | validated and merged into the host hook document; no wrapper, no kernel | +| Routed CLI | `cli-entry.ts` `runGeneratedCliEntry` | command tree from the route graph; rendered `.tsx` commands use `runAgentRequest`. CLI document types live in `cli-entry.ts` and do not import `@agent-bundle/runtime` | +| Browser Apps | host `ui/*` bridge (Workbench `McpAppFrameRelay`, `serve-app` `HOST_SCRIPT`) | the App is a view over a tool result, not a second route graph | + +`mcp-entry.ts` is the stdio process shell. It does not construct request +context. `mcp-server-runtime.ts` does: identity, lineage, providers, +`runAgentRequest`, layout (for document routes), and the MCP projection. + +The **Agent Document** is the canonical rendered-route response. The type +lives in `packages/rsc-runtime/src/agent-document.ts` and is imported as +`@agent-bundle/runtime`: + +- `version` (currently `1`) +- `status`: `success` \| `represented-error` \| `failed` +- `root`: a tree of `Agent.*` nodes (`result`, `text`, `markdown`, + `context`, `json`, `progress`, `image`, `audio`, `resource`, `error`) +- optional `value` (JSON-serializable structured result) + +MCP tool routes lower that document to `CallToolResult` content plus +`structuredContent`. Resource and prompt routes return their validated +protocol result from `document.value`. CLI human/JSON modes render the same +document through the CLI output contract. The Workbench inspects it via +`packages/workbench/src/runtime/agent-document-client.ts`. Raw +`CallToolResult` is an interop boundary, not the authoring model. + +Context values are `Observed` (`@agent-bundle/runtime`): `state` is +`available` (with `source` `native` | `receipt` | `derived`) or +`unavailable` (with a `reason`). The kernel does not invent a host or +session identity the host did not supply. + +## `agent-bundle.manifest.json` today + +The writer is `build/build.ts` `manifestFor`. It assembles an +`ArtifactManifest` (`build/manifest.ts`; TypeDoc: +[`ArtifactManifest`](../../api/interfaces/index.ArtifactManifest.md)) 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 +names the manifest itself. + +The schema is **closed in TypeScript**, not shipped as JSON Schema. +`requireExactKeys` in `build/manifest.ts` is the authority. Host +`plugin.json` / `hooks.json` / `mcp.json` schemas under +`adapters/schemas/**` and Agent Skills frontmatter under `schemas/**` are a +different contract; the website [Hosts](../../reference/hosts.md) / +[Events](../../reference/events.md) pages are generated from +`adapters/capabilities/*.json` and `docs/diagnostics.md`, not from this +manifest. Step 3 of #592 (authoritative manifest) is the follow-up that +would give this file a richer, machine-readable schema. + +### Fields the writer emits + +| Field | Shape | Source | +| --- | --- | --- | +| `producer` | `{ name: 'agent-bundle', version }` | `packages/agent-bundle/package.json` `version` | +| `project` | `configPath`, `configDigest`, `modelDigest`, `revision`, `sourceInputs[]`, optional `packageName` / `packageVersion` | `ProjectContext` from the build (`configDigest` must equal the `sourceInputs` hash of `configPath`; `revision` is `digest({ inputs: sourceInputs })`) | +| `files[]` | `path`, `bytes`, `sha256`, `kind` (`bundle` \| `copy` \| `generated` \| `prebuilt`), optional `mode`, `sourceInputs[]` | `createArtifactManifestFiles` over the staged tree + output provenance. The manifest path itself is omitted. Sorted by `path`. | +| `runtime` | `{ node }` | `NormalizedPlugin.runtime` (canonical `major.minor.patch`, must satisfy the generated-runtime floor) | +| `targets[]` | `name`, `adapterRevision`, `observedVersion`, `schemas[]` (`name`, `revision`, `sha256`) | `registry.metadata(name)` for each selected projection, sorted by `name` | +| `agentSkills` | `specification`, `sourceRevision`, `schemaSha256` | `schemas/agent-skills/contract.ts` `agentSkillsSchemaRevision` | +| `validation` | `{ artifact, source, targets[] }` each `{ status: 'passed' }` (target rows also have `name`) | written only after a successful build; `validation.targets` names must equal `targets` | + +`project.sourceInputs[]` rows are `{ path, sha256, executable? }`. +`files[].sourceInputs` are path strings that must already appear on +`project.sourceInputs`. + +There is no `routes`, `servers`, `apps`, `hooks`, `bins`, or `web` section. +A file that is a compiled MCP entry or a CLI bin appears only as a row in +`files[]`. + +### Who reads each field + +Production readers call `parseArtifactManifest` or take an already-parsed +`ArtifactManifest`. Tests are omitted. + +| Reader | Fields used | Purpose | +| --- | --- | --- | +| `build/validate-artifact.ts` | all of them | Re-parse the on-disk bytes, match `files[]` digests and modes, check `targets[]` against the registry, pin `agentSkills` and `runtime.node` | +| `build/validate-artifact-modules.ts` | `files[]` (`.mjs` rows) plus package-build `dist` | `AB6005` import graph | +| `build/validate-artifact-skills.ts` | `targets[]` (`manifestTargets`) plus the tree | Skill documents vs selected hosts | +| `build/validate-artifact-hooks.ts` | `targets[]`, hook files | Hook documents vs selected hosts | +| `build/validate-artifact-mcp.ts` | `targets[]`, MCP files | MCP documents vs selected hosts | +| `build/pack-inventory.ts` | `files[]`, `targets[]`, `project.packageVersion` | Packed tarball must contain every manifest file; install-surface requirements derived from selected names (`AB7010`); digest drift; release-version agreement; `AB7014` / `AB7015` | +| `eval/artifact.ts` | `files[]`, `targets[]`, `runtime` | `evalTargetDigests`: one digest per selected host over the **whole** file table (same bytes, distinct identity) | +| `dev/artifacts/artifact-inspection-service.ts` | `files[]`, `project`, `targets[]` | Workbench artifact inspector: rebuilds one tree from `files[]` and labels it once per selected host | +| `dev/artifacts/artifact-script-catalog.ts` | `files[]`, `targets[]` | Browser-selectable scripts. Each selected host that lays out `scripts/` gets a catalog row pointing at the **same** root file | +| `index.ts` | re-exports the types and `parse` / `serialize` / `assemble` | Public API | + +`install/install.ts` and `install/doctor.ts` **do not** read +`agent-bundle.manifest.json`. `resolveBundleRoot` looks for the Claude, +Codex, or Cursor plugin manifest (`.claude-plugin/plugin.json`, +`.codex-plugin/plugin.json`, `.cursor-plugin/plugin.json`) directly under +`--from`. Identity comes from that host document; Claude and Codex also +read the marketplace name from `.claude-plugin/marketplace.json` or +`.agents/plugins/marketplace.json`. There is no portable `install` / +`doctor` host. Missing projection is `AB7001`. + +### Step 3 gap list + +[#592](https://github.com/ScriptedAlchemy/agent-bundle/issues/592) step 3 +makes this file the compiled application database. Today the following is +inferred by re-reading source, re-probing the tree, or consulting the +in-memory `NormalizedPlugin` — none of it is in the manifest: + +1. **Route graph.** Servers, tools, resources, prompts, Apps, CLI commands, + event routes, providers, and layouts exist on `CompiledRouteGraph` + (`PreparedProject.routeGraph`) and as copied collections on + `NormalizedPlugin`. Workbench route pages and `inspect` rebuild or + retain that graph from the project, not from the artifact. +2. **MCP / CLI / App inventory.** `files[]` lists `mcp/*.mjs` and + `bin/*.mjs` as opaque paths. There is no `servers[]` with ids, + `resourceUri`, opening tools, or env. `serve-app` still resolves Apps + from the live server and the project/epoch, not from the manifest. + `dev/epoch-store.ts` and `serve-app` do not parse + `agent-bundle.manifest.json` + ([#564](https://github.com/ScriptedAlchemy/agent-bundle/issues/564) + proposes a `web` section). +3. **Hook semantics.** `agent-bundle.hooks.json` indexes wrappers; the + artifact manifest does not. Config-declared vs event-route vs native + origin is not recorded. +4. **Install / doctor.** Claude, Codex, and Cursor identity is read from + that host's `plugin.json`. Claude/Codex marketplace names come from the + corresponding marketplace document. Selected-projection membership is + "does this host's manifest path exist," not `manifest.targets`. Portable + is not an `install` / `doctor` host. +5. **Capability view.** `targets[].schemas` pins host document schemas. + Required capabilities, notice-delivery intersection, and omitted + features are not in the manifest (`inspect` `omittedFeatures` comes from + the model). +6. **Executables as first-class rows.** Mode bits on `files[]` mark + executables. There is no `bins[]` / `mcpEntries[]` with the composite + identity, allowed event targets, or launch env. +7. **Distribution metadata.** Git / npm / local source entries live in host + marketplace documents when adapters emit them, not in this file. + +## Where the code diverges today + +#592 names the splits this page must not paper over. Paths only; no fixes. + +**Discovery is not one graph.** `compileRouteGraph` covers executable +routes. Skills, commands, rules, config hooks, native hooks, and +handwritten MCP entries are parallel collections on `DiscoveredProject` / +`NormalizedPlugin`. A later consumer that needs "every surface" still walks +several fields. + +**Four planners, one merge.** `planClaudeArtifacts`, `planCodexArtifacts`, +`planCursorArtifacts`, and `portableAdapter.plan` each walk the whole +model and emit host documents. `compose.ts` merges bytes; it does not +replace those planners with a single `project(application, capabilities)` +function. + +**Three hook systems.** Config-declared `hooks..handler` +(`config/normalize.ts` `normalizeHooks`), conventional `src/events/**` +event routes (same function, `eventRoute` set), and `nativeHooks` from +adapter-declared documents. Generated wrappers (`adapters/hook-contract.ts`) +are per-host source templates. High-frequency shell hooks that cannot pay +the rendered event-route startup cost stay on the config handler path +([#595](https://github.com/ScriptedAlchemy/agent-bundle/issues/595)). + +**Duplicate MCP / CLI route modules.** Automatic MCP-to-CLI projection +exists (`routes/cli-commands.ts` `compileMcpCliCommands`), but a mature CLI +still authors a second module under `src/cli/**` when it needs its own +command path, positionals, or flag names +([#596](https://github.com/ScriptedAlchemy/agent-bundle/issues/596)). +Local `inputSchema` imports now resolve into one `RouteContract` +([#593](https://github.com/ScriptedAlchemy/agent-bundle/issues/593) +landed): an unresolvable chain is `AB4838`, a cycle is `AB4839`, and a +grammar error inside a resolved schema stays `AB4814`. + +**Browser bridge is forked.** Workbench +`packages/workbench/src/mcp/mcp-app-frame.tsx` `McpAppFrameRelay` and +`serve-app/serve-app-page.ts` `HOST_SCRIPT` implement the same relay. +Apps that need a typed client still hand-write `postMessage` +([#594](https://github.com/ScriptedAlchemy/agent-bundle/issues/594), +[#564](https://github.com/ScriptedAlchemy/agent-bundle/issues/564)). + +**Filesystem probing next to the manifest.** `install` / `doctor` +`resolveBundleRoot` probes the Claude, Codex, or Cursor `plugin.json`. Eval and the Workbench +inspector parse the artifact manifest for integrity, then still derive +scripts and host trees from path prefixes and +`registry.artifactLayout`. `evalTargetDigests` hashes the whole root once +per selected host rather than recording a per-projection view. + +**Per-target leftovers in shared surfaces.** Shared MCP / CLI / App +compile uses `composite.identity`, but hook wrappers still bake one +`target`. `artifact-script-catalog.ts` emits one catalog row per selected +host for the same file. `artifact-inspection-service.ts` labels the same +tree once per `manifest.targets[]` name. Notice delivery is the +intersection of every selected host, applied to every shared MCP entry. + +**Capability selection is still host names.** Authors write +`targets: ['claude', 'codex']` (or per-component `targets`) rather than +`requires: ['hooks.preTool']`. The capability tables exist; the compiler +does not yet resolve application requirements through them. + +## Roadmap + +[#592](https://github.com/ScriptedAlchemy/agent-bundle/issues/592) is the +umbrella. This page is step 2 (document the boundaries). The +implementation slices under it, each with its own issue: + +| Issue | Slice | +| --- | --- | +| [#555](https://github.com/ScriptedAlchemy/agent-bundle/issues/555) | Composite plugin root; `targets` as projection selection (Wave 1 landed as PR #578) | +| [#593](https://github.com/ScriptedAlchemy/agent-bundle/issues/593) | Resolve local schema imports into one route contract (**landed**) | +| [#596](https://github.com/ScriptedAlchemy/agent-bundle/issues/596) | One operation, idiomatic MCP + CLI projections | +| [#595](https://github.com/ScriptedAlchemy/agent-bundle/issues/595) | Preflight / lazy providers on the event-route kernel | +| [#594](https://github.com/ScriptedAlchemy/agent-bundle/issues/594) | Generated typed App client + shared bridge | +| [#564](https://github.com/ScriptedAlchemy/agent-bundle/issues/564) | Production `web` surface on that same bridge | + +Step 3 is an authoritative `agent-bundle.manifest.json`. The gap list +above is the input to that work. #592 stays open until the acceptance +criteria on that issue land. + +## Next + +- [Project structure](../start/project-structure.mdx) — the `src/` roots + discovery walks. +- [Configuration model](../authoring/index.mdx) — the config those roots + fill in. +- [MCP servers and Apps](../authoring/mcp.mdx) and + [Hooks](../authoring/hooks.mdx) — the two executable surfaces most + authors meet first. +- [Targets and artifacts](../../reference/targets-artifacts.mdx) — the + composite root and the shorter manifest field table. +- [Shipping a bundle](../distribution/index.mdx) — how the root compiles + and what ships inside it. +- [Artifact validation](../distribution/validation.mdx) — the checks that + re-read this manifest. diff --git a/website/docs/en/guide/start/index.mdx b/website/docs/en/guide/start/index.mdx index f3ac12100..0d9d7b406 100644 --- a/website/docs/en/guide/start/index.mdx +++ b/website/docs/en/guide/start/index.mdx @@ -85,6 +85,7 @@ than the harness produced is `inconclusive` rather than silently passing. - [Installation](./installation.mdx) — install the preview tarballs that CI publishes today. - [Quick start](./quick-start.mdx) — scaffold a project, or write the config by hand. - [Project structure](./project-structure.mdx) — the conventional `src/` roots and the output layout. +- [Compiler architecture](../concepts/architecture.mdx) — how one route becomes MCP, CLI, and hooks. - [Authoring](../authoring/index.mdx) — the configuration model and every authorable surface. The repository documents the same contracts in more depth: diff --git a/website/docs/en/guide/start/project-structure.mdx b/website/docs/en/guide/start/project-structure.mdx index 692fdf607..8a32a9a8a 100644 --- a/website/docs/en/guide/start/project-structure.mdx +++ b/website/docs/en/guide/start/project-structure.mdx @@ -182,6 +182,8 @@ export default defineConfig({ ## Next steps +- [Compiler architecture](../concepts/architecture.mdx) — how these roots + become a route graph, host projections, and one composite artifact. - [Configuration model](../authoring/index.mdx) — the full config surface. - [Skills](../authoring/skills.mdx), [Hooks](../authoring/hooks.mdx), [MCP servers and Apps](../authoring/mcp.mdx) — one page per surface. diff --git a/website/docs/en/reference/targets-artifacts.mdx b/website/docs/en/reference/targets-artifacts.mdx index 8d020e722..d587a560a 100644 --- a/website/docs/en/reference/targets-artifacts.mdx +++ b/website/docs/en/reference/targets-artifacts.mdx @@ -134,8 +134,10 @@ inventory checks the same paths (`AB7010`). ## agent-bundle.manifest.json -One manifest is emitted per root and is the input to every later integrity check — -`validate --artifact`, `prepack`, `doctor --from`, and the packed and installed-host proof levels. +One manifest is emitted per root and is the input to later integrity checks — +`validate --artifact`, `prepack`, and the packed and installed-host proof +levels. `doctor --from` and `install --from` identify the root from the +host `plugin.json` under `--from`; they do not parse this file. | Field | Contents | | --- | --- | @@ -182,6 +184,8 @@ schema pin, and emitted files and source inputs. ## Next +- [Compiler architecture](../guide/concepts/architecture.mdx) — the three + compiler layers and which production readers consume each manifest field. - [Artifact validation](../guide/distribution/validation.mdx) — the checks that read this manifest. - [Host installation](../guide/distribution/installation.mdx) — installing the root into each host. - [Runtime environment](./runtime-environment.mdx) — what the emitted executables assume at run time. diff --git a/website/docs/zh/guide/_meta.json b/website/docs/zh/guide/_meta.json index 6dbd2a884..6c316e179 100644 --- a/website/docs/zh/guide/_meta.json +++ b/website/docs/zh/guide/_meta.json @@ -4,6 +4,11 @@ "name": "start", "label": "开始" }, + { + "type": "dir-section-header", + "name": "concepts", + "label": "概念" + }, { "type": "dir-section-header", "name": "authoring", diff --git a/website/docs/zh/guide/authoring/hooks.mdx b/website/docs/zh/guide/authoring/hooks.mdx index 7105b8e7b..ce2e64374 100644 --- a/website/docs/zh/guide/authoring/hooks.mdx +++ b/website/docs/zh/guide/authoring/hooks.mdx @@ -357,3 +357,5 @@ targets、tools、timeout 与 args,因此声明的任何改动都会得到新 - [MCP 服务器与 MCP App](./mcp.mdx) —— 另一种可执行表面。 - [脚本与资源](./scripts-assets.mdx) —— 钩子或 Skill 可以调用的代码。 +- [编译器架构](../concepts/architecture.mdx) —— 事件路由、配置钩子与宿主包装层 + 在编译管线中的位置。 diff --git a/website/docs/zh/guide/authoring/index.mdx b/website/docs/zh/guide/authoring/index.mdx index 1eaa9e564..3eb57f193 100644 --- a/website/docs/zh/guide/authoring/index.mdx +++ b/website/docs/zh/guide/authoring/index.mdx @@ -171,3 +171,6 @@ schema 全部内联的路由图保持其已有的 digest。 - [MCP 服务器与 MCP App](./mcp.mdx) —— 生成式路由服务器、手写 stdio 入口与浏览器 App。 - [脚本与资源](./scripts-assets.mdx) —— 产物脚本与静态文件。 - [包入口](./package-entries.mdx) —— `bin`、`lib`、路由式 CLI 与打包器逃生舱。 + +一条路由如何同时变成 MCP、CLI 与钩子——以及编译器今天仍在哪些地方重复——见 +[编译器架构](../concepts/architecture.mdx)。 diff --git a/website/docs/zh/guide/authoring/mcp.mdx b/website/docs/zh/guide/authoring/mcp.mdx index 731238ce2..750fe75de 100644 --- a/website/docs/zh/guide/authoring/mcp.mdx +++ b/website/docs/zh/guide/authoring/mcp.mdx @@ -918,3 +918,5 @@ HTTP 端点。`--target` 默认为 `portable`,`--url` 可覆盖发现过程。 - [脚本与资源](./scripts-assets.mdx) —— 产物中非协议类的可执行文件。 - [包入口](./package-entries.mdx) —— `bin`、`lib` 与路由式 CLI。 +- [编译器架构](../concepts/architecture.mdx) —— 生成式路由如何进入应用图、 + 宿主投影与产物。 diff --git a/website/docs/zh/guide/concepts/_meta.json b/website/docs/zh/guide/concepts/_meta.json new file mode 100644 index 000000000..f9111f239 --- /dev/null +++ b/website/docs/zh/guide/concepts/_meta.json @@ -0,0 +1 @@ +["architecture"] diff --git a/website/docs/zh/guide/concepts/architecture.mdx b/website/docs/zh/guide/concepts/architecture.mdx new file mode 100644 index 000000000..9927053de --- /dev/null +++ b/website/docs/zh/guide/concepts/architecture.mdx @@ -0,0 +1,500 @@ +--- +description: 'agent-bundle 如何把 src/ 约定逐层编译为路由图、宿主投影与单一复合产物,以及 agent-bundle.manifest.json 今天记录了什么。' +--- + +# 编译器架构 + +agent-bundle 把一个项目编译为宿主原生的插件。本页描述的是编译器**在今天的代码中的实际工作 +方式**:后续阶段读取的三层数据、生产与消费每一层的模块,以及这些阶段留下的产物清单。它是 +[#592](https://github.com/ScriptedAlchemy/agent-bundle/issues/592) 的文档切片(第 2 步)。 +这里没有任何内容会改变公开行为。 + +除非明确写出包名,下文的路径都相对于 `packages/agent-bundle/src/`。类型名就是编译器导出的 +那些——目前还不存在 `ApplicationIR`、`ProjectionIR` 或 `ArtifactIR` 类型。 + +本页描述的输出布局是**复合插件根目录**:产物输出处只有一个目录,由 `targets` 选择其中出现 +哪些宿主投影 +([#555](https://github.com/ScriptedAlchemy/agent-bundle/issues/555) Wave 1, +[PR #578](https://github.com/ScriptedAlchemy/agent-bundle/pull/578))。不存在 +`artifact//` 分区,也不存在 `plugin` target。 + +## 三层 + +```text +src/ conventions + agent-bundle.config.ts + │ + ▼ +config/discover.ts + + routes/graph.ts (compileRouteGraph) + │ + ▼ +DiscoveredProject + (skills, commands, rules, state, routeGraph, …) + │ + ▼ +config/normalize.ts → NormalizedPlugin ← Application layer + │ + ▼ +adapters/*.ts plan() + + adapters/capabilities/*.json + │ + ▼ +TargetArtifactPlan (one per selected host) + │ + ▼ +build/compose.ts (composeProjections) ← Projection layer + │ + ▼ +CompositePlan (entries, hookEntries, identity) + │ + ▼ +build/build.ts + build/emit.ts + build/compile-stages.ts + │ + ▼ +composite plugin root + + agent-bundle.manifest.json + │ + ▼ +build/validate-artifact*.ts / AB6005 + / prepack AB7014, AB7015 ← Artifact layer +``` + +想了解这些箭头起点处的文件系统约定,请读[项目结构](../start/project-structure.mdx);想了解 +箭头终点处的字节,请读 [Target 与产物](../../reference/targets-artifacts.mdx)。 + +## 应用层 + +发现在每次构建中运行一次,随后规范化冻结出一个与宿主无关的模型。今天这项工作由两个结构 +分担;它们还不是同一个 IR。 + +### 发现产出什么 + +`config/discover.ts` 遍历项目并返回一个 `DiscoveredProject`: + +| 集合 | 来源 | 解析器 | +| --- | --- | --- | +| `skills` | `src/skills//SKILL.md` 或渲染式 Skill 模块,或显式的 `skills` glob | `config/skill.ts` | +| `commands` | `src/commands/*.md` | `config/command.ts` | +| `rules` | `src/rules/*.mdc` | `config/rule.ts` | +| `state` | `src/state.ts`(以 `state: false` 退出) | `config/state-extract.ts` | +| `assets` / `payloads` | `assets/`,或配置中的 `assets` / `payload` | `config/discover.ts` | +| `routeGraph` | 约定的可执行模块 | `routes/graph.ts` | + +`routes/graph.ts` 中的 `compileRouteGraph` 是可执行路由的编译器。它只 glob 下列根目录 +(不含其他): + +```text +src/layout.{ts,tsx} +src/mcp/*/layout.{ts,tsx} +src/mcp/*/{tools,resources,prompts,apps}/*.{ts,tsx} +src/events/*/*.{ts,tsx} +src/events/stop.{ts,tsx} +src/providers/*.{ts,tsx} +src/cli/**/*.{ts,tsx} +src/scripts/**/*.{ts,tsx,jsx} +``` + +冻结后的结果是一个 `CompiledRouteGraph`(`routes/types.ts`): + +- `servers[]` —— `CompiledServerSurface`(`generated` / `custom` / `command` / + `remote` / `conflict`),每个都持有 kind 为 `tool`、`resource`、`prompt` 或 `app` 的 + `CompiledAgentRoute` 行。 +- `cli?` —— `CompiledCliSurface`(`generated` / `conventional` / `conflict`),带有 + `CompiledCliCommand` 行,其 argv 语法来自有界的 `inputSchema`。 +- `events[]` —— kind 为 `event-route` 的 `CompiledAgentRoute` 行。 +- `scripts[]` —— kind 为 `script`。 +- `providers[]` —— `CompiledProvider`(不是路由 kind;它们包裹执行)。 +- `layouts?` —— `CompiledLayout`(`root` 或 `server` 作用域)。事件路由与浏览器 App + 永不被包裹。 +- `contracts?` —— `RouteContract` 行(`id` = `contract:#`),每个静态 + 解析到的 `inputSchema` 声明一份。导入同一绑定的路由共享一份契约 + ([#593](https://github.com/ScriptedAlchemy/agent-bundle/issues/593))。 +- `digest` —— 对相对项目的身份计算的 sha256。 +- `diagnostics` —— 路由图错误(`AB48xx` 与 `AB494x`;无法跟随 schema 导入时还有 + `AB4838` / `AB4839`)。 + +每个 `CompiledAgentRoute` 携带 `id`、`kind`、`source`、约定式的 `provenance`、一份静态 +提取的 `config`(或 `emptyRouteConfig`)、可选的有界 `inputSchema`、可选的 `contract` +(共享的 `RouteContract` id),以及——对 MCP 路由而言——`serverId`。事件路由还携带 +`event`(来自 `routes/public.ts` 的 `CanonicalAgentEvent`)。 + +Skill、命令、规则、配置中声明的钩子、手写的 MCP 入口以及宿主原生的钩子文档**不在**这张 +图里。它们留在与之并列的 `DiscoveredProject` / `NormalizedPlugin` 上。 + +### 规范化向前传递什么 + +`config/normalize.ts` 消费 `DiscoveredProject` 与已加载的配置,发出一个 `NormalizedPlugin` +(`core/types.ts`)。它就是之后每个规划器读取的对象。它**并不**保留 +`CompiledRouteGraph`;`PreparedProject`(`dev/project-service.ts`)把 `model` 与 +`routeGraph` 作为并列字段携带。插件对象持有: + +- 身份(`metadata`)与所选的 `targets`(`NormalizedTarget[]`,排序去重后的名称); +- `skills`、`commands`、`rules`、`hooks`、`nativeHooks`、`mcpServers`、`mcpApps`、 + `scripts`、`assets`、`payloads`; +- 从路由图复制过来的 `providers` 与 `layouts`; +- `runtime.node`(生成式可执行文件的下限); +- 可选的 `state`、`notices`、`packageBuild`、`marketplace` 与宿主扩展。 + +配置声明的钩子与 `src/events/**` 路由都落在 `NormalizedPlugin.hooks` 中。事件路由分支会 +设置 `eventRoute` 以及形如 `hook:event-route:tool-before` 的 id(规范事件名里的 `/` +换成 `-`);配置分支则不会。宿主原生的 +钩子文档(Claude 的 `hooks/hooks.json` 源等)是第三个集合 `nativeHooks`。 + +`config/validate.ts` 针对同一个已发现的项目运行。它不会重新发现文件;它只判定发现阶段 +已经找到的内容。 + +### 下一层接收什么 + +适配器与 `build/compose.ts` 接收完整的 `NormalizedPlugin`。它们不会再次调用 +`compileRouteGraph`。共享的编译阶段(`build/entries.ts`、`build/cli-bins.ts`、 +`build/mcp-apps.ts`)也读取这个模型:生成式 MCP 入口、路由式 CLI bin、脚本与 App 都从它 +规划一次,然后归属到复合身份上。 + +## 投影层 + +**投影**是同一个 `NormalizedPlugin` 在某个宿主上的表示。配置键仍然是 `targets`。复合根目录 +落地之后,这个键选择的是哪些投影会被规划进那唯一的输出目录——它并不命名产物、运行时、 +分发形式或应用。 + +### target 从哪里进入 + +1. `agent-bundle.config.ts` 的 `targets`,或 CLI 的 `--target`。两者都省略时, + `adapters/registry.ts` 只接纳默认宿主 `portable`。 +2. `config/normalize.ts` 把所选名称存到 `NormalizedPlugin.targets` 上。 +3. `build/compose.ts` 的 `planComposite` 调用 + `sortedProjections(model.targets.map((t) => t.name))`,并且**只**对这些名称运行 + `registry.get(name).plan(model)`。 +4. `plugin` 不是 target。`targets: ['plugin']` 与 `--target plugin` 都是 `AB4100`。 +5. `inspect --target` 是 `api.ts` 的 `inspect()` 上的**显示过滤器**:它只在打印的 + `plans` 中保留该名称(未知名称是 `AB7004`)。它不会改变 `selectedTargets` 或复合 + 身份。`inspect --bundler` 仍然组合完整的所选集合。 + +`adapters/composite-layout.ts` 拥有选择相关的辅助函数:`sortedProjections`、 +`projectionIdentity`(排序后的名称以 `+` 连接,例如 `claude+codex`)、`hookWrapperPath` +与 `folderDiscoveryShadowed`。 + +命令、规则、钩子或脚本上声明级的 `targets` 仍然表示“这个组件到达这些宿主”。当该集合 +与所选集合有交集时,组件就会被包含。命令或规则若只限定在所选宿主的子集上,却位于另一个所选 +宿主会按约定发现的目录中,则是 `AB4105`。Skill 总是发往每一个所选宿主 +(`skill.targets` 就是所选集合);会改变字节的按宿主 Skill frontmatter 扩展是 +`AB4103`。 + +### 谁来规划投影 + +每个内置适配器都实现 `TargetAdapter.plan(model)`,并返回一个 `TargetArtifactPlan` +(`adapters/types.ts`):`entries`(`write` 或 `copy`)、可选的 `hookEntries`,以及 +`diagnostics`。 + +| 宿主 | 规划器 | 能力表 | +| --- | --- | --- | +| `claude` | `adapters/claude.ts` 中的 `planClaudeArtifacts` | `adapters/capabilities/claude-2.1.260.json` | +| `codex` | `adapters/codex.ts` 中的 `planCodexArtifacts` | `adapters/capabilities/codex-0.147.0.json` | +| `cursor` | `adapters/cursor.ts` 中的 `planCursorArtifacts` | `adapters/capabilities/cursor-2026-08-28.json` | +| `portable` | `adapters/portable.ts` 中的 `portableAdapter.plan` | `adapters/capabilities/portable-1.0.0.json` | + +这些能力 JSON 文件是注册表与生成的[宿主参考](../../reference/hosts.md)页面所读取的宿主 +证据:观察到的版本、清单路径、安装表面、路径 token、MCP 传输方式与组件支持。适配器据此 +查询宿主能表达什么;`compose.ts` 在判定 `AB4105` 时查询 `registry.hostsComponent` 与 +`registry.artifactLayout`,在对整个所选集合求通知投递声明的交集时查询 +`registry.noticeDelivery`。共享的 MCP 入口与每个宿主的钩子包装器都由该交集接线,因此它们 +声明的是同一组路由。 + +`TargetRegistry`(`adapters/registry.ts`)是注册适配器的唯一位置。`createDefaultRegistry` +先把 `portable` 注册为默认值,然后注册 `codex`、`claude` 与 `cursor`。不存在 `plugin` +适配器。 + +### compose 交给产物组装什么 + +`composeProjections`(`build/compose.ts`)合并所选的计划: + +- 同一路径上字节相同的条目只保留一份。同一路径上字节不同则是 `AB4103`(投影按宿主名顺序 + 比较,路径按路径顺序比较)。 +- `install/surface.ts` 的 `installSurfaceEntries` 作为一个合成的所有者被合并进来(任何 + 内置宿主都有 `INSTALL.md`;选中 `cursor` 或 `portable` 时有 `install.mjs`)。 +- 钩子条目是拼接的;它们不按路径合并。到达多个所选宿主的钩子会为每个宿主编译一个包装器 + (`hooks/..mjs`);只到达单个宿主的钩子保留 `hooks/.mjs` + (`hookWrapperPath`)。 +- Codex 与 Cursor 的钩子/MCP 文档与各自的清单并列(`.codex-plugin/hooks.json`、 + `.cursor-plugin/mcp.json`……)。当另一个所选宿主认领了约定的 `hooks/hooks.json` / + `.mcp.json` / `mcp.json` 路径时,这些投影会发出一份空的屏蔽文档,使目录发现无法加载 + 另一个宿主的文件。 + +构建阶段拿到的 `CompositePlan` 携带 `entries`、`hookEntries`、`selected`、`identity`、 +`projections`(每个所选宿主一份已规划的投影)、`cliBin`(当任一所选宿主接纳路由式 CLI +时为 true)以及 `noticeDelivery`。`AB4106` 更早在模型上判定,位于 +`config/validate.ts`:把高级注册表上的适配器与任何其他 target 混在一起的选择不能共享 +一个根目录。 + +编译后的 MCP 入口、脚本、路由式 CLI bin 与 MCP App **不会**按宿主重新规划。 +`build/build.ts` 以 `target: composite.identity` 把它们编译一次,并写到根目录。 + +## 产物层 + +产物组装消费 `CompositePlan` 与已编译的表面,并在 `artifactRoot` 写出一棵目录树(CLI 默认为 +`artifact/`;`output.distPath` 或 `--output` 可以移动它)。 + +### 写入器 + +| 写入器 | 模块 | 写出什么 | +| --- | --- | --- | +| 计划条目 | `build/emit.ts` 的 `emitPlanEntries` | 宿主文档、Skill、命令、规则、资源、`INSTALL.md` / `install.mjs` | +| 脚本、钩子、MCP 入口、CLI bin | `build/rslib.ts` 的 `compileRslibSurfaces`,经由 `build/entries.ts`、`build/cli-bins.ts` | `scripts/*.mjs`、`hooks/*.mjs`、`mcp/mcp--.mjs`、`bin/.mjs`(外加 `-flight.mjs` worker) | +| MCP App | `build/mcp-apps.ts` 的 `compileMcpApps` | `mcp-apps/.html`(同时内联进生成的服务器) | +| 钩子索引 | `build/emit.ts` 的 `writeHookIndex` | 覆盖所选宿主的 `agent-bundle.hooks.json` | +| 清单 | `build/build.ts` 的 `manifestFor` + `build/emit.ts` 的 `writeManifest` | `agent-bundle.manifest.json` | +| 发布 | `build/emit.ts` 的 `publishArtifact` | 把暂存目录原子重命名到 `outputRoot` | + +`build/compile-stages.ts` 安排工作顺序:先是 MCP App(MCP 入口会嵌入它们的 HTML),然后是 +node 表面。 + +### 校验器 + +| 检查 | 模块 | 代码 | +| --- | --- | --- | +| 规范清单解析 + 文件摘要匹配 | `build/validate-artifact.ts` | `AB60xx` 系列;解析错误由 `parseArtifactManifest` 抛出 | +| 宿主包与包构建 `dist` 模块只导入相对/`file:` 说明符或 Node 内建模块 | `build/validate-artifact-modules.ts` | `AB6005` | +| Skill / 钩子 / MCP 文档与所选宿主匹配 | `build/validate-artifact-skills.ts`、`build/validate-artifact-hooks.ts`、`build/validate-artifact-mcp.ts` | 按表面划分的 `AB60xx` | +| 产物对输出根目录的所有权 | `build/validate-artifact.ts` | `AB6014` | +| 打包的 tarball 包含清单中的每个文件,且没有未使用的安装依赖 | `build/pack-inventory.ts` | `AB7010`、`AB7014`、`AB7015` | + +`AB6005` 遍历每个发出的 JavaScript 模块:`manifest.files` 中的宿主包 `.mjs` 行,以及 +包构建的 `dist` 捆绑(`dist/bin/*.js`、Flight worker、`lib` 入口)——在 `dist` 发布之前。 +裸包说明符会失败;只有 Node 内建模块(`node:module.isBuiltin`)可以保持外部。预构建 payload +(`kind: 'prebuilt'`)只做哈希锁定,不参与遍历。这与生成式插件编译器配置所强制的 +自包含规则相同(`build/rslib.ts` 的 `composeEntryLibConfig`:`autoExternal: false`、 +`bundle: true`、没有面向作者的 `externals`)。 + +`AB7014` / `AB7015` 是 prepack 门禁:`package.json` 中的安装期依赖必须出现在打包后的 +JavaScript、声明文件、`imports` 或消费者侧安装脚本中(`AB7014`),并且消费者的 npm 必须 +能够抓取它(`AB7015`)。 + +### 复合根目录 + +以 `targets: ['claude', 'codex', 'cursor', 'portable']` 构建时,host-test 示例的根目录为: + +```text +artifact/ +├── .agents/plugins/marketplace.json +├── .claude-plugin/{plugin.json,marketplace.json} +├── .codex-plugin/{plugin.json,hooks.json,mcp.json} +├── .cursor-plugin/{plugin.json,marketplace.json,hooks.json,mcp.json} +├── .mcp.json +├── plugin.json, mcp.json +├── hooks/hooks.json +├── hooks/.mjs +├── hooks/.{claude,codex,cursor}.mjs +├── hooks/hooks-flight.mjs +├── mcp/mcp--.mjs (+ -flight) +├── bin/.mjs, bin/-flight.mjs +├── skills/, scripts/, commands/, rules/, assets/, mcp-apps/ +├── INSTALL.md, install.mjs +├── agent-bundle.manifest.json +└── agent-bundle.hooks.json +``` + +[Target 与产物](../../reference/targets-artifacts.mdx)是输出契约:哪个宿主读取哪份文档、 +钩子包装器的命名规则,以及 `AB4103` / `AB4105` / `AB4106`。本页不重复那张表。 + +## 执行内核与 Agent Document + +上面的编译器流水线止于磁盘上的文件。请求时是另一套独立的栈。**已经存在**的请求内核是 +`runAgentRequest`(`packages/rsc-runtime/src/agent-request.ts`,以 +`@agent-bundle/runtime` 导入)。生成式 MCP 路由、事件路由与渲染式 CLI 命令会调用它。 +配置声明的钩子**绕过**它:生成的包装器解码宿主信封并直接调用作者的函数,没有 +provider、布局或 Agent Document。原生钩子文档是适配器校验并合并的宿主 JSON;它们不是 +编译出来的包装器,也不进入内核。 + +| 表面 | 入口 | 请求路径 | +| --- | --- | --- | +| 生成式 MCP stdio | `mcp-entry.ts`(仅生命周期:stdout 守卫、信号、关闭),然后是来自 `build/entry-shell.ts` 的生成入口 | `mcp-server-runtime.ts` 注册路由、运行 `runAgentRequest`、通过预热的 Flight worker 渲染,并用 `attachMcpStructuredContent` 对 tool 结果做降级 | +| 事件路由 | 同一个生成的 MCP 服务器(`events/ipc.ts` 中的 `createEventRuntimeServer`) | `events/project.ts` 把宿主信封规范化,并经 `runAgentRequest` 投影文档(`projectEventDocument`) | +| 配置声明的钩子 | 由 `adapters/hook-contract.ts` 生成的 `hooks/.mjs` | 包装器中的宿主原生编解码器;**不**调用 `runAgentRequest` | +| 原生钩子文档 | 适配器声明的宿主 JSON(`nativeHooks`) | 校验后合并进宿主钩子文档;没有包装器,也不进内核 | +| 路由式 CLI | `cli-entry.ts` 的 `runGeneratedCliEntry` | 来自路由图的命令树;渲染式 `.tsx` 命令使用 `runAgentRequest`。CLI 文档类型位于 `cli-entry.ts`,并不导入 `@agent-bundle/runtime` | +| 浏览器 App | 宿主 `ui/*` 桥接(Workbench 的 `McpAppFrameRelay`、`serve-app` 的 `HOST_SCRIPT`) | App 是工具结果之上的一个视图,而不是第二张路由图 | + +`mcp-entry.ts` 是 stdio 进程外壳。它不构造请求上下文。构造请求上下文的是 +`mcp-server-runtime.ts`:身份、lineage、provider、`runAgentRequest`、布局(针对文档路由) +以及 MCP 投影。 + +**Agent Document** 是渲染式路由的规范响应。其类型位于 +`packages/rsc-runtime/src/agent-document.ts`,以 `@agent-bundle/runtime` 导入: + +- `version`(当前为 `1`) +- `status`:`success` \| `represented-error` \| `failed` +- `root`:由 `Agent.*` 节点组成的树(`result`、`text`、`markdown`、`context`、`json`、 + `progress`、`image`、`audio`、`resource`、`error`) +- 可选的 `value`(可 JSON 序列化的结构化结果) + +MCP 的 tool 路由把这份文档降级为 `CallToolResult` 内容加 `structuredContent`。resource 与 +prompt 路由则返回经校验的协议结果(来自 `document.value`)。CLI 的人类可读/JSON 模式 +通过 CLI 输出契约渲染同一份文档。Workbench 通过 +`packages/workbench/src/runtime/agent-document-client.ts` 检视它。原始的 `CallToolResult` +是互操作边界,而不是编写模型。 + +上下文值是 `Observed`(`@agent-bundle/runtime`):`state` 为 `available` +(带有 `source`:`native` | `receipt` | `derived`)或 `unavailable`(带有 +`reason`)。内核不会凭空发明宿主未提供的宿主或会话身份。 + +## `agent-bundle.manifest.json` 的现状 + +写入器是 `build/build.ts` 的 `manifestFor`。它组装出一个 `ArtifactManifest` +(`build/manifest.ts`;TypeDoc: +[`ArtifactManifest`](../../api/interfaces/index.ArtifactManifest.md)),`writeManifest` +再用 `assembleArtifactManifest` 将其序列化:规范的 +`stableJson` 加一个末尾换行。`parseArtifactManifest` 拒绝任何其他字节序列、重复键、未知键、 +缺失键、未排序的数组,以及指向清单自身的文件条目。 + +该 schema **在 TypeScript 中封闭**,并不作为 JSON Schema 发布。`build/manifest.ts` 中的 +`requireExactKeys` 是权威。`adapters/schemas/**` 下的宿主 `plugin.json` / `hooks.json` / +`mcp.json` schema 与 `schemas/**` 下的 Agent Skills frontmatter 是另一份契约;网站的 +[宿主参考](../../reference/hosts.md) / [事件参考](../../reference/events.md)页面由 +`adapters/capabilities/*.json` 与 `docs/diagnostics.md` 生成,而不是由这份清单生成。#592 +的第 3 步(权威清单)是后续工作,它会给这个文件一个更丰富、机器可读的 schema。 + +### 写入器发出的字段 + +| 字段 | 形状 | 来源 | +| --- | --- | --- | +| `producer` | `{ name: 'agent-bundle', version }` | `packages/agent-bundle/package.json` 的 `version` | +| `project` | `configPath`、`configDigest`、`modelDigest`、`revision`、`sourceInputs[]`,可选的 `packageName` / `packageVersion` | 来自构建的 `ProjectContext`(`configDigest` 必须等于 `sourceInputs` 中 `configPath` 的哈希;`revision` 是 `digest({ inputs: sourceInputs })`) | +| `files[]` | `path`、`bytes`、`sha256`、`kind`(`bundle` \| `copy` \| `generated` \| `prebuilt`)、可选的 `mode`、`sourceInputs[]` | `createArtifactManifestFiles` 遍历暂存树 + 输出来源。清单路径自身被省略。按 `path` 排序。 | +| `runtime` | `{ node }` | `NormalizedPlugin.runtime`(规范的 `major.minor.patch`,必须满足生成式运行时的下限) | +| `targets[]` | `name`、`adapterRevision`、`observedVersion`、`schemas[]`(`name`、`revision`、`sha256`) | 对每个所选投影调用 `registry.metadata(name)`,按 `name` 排序 | +| `agentSkills` | `specification`、`sourceRevision`、`schemaSha256` | `schemas/agent-skills/contract.ts` 的 `agentSkillsSchemaRevision` | +| `validation` | `{ artifact, source, targets[] }`,每一项都是 `{ status: 'passed' }`(target 行还带 `name`) | 只在构建成功后写入;`validation.targets` 的名称必须与 `targets` 一致 | + +`project.sourceInputs[]` 的行是 `{ path, sha256, executable? }`。`files[].sourceInputs` 是 +路径字符串,必须已经出现在 `project.sourceInputs` 上。 + +不存在 `routes`、`servers`、`apps`、`hooks`、`bins` 或 `web` 段。一个作为编译后 MCP 入口或 +CLI bin 的文件,只以 `files[]` 中一行的形式出现。 + +### 谁读取各个字段 + +生产环境的读取方调用 `parseArtifactManifest`,或接收一个已解析的 `ArtifactManifest`。测试 +不在此列。 + +| 读取方 | 使用的字段 | 用途 | +| --- | --- | --- | +| `build/validate-artifact.ts` | 全部 | 重新解析磁盘上的字节,匹配 `files[]` 的摘要与 mode,对照注册表检查 `targets[]`,固定 `agentSkills` 与 `runtime.node` | +| `build/validate-artifact-modules.ts` | `files[]`(`.mjs` 行)以及包构建的 `dist` | `AB6005` 导入图 | +| `build/validate-artifact-skills.ts` | `targets[]`(`manifestTargets`)加目录树 | Skill 文档对照所选宿主 | +| `build/validate-artifact-hooks.ts` | `targets[]`、钩子文件 | 钩子文档对照所选宿主 | +| `build/validate-artifact-mcp.ts` | `targets[]`、MCP 文件 | MCP 文档对照所选宿主 | +| `build/pack-inventory.ts` | `files[]`、`targets[]`、`project.packageVersion` | 打包的 tarball 必须包含清单中的每个文件;由所选名称推导的安装表面要求(`AB7010`);摘要漂移;发布版本对齐;`AB7014` / `AB7015` | +| `eval/artifact.ts` | `files[]`、`targets[]`、`runtime` | `evalTargetDigests`:对**整张**文件表为每个所选宿主计算一个摘要(相同字节,不同身份) | +| `dev/artifacts/artifact-inspection-service.ts` | `files[]`、`project`、`targets[]` | Workbench 产物检视器:从 `files[]` 重建一棵树,并为每个所选宿主各标注一次 | +| `dev/artifacts/artifact-script-catalog.ts` | `files[]`、`targets[]` | 可在浏览器中选择的脚本。每个布局了 `scripts/` 的所选宿主都得到一行目录条目,指向**同一个**根文件 | +| `index.ts` | 重新导出这些类型与 `parse` / `serialize` / `assemble` | 公开 API | + +`install/install.ts` 与 `install/doctor.ts` **不**读取 `agent-bundle.manifest.json`。 +`resolveBundleRoot` 直接在 `--from` 之下查找 Claude、Codex 或 Cursor 的插件清单 +(`.claude-plugin/plugin.json`、`.codex-plugin/plugin.json`、 +`.cursor-plugin/plugin.json`)。身份来自该宿主文档;Claude 与 Codex 还会从 +`.claude-plugin/marketplace.json` 或 `.agents/plugins/marketplace.json` 读取市场名称。 +不存在 portable 的 `install` / `doctor` 宿主。缺少投影是 `AB7001`。 + +### 第 3 步的差距列表 + +[#592](https://github.com/ScriptedAlchemy/agent-bundle/issues/592) 的第 3 步会让这个文件 +成为编译后的应用数据库。今天,下列内容都是通过重新读取源码、重新探测目录树或查询内存中的 +`NormalizedPlugin` 推断出来的——没有一项在清单里: + +1. **路由图。** 服务器、工具、资源、提示、App、CLI 命令、事件路由、provider 与布局存在于 + `CompiledRouteGraph`(`PreparedProject.routeGraph`)以及 `NormalizedPlugin` 上复制过来 + 的集合中。Workbench 的路由页面与 `inspect` 是从项目而不是从产物重建或保留这张图的。 +2. **MCP / CLI / App 清点。** `files[]` 把 `mcp/*.mjs` 与 `bin/*.mjs` 列为不透明路径。 + 不存在带有 id、`resourceUri`、打开工具或 env 的 `servers[]`。`serve-app` 仍然从活跃 + 服务器与项目/epoch 解析 App,而不是从清单解析。`dev/epoch-store.ts` 与 `serve-app` + 都不解析 `agent-bundle.manifest.json` + ([#564](https://github.com/ScriptedAlchemy/agent-bundle/issues/564) 提议增加一个 + `web` 段)。 +3. **钩子语义。** `agent-bundle.hooks.json` 索引了包装器;产物清单没有。配置声明、事件路由 + 还是原生这三种来源没有被记录。 +4. **Install / doctor。** Claude、Codex 与 Cursor 的身份从该宿主的 `plugin.json` + 读取。Claude/Codex 的市场名称来自对应的市场文档。所选投影的成员关系是“这个宿主的 + 清单路径是否存在”,而不是 `manifest.targets`。portable 不是 `install` / `doctor` + 宿主。 +5. **能力视图。** `targets[].schemas` 固定了宿主文档 schema。所需能力、通知投递交集与被 + 省略的特性都不在清单中(`inspect` 的 `omittedFeatures` 来自模型)。 +6. **作为一等行的可执行文件。** `files[]` 上的 mode 位标记了可执行文件。不存在带有复合 + 身份、允许的事件 target 或启动 env 的 `bins[]` / `mcpEntries[]`。 +7. **分发元数据。** Git / npm / 本地来源条目在适配器输出它们时位于宿主的市场文档中,而不在 + 这个文件里。 + +## 代码今天在哪里分叉 + +#592 点名了本页不得掩盖的那些分裂。这里只列路径,不给修复。 + +**发现不是一张图。** `compileRouteGraph` 覆盖可执行路由。Skill、命令、规则、配置钩子、 +原生钩子与手写的 MCP 入口是 `DiscoveredProject` / `NormalizedPlugin` 上彼此平行的集合。 +之后需要“每一个表面”的消费者仍要遍历多个字段。 + +**四个规划器,一次合并。** `planClaudeArtifacts`、`planCodexArtifacts`、 +`planCursorArtifacts` 与 `portableAdapter.plan` 各自遍历整个模型并输出宿主文档。 +`compose.ts` 合并的是字节;它并没有用单个 `project(application, capabilities)` 函数取代 +这些规划器。 + +**三套钩子系统。** 配置声明的 `hooks..handler`(`config/normalize.ts` 的 +`normalizeHooks`)、约定的 `src/events/**` 事件路由(同一个函数,设置了 `eventRoute`), +以及来自适配器声明文档的 `nativeHooks`。生成的包装器(`adapters/hook-contract.ts`)是按 +宿主划分的源码模板。无法承担渲染式事件路由启动开销的高频 shell 钩子仍走配置处理器路径 +([#595](https://github.com/ScriptedAlchemy/agent-bundle/issues/595))。 + +**重复的 MCP / CLI 路由模块。** 自动的 MCP 到 CLI 投影是存在的(`routes/cli-commands.ts` +的 `compileMcpCliCommands`),但成熟的 CLI 在需要自己的命令路径、位置参数或标志名时, +仍会在 `src/cli/**` 下另写一个模块 +([#596](https://github.com/ScriptedAlchemy/agent-bundle/issues/596))。本地 `inputSchema` +导入现在会解析成一份 `RouteContract` +([#593](https://github.com/ScriptedAlchemy/agent-bundle/issues/593) 已落地):无法跟随的 +链是 `AB4838`,环是 `AB4839`,已解析 schema 内部的语法错误仍是 `AB4814`。 + +**浏览器桥接被分叉。** Workbench 的 `packages/workbench/src/mcp/mcp-app-frame.tsx` +`McpAppFrameRelay` 与 `serve-app/serve-app-page.ts` 的 `HOST_SCRIPT` 实现了同一个中继。 +需要类型化客户端的 App 仍在手写 `postMessage` +([#594](https://github.com/ScriptedAlchemy/agent-bundle/issues/594)、 +[#564](https://github.com/ScriptedAlchemy/agent-bundle/issues/564))。 + +**与清单并存的文件系统探测。** `install` / `doctor` 的 `resolveBundleRoot` 探测 +Claude、Codex 或 Cursor 的 `plugin.json`。Eval 与 Workbench 检视器为完整性解析产物清单,随后仍从路径前缀与 +`registry.artifactLayout` 推导脚本与宿主目录树。`evalTargetDigests` 为每个所选宿主把整个 +根目录各哈希一遍,而不是记录一份按投影划分的视图。 + +**共享表面中残留的按 target 逻辑。** 共享的 MCP / CLI / App 编译使用 +`composite.identity`,但钩子包装器仍然固化一个 `target`。`artifact-script-catalog.ts` 为 +同一个文件按每个所选宿主各输出一行目录条目。`artifact-inspection-service.ts` 为每个 +`manifest.targets[]` 名称把同一棵树各标注一次。通知投递是所有所选宿主的交集,应用到每一个 +共享的 MCP 入口上。 + +**能力选择仍然是宿主名。** 作者写的是 `targets: ['claude', 'codex']`(或按组件的 +`targets`),而不是 `requires: ['hooks.preTool']`。能力表是存在的;编译器还没有通过它们来 +解析应用需求。 + +## 路线图 + +[#592](https://github.com/ScriptedAlchemy/agent-bundle/issues/592) 是总纲。本页是第 2 步 +(记录边界)。它之下的实现切片各有自己的 issue: + +| Issue | 切片 | +| --- | --- | +| [#555](https://github.com/ScriptedAlchemy/agent-bundle/issues/555) | 复合插件根目录;`targets` 作为投影选择(Wave 1 已作为 PR #578 落地) | +| [#593](https://github.com/ScriptedAlchemy/agent-bundle/issues/593) | 把本地 schema 导入解析进同一份路由契约(**已落地**) | +| [#596](https://github.com/ScriptedAlchemy/agent-bundle/issues/596) | 一个操作,地道的 MCP + CLI 投影 | +| [#595](https://github.com/ScriptedAlchemy/agent-bundle/issues/595) | 事件路由内核上的预检 / 惰性 provider | +| [#594](https://github.com/ScriptedAlchemy/agent-bundle/issues/594) | 生成的类型化 App 客户端 + 共享桥接 | +| [#564](https://github.com/ScriptedAlchemy/agent-bundle/issues/564) | 基于同一桥接的生产 `web` 表面 | + +第 3 步是一份权威的 `agent-bundle.manifest.json`。上面的差距列表就是那项工作的输入。#592 +会一直保持打开,直到该 issue 上的验收标准落地。 + +## 下一步 + +- [项目结构](../start/project-structure.mdx) —— 发现所遍历的 `src/` 根目录。 +- [配置模型](../authoring/index.mdx) —— 这些根目录所填充的配置。 +- [MCP 服务器与 MCP App](../authoring/mcp.mdx) 与[钩子](../authoring/hooks.mdx) —— 大多数 + 作者最先遇到的两个可执行表面。 +- [Target 与产物](../../reference/targets-artifacts.mdx) —— 复合根目录与更简短的清单 + 字段表。 +- [交付捆绑包](../distribution/index.mdx) —— 根目录如何编译,以及其中装了什么。 +- [产物校验](../distribution/validation.mdx) —— 重新读取这份清单的那些检查。 diff --git a/website/docs/zh/guide/start/index.mdx b/website/docs/zh/guide/start/index.mdx index 4c2d646ba..aa807d0dc 100644 --- a/website/docs/zh/guide/start/index.mdx +++ b/website/docs/zh/guide/start/index.mdx @@ -77,6 +77,7 @@ CLI 派发、打包后的 stdio、删除源码后的打包运行,以及宿主 - [安装](./installation.mdx) —— 安装 CI 目前发布的预览包。 - [快速开始](./quick-start.mdx) —— 使用脚手架,或手写配置。 - [项目结构](./project-structure.mdx) —— 约定的 `src/` 根目录与输出布局。 +- [编译器架构](../concepts/architecture.mdx) —— 一条路由如何变成 MCP、CLI 与钩子。 - [编写](../authoring/index.mdx) —— 配置模型与每一种可编写的表面。 仓库中对同样的契约有更深入的说明: diff --git a/website/docs/zh/guide/start/project-structure.mdx b/website/docs/zh/guide/start/project-structure.mdx index 1c04bfeb4..251b7897e 100644 --- a/website/docs/zh/guide/start/project-structure.mdx +++ b/website/docs/zh/guide/start/project-structure.mdx @@ -170,6 +170,8 @@ export default defineConfig({ ## 下一步 +- [编译器架构](../concepts/architecture.mdx) —— 这些根目录如何变成路由图、 + 宿主投影与一份复合产物。 - [配置模型](../authoring/index.mdx) —— 完整的配置表面。 - [Skills](../authoring/skills.mdx)、[钩子](../authoring/hooks.mdx)、 [MCP 服务器与 MCP App](../authoring/mcp.mdx) —— 每种表面一页。 diff --git a/website/docs/zh/reference/targets-artifacts.mdx b/website/docs/zh/reference/targets-artifacts.mdx index 10b52d471..0c7b757fb 100644 --- a/website/docs/zh/reference/targets-artifacts.mdx +++ b/website/docs/zh/reference/targets-artifacts.mdx @@ -121,8 +121,9 @@ MCP 入口、脚本、路由式 CLI bin 与 MCP App 只编译**一次**,归属 ## agent-bundle.manifest.json -每个根目录输出一份清单,它是之后每一项完整性检查的输入 —— `validate --artifact`、`prepack`、 -`doctor --from`,以及 packed 与 installed-host 证明级别。 +每个根目录输出一份清单,它是之后完整性检查的输入 —— `validate --artifact`、`prepack`, +以及 packed 与 installed-host 证明级别。`doctor --from` 与 `install --from` 通过 `--from` +下的宿主 `plugin.json` 识别根目录;它们不解析这个文件。 | 字段 | 内容 | | --- | --- | @@ -162,6 +163,8 @@ target 行还记录 `adapterRevision`(单调递增,仓库自有)与 `obser ## 下一步 +- [编译器架构](../guide/concepts/architecture.mdx) —— 编译器的三层,以及哪些 + 生产读者消费清单的每个字段。 - [产物校验](../guide/distribution/validation.mdx) —— 读取这份清单的那些检查。 - [宿主安装](../guide/distribution/installation.mdx) —— 把根目录安装进各个宿主。 - [运行时环境](./runtime-environment.mdx) —— 输出的可执行文件在运行时假定了什么。