feat(#1943): extensionEvents vocabulary — separate from hookEvents (extension-system surface) (#1946)

* feat(#1943): extensionEvents vocabulary — separate from hookEvents (extension-system surface)

* fix(#1943): re-export VALID_EXTENSION_EVENTS from gen-capability-registry (test import path)

* fix(#1943): regenerate capability-registry.cjs + add changeset fragment

* fix(#1943): import VALID_EXTENSION_EVENTS from validator, not gen-capability-registry (golden parity)
This commit is contained in:
Tom Boucher
2026-07-02 21:45:35 -04:00
committed by GitHub
parent d3d689a5e9
commit b51cbf96cf
11 changed files with 157 additions and 47 deletions

View File

@@ -1690,6 +1690,7 @@ const capabilities = {
},
"commandStyle": "slash-hyphen",
"hooksSurface": "none",
"extensionEvents": "opencode",
"sandboxTier": "none",
"supportTier": 2,
"installSurface": "settings-json",
@@ -4227,6 +4228,7 @@ const runtimes = {
},
"commandStyle": "slash-hyphen",
"hooksSurface": "none",
"extensionEvents": "opencode",
"sandboxTier": "none",
"supportTier": 2,
"installSurface": "settings-json",

View File

@@ -704,7 +704,12 @@ const VALID_CONFIG_FORMATS = new Set(['settings-json', 'toml', 'markdown', 'mark
const VALID_CONFIG_HOME_KINDS = new Set(['dot-home', 'dot-home-nested', 'xdg', 'generic-agents-root']);
const VALID_COMMAND_STYLES = new Set(['slash-hyphen', 'shell-var']);
const VALID_HOOKS_SURFACES = new Set(['settings-json', 'codex-hooks-json', 'cursor-hooks-json', 'copilot-inline', 'cline-rules', 'none']);
const VALID_HOOK_EVENTS = new Set(['claude', 'gemini', 'opencode-subset']);
const VALID_HOOK_EVENTS = new Set(['claude', 'gemini']);
// extensionEvents — the plugin/extension-system event dialect (ADR-1239 amendment / #1943).
// DISTINCT from hookEvents (managed-hook dialect): extensionEvents describes the
// plugin-owned event subset imperative hosts expose (opencode / pi); 'none' = the
// host exposes no extension surface (engine owns the bus, e.g. VS Code).
const VALID_EXTENSION_EVENTS = new Set(['opencode', 'pi', 'none']);
const VALID_SANDBOX_TIERS = new Set(['none', 'codex-agent-sandbox']);
const VALID_ARTIFACT_KIND_NAMES = new Set(['commands', 'agents', 'skills', 'kimi-agents']);
const VALID_ARTIFACT_NESTINGS = new Set(['flat', 'nested']);
@@ -978,7 +983,9 @@ function validateRuntimeBody(cap) {
);
}
// hookEvents — optional; if present must be in closed 3-enum (ADR-1016 Decision 5)
// hookEvents — optional; if present must be in closed enum (ADR-1016 Decision 5).
// Managed-hook dialect only (claude/gemini). The OpenCode extension-system event
// subset is NOT a hookEvents value — it is `extensionEvents` (ADR-1239 / #1943).
if (r.hookEvents !== undefined) {
if (r.hookEvents === '__proto__' || r.hookEvents === 'constructor' || r.hookEvents === 'prototype') {
errors.push('runtime.hookEvents "' + r.hookEvents + '" is a reserved name');
@@ -990,6 +997,20 @@ function validateRuntimeBody(cap) {
}
}
// extensionEvents — optional; the extension-system event dialect (ADR-1239 amendment / #1943).
// Distinct from hookEvents. Only imperative-embedding hosts (with a plugin/extension
// API) set it; declarative hosts do not.
if (r.extensionEvents !== undefined) {
if (r.extensionEvents === '__proto__' || r.extensionEvents === 'constructor' || r.extensionEvents === 'prototype') {
errors.push('runtime.extensionEvents "' + r.extensionEvents + '" is a reserved name');
} else if (!VALID_EXTENSION_EVENTS.has(r.extensionEvents)) {
errors.push(
'runtime.extensionEvents must be one of: ' + [...VALID_EXTENSION_EVENTS].join(', ') +
' (got: ' + JSON.stringify(r.extensionEvents) + ')',
);
}
}
// sandboxTier — closed 2-enum (ADR-1016 Decision 6); inline literal guard (CodeQL barrier)
if (r.sandboxTier === '__proto__' || r.sandboxTier === 'constructor' || r.sandboxTier === 'prototype') {
errors.push('runtime.sandboxTier "' + r.sandboxTier + '" is a reserved name');
@@ -2225,6 +2246,7 @@ module.exports = {
VALID_COMMAND_STYLES,
VALID_HOOKS_SURFACES,
VALID_HOOK_EVENTS,
VALID_EXTENSION_EVENTS,
VALID_SANDBOX_TIERS,
VALID_ARTIFACT_KIND_NAMES,
VALID_ARTIFACT_NESTINGS,