@aaplugin/extension-hooks
v1.0.0-beta.4
Published
Portable hook authoring and Platform contributors for AAPlugin.
Readme
@aaplugin/extension-hooks
Portable Hook authoring plus six official Platform Contributors for aaplugin.
Requires Node.js ^20.19.0 || ^22.13.0 || >=23.5.0.
统一书写 Hook,通过 Core Compiler 只构建一次,再由官方 Contributor 交付为六个平台各自支持的静态或运行时能力。
pnpm add -D @aaplugin/kit \
@aaplugin/platform-claude-code \
@aaplugin/extension-hooks// aaplugin.config.ts
import { defineConfig } from '@aaplugin/kit';
import claudeCode from '@aaplugin/platform-claude-code';
import hooks from '@aaplugin/extension-hooks';
export default defineConfig({
name: 'my-plugin',
version: '1.0.0',
description: 'Reusable AI workflows.',
platforms: [claudeCode()],
extensions: [hooks()],
});Each Hook is a plain ESM default export at src/hooks/<id>/hook.ts:
每个 Hook 使用独立一级目录,并通过 satisfies 获得事件级输入和结果类型。
import type { Hook } from '@aaplugin/extension-hooks';
export default {
event: 'PreToolUse',
matcher: 'Bash|Write|Edit',
timeout: 10,
platforms: {
codex: { additionalContextLimit: 2_500 },
},
async run(input, context) {
return input.toolName === 'Bash'
? { decision: 'allow' }
: { decision: 'deny', reason: `Denied on ${context.platform}.` };
},
} satisfies Hook<'PreToolUse'>;The canonical events are SessionStart, SessionEnd, UserPromptSubmit, PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, SubagentStart, SubagentStop, and Stop.
Platform-only events stay explicitly scoped and never expand that union:
平台专属事件必须显式限定;其他 Platform 不会获得产物或兼容性结论。
import type { Hook } from '@aaplugin/extension-hooks';
export default {
event: { platform: 'claude-code', name: 'Setup' },
matcher: 'init',
run() {},
} satisfies Hook;AAPlugin's Core portable-node Compiler bundles each implementation once as a self-contained, platform-neutral Node 20 ESM hooks/<id>/handler.mjs. Verified wire profiles are compiled into the same file and own native stdin schemas, camelCase conversion, runtime root/data environment mapping, and stdout mapping. The Handler validates event-specific results, keeps stdin/stdout within 1 MiB, emits only stable error codes, and requires no adjacent runtime JavaScript. Third-party code included in a Handler receives a deterministic THIRD_PARTY_LICENSES.txt.
作者不能声明原始 shell、绝对 executable、HTTP、prompt、agent 或 MCP-tool Handler;平台 wire 协议完全由对应 Contributor 管理。
Claude Code uses shell-free exec form (command: "node" plus args). Codex currently receives a fixed framework-generated command string because its public Hook schema does not expose args. A meaningful matcher is reported as degraded whenever the selected host silently ignores it, including Claude Code UserPromptSubmit/Stop and Codex UserPromptSubmit/Stop; empty Hooks produce no Assets.
OpenCode and Pi SessionStart
The generated bridges invoke PATH node explicitly and run handlers with the business workspace as both process cwd and semantic input.cwd. They do not assume the host's process.execPath is Node. Input, stdout and stderr are bounded; missing Node, handler failure, malformed output and timeout use fixed framework error codes.
OpenCode caches each session's startup result and awaits it in experimental.chat.system.transform. The context is included when that session's system prompt is constructed, without duplicate text in the same output. Startup events and initial system transforms share one in-flight execution; session deletion and instance disposal prevent late injection. continue allows SessionStart rather than blocking it.
Pi delivers SessionStart additionalContext through a hidden pi.sendMessage with triggerTurn: false. Returning text from the native session_start notification alone would not deliver context. The semantic Hook source remains unchanged.
These callback contracts were checked against the published @opencode-ai/[email protected] types and Pi Extension documentation. Generated-bridge tests are separate from real host session verification.
Portable event support:
| Platform | Native | Transformed | Degraded | Unsupported |
| --- | --- | --- | --- | --- |
| Claude Code | all 11 portable events | — | matcher on selected events | — |
| Codex | all 11 portable events | — | matcher on selected events | — |
| Cursor | — | 9 events | field-level matcher/status loss | PermissionRequest, PostCompact |
| Antigravity | SessionStart, SessionEnd, PreToolUse, PostToolUse, PreCompact | — | field-level matcher/status loss | remaining 6 events |
| OpenCode | SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PostCompact | — | SessionEnd, Stop | remaining 4 events |
| Pi | SessionStart, SessionEnd, UserPromptSubmit, PreToolUse, PostToolUse, PreCompact, PostCompact | — | Stop | PermissionRequest, SubagentStart, SubagentStop |
Strict mode rejects degraded or unsupported outcomes; relaxed mode emits only verified runtimes and preserves the full structured report. Empty Hooks produce no Asset.
Contracts were last rechecked on 2026-08-06 against Claude Code Hooks, Codex Hooks, Cursor Hooks, Antigravity Plugins, OpenCode Plugins, and Pi Extensions.
License
MIT
