Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/public-capability-table-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'agent-bundle': patch
---

Export the `CapabilityRow` and `HostCapabilityTable` capability-table types. (#626)
22 changes: 20 additions & 2 deletions packages/agent-bundle/src/adapters/capability-state.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CapabilityStateError, unknownCapabilityStateError } from '../core/capabilities.ts';
import type { CapabilityEvidence, CapabilityState } from '../core/capabilities.ts';
import { featureCapabilityName } from '../core/components.ts';
import type { JsonObject } from '../core/strict-json.ts';
import {
NOTICE_DELIVERY_ROUTES,
NOTICE_SENSITIVITIES,
Expand Down Expand Up @@ -43,6 +44,24 @@ export const unavailableCapability = (reason: string): CapabilityState => Object
state: 'unavailable',
});

/** A row from a pinned host capability table. */
export interface CapabilityRow {
readonly availability?: Readonly<Record<string, { readonly reason?: string; readonly state?: string }>>;
readonly evidence?: readonly string[];
readonly nativeEvent?: string;
readonly payload?: JsonObject;
readonly reason?: string;
readonly state?: string;
}

/** A loaded pinned host capability table and its source identity. */
export interface HostCapabilityTable {
readonly data: JsonObject;
readonly fileName: string;
readonly host: string;
readonly version: string;
}

export interface EventRouteCapabilityTableEntry {
readonly nativeEvent?: string;
/**
Expand Down Expand Up @@ -90,8 +109,7 @@ export const supportedEventRouteNamesFrom = (
));

/** A pinned capability-table row: JSON imports widen the state literal, so unknown states fail closed. */
export interface CapabilityTableRow {
readonly reason?: string;
export interface CapabilityTableRow extends CapabilityRow {
readonly state: string;
}

Expand Down
1 change: 1 addition & 0 deletions packages/agent-bundle/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ export type AgentBundleConfig = CoreAgentBundleConfig
& PortableConfigExtension;

export type { PortableAuthorConfig, PortableManifestConfig } from './adapters/portable.ts';
export type { CapabilityRow, HostCapabilityTable } from './adapters/capability-state.ts';

// The config hook handler contract (#488): the payload a `hooks.<event>.handler`
// receives and the result the generated wrapper admits, per canonical event.
Expand Down
30 changes: 15 additions & 15 deletions website/docs/en/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -119,32 +119,32 @@ declaration, because a handler has to be bound to an event.
```text title="artifact/"
artifact/
├── .claude-plugin/
│ ├── plugin.json # Claude Code manifest
│ ├── plugin.json
│ └── marketplace.json
├── .codex-plugin/
│ ├── plugin.json # Codex manifest
│ ├── hooks.json # Codex hook document
│ └── mcp.json # Codex MCP document
├── .agents/plugins/marketplace.json # Codex marketplace
├── .mcp.json # Claude Code MCP document
├── plugin.json # portable (Agent Plugins) manifest
├── mcp.json # portable MCP document
│ ├── plugin.json
│ ├── hooks.json
│ └── mcp.json
├── .agents/plugins/marketplace.json
├── .mcp.json
├── plugin.json
├── mcp.json
├── hooks/
│ ├── hooks.json # Claude Code hook document
│ ├── session-start-….claude.mjs # one wrapper per host the hook reaches
│ ├── hooks.json
│ ├── session-start-….claude.mjs
│ ├── session-start-….codex.mjs
│ └── hooks-flight.mjs
├── mcp/
│ ├── mcp-status-….mjs # compiled once, shared by every host
│ ├── mcp-status-….mjs
│ └── mcp-status-…-flight.mjs
├── scripts/check-service.mjs
├── skills/release-review/
│ ├── SKILL.md
│ └── references/policy.md
├── INSTALL.md # one section per selected host
├── install.mjs # installer for portable and Cursor
├── agent-bundle.manifest.json # every emitted file with its SHA-256
└── agent-bundle.hooks.json # hook index over the selected hosts
├── INSTALL.md
├── install.mjs
├── agent-bundle.manifest.json
└── agent-bundle.hooks.json
```

Every selected host reads this one directory as its plugin root: Claude Code finds
Expand Down
30 changes: 15 additions & 15 deletions website/docs/zh/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -116,32 +116,32 @@ Skill、MCP 服务器与脚本都按约定被发现。只有钩子需要声明
```text title="artifact/"
artifact/
├── .claude-plugin/
│ ├── plugin.json # Claude Code 清单
│ ├── plugin.json
│ └── marketplace.json
├── .codex-plugin/
│ ├── plugin.json # Codex 清单
│ ├── hooks.json # Codex 钩子文档
│ └── mcp.json # Codex MCP 文档
├── .agents/plugins/marketplace.json # Codex marketplace
├── .mcp.json # Claude Code MCP 文档
├── plugin.json # portable(Agent Plugins)清单
├── mcp.json # portable MCP 文档
│ ├── plugin.json
│ ├── hooks.json
│ └── mcp.json
├── .agents/plugins/marketplace.json
├── .mcp.json
├── plugin.json
├── mcp.json
├── hooks/
│ ├── hooks.json # Claude Code 钩子文档
│ ├── session-start-….claude.mjs # 钩子到达的每个宿主各一个包装脚本
│ ├── hooks.json
│ ├── session-start-….claude.mjs
│ ├── session-start-….codex.mjs
│ └── hooks-flight.mjs
├── mcp/
│ ├── mcp-status-….mjs # 只编译一次,所有宿主共用
│ ├── mcp-status-….mjs
│ └── mcp-status-…-flight.mjs
├── scripts/check-service.mjs
├── skills/release-review/
│ ├── SKILL.md
│ └── references/policy.md
├── INSTALL.md # 每个所选宿主一节
├── install.mjs # portable 与 Cursor 的安装器
├── agent-bundle.manifest.json # 每个输出文件及其 SHA-256
└── agent-bundle.hooks.json # 覆盖所选宿主的钩子索引
├── INSTALL.md
├── install.mjs
├── agent-bundle.manifest.json
└── agent-bundle.hooks.json
```

每个所选宿主都把这同一个目录当作自己的插件根目录来读取:Claude Code 找到 `.claude-plugin/`、
Expand Down
27 changes: 6 additions & 21 deletions website/plugins/generated-reference.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
import path from 'node:path';
import type { RspressPlugin } from '@rspress/core';
import type {
CapabilityRow,
HostCapabilityTable,
} from '../../packages/agent-bundle/src/adapters/capability-state.ts';
import type { JsonObject, JsonValue } from '../../packages/agent-bundle/src/core/strict-json.ts';

/**
* Build-time reference pages rendered from repository sources of truth:
Expand All @@ -15,26 +20,6 @@ import type { RspressPlugin } from '@rspress/core';
* artifacts exactly like authored pages, while never being committed.
*/

type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };
type JsonObject = { [key: string]: JsonValue };

interface CapabilityRow {
readonly state?: string;
readonly reason?: string;
readonly nativeEvent?: string;
readonly evidence?: readonly string[];
readonly availability?: Readonly<Record<string, { readonly state?: string; readonly reason?: string }>>;
/** Canonical payload field → host key (or `{ nativeKey, decode }`), on supported event-route rows. */
readonly payload?: JsonObject;
}

interface HostCapabilityTable {
readonly fileName: string;
readonly host: string;
readonly version: string;
readonly data: JsonObject;
}

export interface GeneratedReferenceLocale {
/** Locale key, such as `en` or `zh`. */
readonly lang: 'en' | 'zh';
Expand Down Expand Up @@ -79,7 +64,7 @@ const mcpPathTokenFields = (host: JsonObject): JsonObject => {
return {};
}
const groups = asObject(substitution.fields);
const derived: JsonObject = {};
const derived: Record<string, JsonValue> = {};
for (const group of ['mcpStdio', 'mcpRemote']) {
const fields = groups[group];
if (Array.isArray(fields)) {
Expand Down
Loading