@s_s/agent-kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +317 -0
- package/build/create-kit.d.ts +16 -0
- package/build/create-kit.js +54 -0
- package/build/create-kit.js.map +1 -0
- package/build/detect.d.ts +13 -0
- package/build/detect.js +34 -0
- package/build/detect.js.map +1 -0
- package/build/hook-capabilities.d.ts +87 -0
- package/build/hook-capabilities.js +191 -0
- package/build/hook-capabilities.js.map +1 -0
- package/build/hook-registry.d.ts +158 -0
- package/build/hook-registry.js +223 -0
- package/build/hook-registry.js.map +1 -0
- package/build/hook-translators/claude-code.d.ts +26 -0
- package/build/hook-translators/claude-code.js +351 -0
- package/build/hook-translators/claude-code.js.map +1 -0
- package/build/hook-translators/index.d.ts +4 -0
- package/build/hook-translators/index.js +4 -0
- package/build/hook-translators/index.js.map +1 -0
- package/build/hook-translators/openclaw.d.ts +25 -0
- package/build/hook-translators/openclaw.js +272 -0
- package/build/hook-translators/openclaw.js.map +1 -0
- package/build/hook-translators/opencode.d.ts +23 -0
- package/build/hook-translators/opencode.js +254 -0
- package/build/hook-translators/opencode.js.map +1 -0
- package/build/hook-translators/types.d.ts +59 -0
- package/build/hook-translators/types.js +2 -0
- package/build/hook-translators/types.js.map +1 -0
- package/build/hook-types.d.ts +155 -0
- package/build/hook-types.js +2 -0
- package/build/hook-types.js.map +1 -0
- package/build/hooks.d.ts +30 -0
- package/build/hooks.js +333 -0
- package/build/hooks.js.map +1 -0
- package/build/index.d.ts +9 -0
- package/build/index.js +11 -0
- package/build/index.js.map +1 -0
- package/build/platform.d.ts +17 -0
- package/build/platform.js +79 -0
- package/build/platform.js.map +1 -0
- package/build/prompt.d.ts +21 -0
- package/build/prompt.js +87 -0
- package/build/prompt.js.map +1 -0
- package/build/register.d.ts +18 -0
- package/build/register.js +34 -0
- package/build/register.js.map +1 -0
- package/build/types.d.ts +111 -0
- package/build/types.js +53 -0
- package/build/types.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Helpers
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
function capitalize(str) {
|
|
5
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
6
|
+
}
|
|
7
|
+
function matcherToRegex(match) {
|
|
8
|
+
if (match === undefined || match === '*')
|
|
9
|
+
return '/.*/';
|
|
10
|
+
if (match instanceof RegExp)
|
|
11
|
+
return match.toString();
|
|
12
|
+
return `/${match}/`;
|
|
13
|
+
}
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// OpenClaw Translator
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
/**
|
|
18
|
+
* Translates intent-based hooks into OpenClaw native format.
|
|
19
|
+
*
|
|
20
|
+
* OpenClaw dual-layer system:
|
|
21
|
+
* - Internal hooks: type:action string keys, event objects, errors never propagate
|
|
22
|
+
* - Plugin hooks: typed, validated, modifying hooks run sequentially by priority
|
|
23
|
+
*
|
|
24
|
+
* File format:
|
|
25
|
+
* - HOOK.md with YAML frontmatter (name, description, metadata.openclaw.events)
|
|
26
|
+
* - handler.ts exporting default async function
|
|
27
|
+
*/
|
|
28
|
+
export class OpenClawTranslator {
|
|
29
|
+
translate(intents, rawHooks, extendHooks, toolName) {
|
|
30
|
+
const files = {};
|
|
31
|
+
const warnings = [];
|
|
32
|
+
const skipped = [];
|
|
33
|
+
// OpenClaw hook files live in subdirectories per hook type.
|
|
34
|
+
// We collect all events that the main handler needs to respond to,
|
|
35
|
+
// and internal hooks that need separate registration.
|
|
36
|
+
const pluginEvents = new Set();
|
|
37
|
+
const internalEvents = new Set();
|
|
38
|
+
const handlerSections = [];
|
|
39
|
+
// Track intent-generated hooks for conflict detection
|
|
40
|
+
const intentGeneratedPluginHooks = new Set();
|
|
41
|
+
const intentGeneratedInternalHooks = new Set();
|
|
42
|
+
// --- inject intents ---
|
|
43
|
+
const injectIntents = intents.filter((i) => i.type === 'inject');
|
|
44
|
+
if (injectIntents.length > 0) {
|
|
45
|
+
const internalHook = 'agent:bootstrap';
|
|
46
|
+
if (rawHooks.has(`openclaw::${internalHook}`)) {
|
|
47
|
+
warnings.push(`[openclaw] raw hook for ${internalHook} overrides inject intent.`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
internalEvents.add(internalHook);
|
|
51
|
+
intentGeneratedInternalHooks.add(internalHook);
|
|
52
|
+
const reminderParts = injectIntents
|
|
53
|
+
.flatMap((i) => [i.sessionStart, i.perTurn].filter(Boolean))
|
|
54
|
+
.join('\\n\\n');
|
|
55
|
+
handlerSections.push(this.buildInjectSection(toolName, reminderParts));
|
|
56
|
+
}
|
|
57
|
+
// session_start / session_end via plugin hooks
|
|
58
|
+
const sessionStarts = injectIntents.filter((i) => i.sessionStart);
|
|
59
|
+
if (sessionStarts.length > 0 && !rawHooks.has('openclaw::session_start')) {
|
|
60
|
+
pluginEvents.add('session_start');
|
|
61
|
+
intentGeneratedPluginHooks.add('session_start');
|
|
62
|
+
}
|
|
63
|
+
const sessionEnds = injectIntents.filter((i) => i.sessionEnd);
|
|
64
|
+
if (sessionEnds.length > 0 && !rawHooks.has('openclaw::session_end')) {
|
|
65
|
+
pluginEvents.add('session_end');
|
|
66
|
+
intentGeneratedPluginHooks.add('session_end');
|
|
67
|
+
const combined = sessionEnds.map((i) => i.sessionEnd).join('\\n\\n');
|
|
68
|
+
handlerSections.push(this.buildSessionEndInjectSection(combined));
|
|
69
|
+
}
|
|
70
|
+
// compaction → session:compact:before (internal) or before_compaction (plugin)
|
|
71
|
+
const compactions = injectIntents.filter((i) => i.compaction);
|
|
72
|
+
if (compactions.length > 0) {
|
|
73
|
+
if (!rawHooks.has('openclaw::before_compaction')) {
|
|
74
|
+
pluginEvents.add('before_compaction');
|
|
75
|
+
intentGeneratedPluginHooks.add('before_compaction');
|
|
76
|
+
const combined = compactions.map((i) => i.compaction).join('\\n\\n');
|
|
77
|
+
handlerSections.push(this.buildCompactionSection(combined));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// --- beforeToolCall intents ---
|
|
82
|
+
const beforeIntents = intents.filter((i) => i.type === 'beforeToolCall');
|
|
83
|
+
if (beforeIntents.length > 0) {
|
|
84
|
+
const hookName = 'before_tool_call';
|
|
85
|
+
if (rawHooks.has(`openclaw::${hookName}`)) {
|
|
86
|
+
warnings.push(`[openclaw] raw hook for ${hookName} overrides beforeToolCall intent.`);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
pluginEvents.add(hookName);
|
|
90
|
+
intentGeneratedPluginHooks.add(hookName);
|
|
91
|
+
handlerSections.push(this.buildBeforeToolCallSection(beforeIntents));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// --- afterToolCall intents ---
|
|
95
|
+
const afterIntents = intents.filter((i) => i.type === 'afterToolCall');
|
|
96
|
+
if (afterIntents.length > 0) {
|
|
97
|
+
const hookName = 'after_tool_call';
|
|
98
|
+
if (rawHooks.has(`openclaw::${hookName}`)) {
|
|
99
|
+
warnings.push(`[openclaw] raw hook for ${hookName} overrides afterToolCall intent.`);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
pluginEvents.add(hookName);
|
|
103
|
+
intentGeneratedPluginHooks.add(hookName);
|
|
104
|
+
handlerSections.push(this.buildAfterToolCallSection(afterIntents));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// --- onSession intents ---
|
|
108
|
+
const sessionIntents = intents.filter((i) => i.type === 'onSession');
|
|
109
|
+
if (sessionIntents.length > 0) {
|
|
110
|
+
const hasStart = sessionIntents.some((i) => i.start);
|
|
111
|
+
const hasEnd = sessionIntents.some((i) => i.end);
|
|
112
|
+
if (hasStart && !intentGeneratedPluginHooks.has('session_start')) {
|
|
113
|
+
if (rawHooks.has('openclaw::session_start')) {
|
|
114
|
+
warnings.push(`[openclaw] raw hook for session_start overrides onSession.start intent.`);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
pluginEvents.add('session_start');
|
|
118
|
+
intentGeneratedPluginHooks.add('session_start');
|
|
119
|
+
handlerSections.push(this.buildOnSessionSection('start'));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (hasEnd && !intentGeneratedPluginHooks.has('session_end')) {
|
|
123
|
+
if (rawHooks.has('openclaw::session_end')) {
|
|
124
|
+
warnings.push(`[openclaw] raw hook for session_end overrides onSession.end intent.`);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
pluginEvents.add('session_end');
|
|
128
|
+
intentGeneratedPluginHooks.add('session_end');
|
|
129
|
+
handlerSections.push(this.buildOnSessionSection('end'));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// --- onPermission intents ---
|
|
134
|
+
const permIntents = intents.filter((i) => i.type === 'onPermission');
|
|
135
|
+
if (permIntents.length > 0) {
|
|
136
|
+
// OpenClaw has no dedicated permission hook.
|
|
137
|
+
// Best effort: degrade to before_tool_call with block capability.
|
|
138
|
+
skipped.push({
|
|
139
|
+
intent: 'onPermission',
|
|
140
|
+
agent: 'openclaw',
|
|
141
|
+
reason: 'OpenClaw has no dedicated permission request hook. ' +
|
|
142
|
+
'Consider using hooks.raw() with before_tool_call for similar behavior.',
|
|
143
|
+
});
|
|
144
|
+
warnings.push(`[openclaw] onPermission: not supported. OpenClaw has no PermissionRequest equivalent. ` +
|
|
145
|
+
`Use hooks.raw("openclaw", "before_tool_call", ...) as a workaround.`);
|
|
146
|
+
}
|
|
147
|
+
// --- Apply extend hooks to handler sections ---
|
|
148
|
+
for (const hookName of [...intentGeneratedPluginHooks, ...intentGeneratedInternalHooks]) {
|
|
149
|
+
const key = `openclaw::${hookName}`;
|
|
150
|
+
const extends_ = extendHooks.get(key);
|
|
151
|
+
if (extends_ && extends_.length > 0) {
|
|
152
|
+
for (const ext of extends_) {
|
|
153
|
+
handlerSections.push(` // --- extend for ${hookName} ---\n ${ext.handler}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// --- Build HOOK.md and handler.ts ---
|
|
158
|
+
if (handlerSections.length > 0 || internalEvents.size > 0 || pluginEvents.size > 0) {
|
|
159
|
+
const allEvents = [...internalEvents, ...pluginEvents];
|
|
160
|
+
files['HOOK.md'] = this.buildHookMd(toolName, allEvents);
|
|
161
|
+
files['handler.ts'] = this.buildHandlerTs(toolName, handlerSections, internalEvents, pluginEvents);
|
|
162
|
+
}
|
|
163
|
+
// --- Raw hooks: write as additional files ---
|
|
164
|
+
for (const [key, reg] of rawHooks) {
|
|
165
|
+
if (!key.startsWith('openclaw::'))
|
|
166
|
+
continue;
|
|
167
|
+
const hookName = key.split('::')[1];
|
|
168
|
+
if (intentGeneratedPluginHooks.has(hookName) || intentGeneratedInternalHooks.has(hookName)) {
|
|
169
|
+
warnings.push(`[openclaw] raw hook for ${hookName} replaces intent-generated hook.`);
|
|
170
|
+
}
|
|
171
|
+
// Raw hooks get their own subdirectory-style files
|
|
172
|
+
const safeName = hookName.replace(/[:.]/g, '-');
|
|
173
|
+
files[`raw-${safeName}.ts`] = reg.handler;
|
|
174
|
+
}
|
|
175
|
+
return { files, warnings, skipped };
|
|
176
|
+
}
|
|
177
|
+
getSettingsEntries() {
|
|
178
|
+
// OpenClaw doesn't use settings.json for hooks
|
|
179
|
+
return [];
|
|
180
|
+
}
|
|
181
|
+
// -----------------------------------------------------------------------
|
|
182
|
+
// Section builders
|
|
183
|
+
// -----------------------------------------------------------------------
|
|
184
|
+
buildInjectSection(toolName, reminderContent) {
|
|
185
|
+
const constName = toolName.toUpperCase().replace(/-/g, '_') + '_REMINDER';
|
|
186
|
+
return ` // --- inject (agent:bootstrap) ---
|
|
187
|
+
if (event.type === 'agent' && event.action === 'bootstrap') {
|
|
188
|
+
if (event.sessionKey && event.sessionKey.includes(':subagent:')) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (Array.isArray(event.context?.bootstrapFiles)) {
|
|
192
|
+
event.context.bootstrapFiles.push({
|
|
193
|
+
path: '${constName}.md',
|
|
194
|
+
content: \`${reminderContent}\`,
|
|
195
|
+
virtual: true,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}`;
|
|
199
|
+
}
|
|
200
|
+
buildSessionEndInjectSection(content) {
|
|
201
|
+
return ` // --- inject.sessionEnd (session_end) ---
|
|
202
|
+
if (event.hookName === 'session_end') {
|
|
203
|
+
// Session end content: ${content.substring(0, 50)}...
|
|
204
|
+
}`;
|
|
205
|
+
}
|
|
206
|
+
buildCompactionSection(content) {
|
|
207
|
+
return ` // --- inject.compaction (before_compaction) ---
|
|
208
|
+
if (event.hookName === 'before_compaction') {
|
|
209
|
+
if (event.context) {
|
|
210
|
+
event.context.additionalContext = (event.context.additionalContext || '') +
|
|
211
|
+
'\\n' + \`${content}\`;
|
|
212
|
+
}
|
|
213
|
+
}`;
|
|
214
|
+
}
|
|
215
|
+
buildBeforeToolCallSection(intents) {
|
|
216
|
+
const cases = intents.map((intent, i) => {
|
|
217
|
+
const regex = matcherToRegex(intent.match);
|
|
218
|
+
return ` // beforeToolCall handler #${i + 1}
|
|
219
|
+
if (${regex}.test(event.toolName || "")) {
|
|
220
|
+
// Handler evaluated at runtime via agent-kit
|
|
221
|
+
}`;
|
|
222
|
+
});
|
|
223
|
+
return ` // --- beforeToolCall (before_tool_call) ---
|
|
224
|
+
if (event.hookName === 'before_tool_call') {
|
|
225
|
+
${cases.join('\n\n')}
|
|
226
|
+
}`;
|
|
227
|
+
}
|
|
228
|
+
buildAfterToolCallSection(intents) {
|
|
229
|
+
const cases = intents.map((intent, i) => {
|
|
230
|
+
const regex = matcherToRegex(intent.match);
|
|
231
|
+
return ` // afterToolCall observer #${i + 1}
|
|
232
|
+
if (${regex}.test(event.toolName || "")) {
|
|
233
|
+
// Observer evaluated at runtime via agent-kit
|
|
234
|
+
}`;
|
|
235
|
+
});
|
|
236
|
+
return ` // --- afterToolCall (after_tool_call) ---
|
|
237
|
+
if (event.hookName === 'after_tool_call') {
|
|
238
|
+
${cases.join('\n\n')}
|
|
239
|
+
}`;
|
|
240
|
+
}
|
|
241
|
+
buildOnSessionSection(phase) {
|
|
242
|
+
return ` // --- onSession.${phase} (session_${phase}) ---
|
|
243
|
+
if (event.hookName === 'session_${phase}') {
|
|
244
|
+
// Session ${phase} handler — extend with hooks.extend() for custom logic.
|
|
245
|
+
}`;
|
|
246
|
+
}
|
|
247
|
+
// -----------------------------------------------------------------------
|
|
248
|
+
// File builders
|
|
249
|
+
// -----------------------------------------------------------------------
|
|
250
|
+
buildHookMd(toolName, events) {
|
|
251
|
+
return `---
|
|
252
|
+
name: ${toolName}
|
|
253
|
+
description: "${capitalize(toolName)} hook - generated by @s_s/agent-kit"
|
|
254
|
+
metadata: {"openclaw":{"events":${JSON.stringify(events)}}}
|
|
255
|
+
---
|
|
256
|
+
`;
|
|
257
|
+
}
|
|
258
|
+
buildHandlerTs(toolName, sections, _internalEvents, _pluginEvents) {
|
|
259
|
+
return `/**
|
|
260
|
+
* ${capitalize(toolName)} Hook Handler for OpenClaw
|
|
261
|
+
* Generated by @s_s/agent-kit
|
|
262
|
+
*/
|
|
263
|
+
|
|
264
|
+
const handler = async (event: any) => {
|
|
265
|
+
${sections.join('\n\n')}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
export default handler;
|
|
269
|
+
`;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=openclaw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openclaw.js","sourceRoot":"","sources":["../../src/hook-translators/openclaw.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AgentHookTranslator, TranslationResult, SettingsHookEntry } from './types.js';
|
|
2
|
+
import type { HookIntent, RawHookRegistration, ExtendHookRegistration } from '../hook-types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Translates intent-based hooks into an OpenCode plugin file.
|
|
5
|
+
*
|
|
6
|
+
* OpenCode constraints:
|
|
7
|
+
* - All hooks must merge into a single .ts plugin file
|
|
8
|
+
* - Plugin exports an async factory function that returns a hook object
|
|
9
|
+
* - Hooks are keys in the returned object (e.g. "tool.execute.before")
|
|
10
|
+
* - Each hook is an async function(input, output) that modifies output in-place
|
|
11
|
+
* - No explicit block mechanism for tool.execute.before (partial support)
|
|
12
|
+
*/
|
|
13
|
+
export declare class OpenCodeTranslator implements AgentHookTranslator {
|
|
14
|
+
translate(intents: readonly HookIntent[], rawHooks: ReadonlyMap<string, RawHookRegistration>, extendHooks: ReadonlyMap<string, readonly ExtendHookRegistration[]>, toolName: string): TranslationResult;
|
|
15
|
+
getSettingsEntries(): SettingsHookEntry[];
|
|
16
|
+
private addHookBody;
|
|
17
|
+
private buildInjectHookBody;
|
|
18
|
+
private buildBeforeToolCallBody;
|
|
19
|
+
private buildAfterToolCallBody;
|
|
20
|
+
private buildSessionBody;
|
|
21
|
+
private buildPermissionBody;
|
|
22
|
+
private buildPluginFile;
|
|
23
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Helpers
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
function toPascalCase(str) {
|
|
5
|
+
return str
|
|
6
|
+
.split(/[-_]/)
|
|
7
|
+
.map((s) => s.charAt(0).toUpperCase() + s.slice(1).toLowerCase())
|
|
8
|
+
.join('');
|
|
9
|
+
}
|
|
10
|
+
function capitalize(str) {
|
|
11
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
12
|
+
}
|
|
13
|
+
function matcherToRegex(match) {
|
|
14
|
+
if (match === undefined || match === '*')
|
|
15
|
+
return '/.*/';
|
|
16
|
+
if (match instanceof RegExp)
|
|
17
|
+
return match.toString();
|
|
18
|
+
return `/${match}/`;
|
|
19
|
+
}
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// OpenCode Translator
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
/**
|
|
24
|
+
* Translates intent-based hooks into an OpenCode plugin file.
|
|
25
|
+
*
|
|
26
|
+
* OpenCode constraints:
|
|
27
|
+
* - All hooks must merge into a single .ts plugin file
|
|
28
|
+
* - Plugin exports an async factory function that returns a hook object
|
|
29
|
+
* - Hooks are keys in the returned object (e.g. "tool.execute.before")
|
|
30
|
+
* - Each hook is an async function(input, output) that modifies output in-place
|
|
31
|
+
* - No explicit block mechanism for tool.execute.before (partial support)
|
|
32
|
+
*/
|
|
33
|
+
export class OpenCodeTranslator {
|
|
34
|
+
translate(intents, rawHooks, extendHooks, toolName) {
|
|
35
|
+
const warnings = [];
|
|
36
|
+
const skipped = [];
|
|
37
|
+
// Collect all hook bodies keyed by OpenCode hook name
|
|
38
|
+
const hookBodies = new Map();
|
|
39
|
+
// Track intent-generated hooks for conflict detection
|
|
40
|
+
const intentGeneratedHooks = new Set();
|
|
41
|
+
// --- inject intents ---
|
|
42
|
+
const injectIntents = intents.filter((i) => i.type === 'inject');
|
|
43
|
+
if (injectIntents.length > 0) {
|
|
44
|
+
const hookName = 'experimental.chat.messages.transform';
|
|
45
|
+
if (rawHooks.has(`opencode::${hookName}`)) {
|
|
46
|
+
warnings.push(`[opencode] raw hook for ${hookName} overrides inject intent.`);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const body = this.buildInjectHookBody(injectIntents);
|
|
50
|
+
this.addHookBody(hookBodies, hookName, body);
|
|
51
|
+
intentGeneratedHooks.add(hookName);
|
|
52
|
+
}
|
|
53
|
+
// compaction → experimental.session.compacting
|
|
54
|
+
const compactions = injectIntents.filter((i) => i.compaction);
|
|
55
|
+
if (compactions.length > 0) {
|
|
56
|
+
const compactHook = 'experimental.session.compacting';
|
|
57
|
+
if (rawHooks.has(`opencode::${compactHook}`)) {
|
|
58
|
+
warnings.push(`[opencode] raw hook for ${compactHook} overrides inject.compaction intent.`);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const combined = compactions.map((i) => i.compaction).join('\\n\\n');
|
|
62
|
+
const body = ` output.context.push(\`${combined}\`);`;
|
|
63
|
+
this.addHookBody(hookBodies, compactHook, body);
|
|
64
|
+
intentGeneratedHooks.add(compactHook);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
warnings.push(`[opencode] inject relies on experimental.chat.messages.transform which is marked experimental and may change.`);
|
|
68
|
+
}
|
|
69
|
+
// --- beforeToolCall intents ---
|
|
70
|
+
const beforeIntents = intents.filter((i) => i.type === 'beforeToolCall');
|
|
71
|
+
if (beforeIntents.length > 0) {
|
|
72
|
+
const hookName = 'tool.execute.before';
|
|
73
|
+
if (rawHooks.has(`opencode::${hookName}`)) {
|
|
74
|
+
warnings.push(`[opencode] raw hook for ${hookName} overrides beforeToolCall intent.`);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const body = this.buildBeforeToolCallBody(beforeIntents);
|
|
78
|
+
this.addHookBody(hookBodies, hookName, body);
|
|
79
|
+
intentGeneratedHooks.add(hookName);
|
|
80
|
+
if (beforeIntents.some((i) => true)) {
|
|
81
|
+
warnings.push(`[opencode] beforeToolCall.block: OpenCode's tool.execute.before has no explicit block mechanism. ` +
|
|
82
|
+
`Blocking is simulated by clearing tool arguments, which may produce inconsistent behavior.`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// --- afterToolCall intents ---
|
|
87
|
+
const afterIntents = intents.filter((i) => i.type === 'afterToolCall');
|
|
88
|
+
if (afterIntents.length > 0) {
|
|
89
|
+
const hookName = 'tool.execute.after';
|
|
90
|
+
if (rawHooks.has(`opencode::${hookName}`)) {
|
|
91
|
+
warnings.push(`[opencode] raw hook for ${hookName} overrides afterToolCall intent.`);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const body = this.buildAfterToolCallBody(afterIntents);
|
|
95
|
+
this.addHookBody(hookBodies, hookName, body);
|
|
96
|
+
intentGeneratedHooks.add(hookName);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// --- onSession intents ---
|
|
100
|
+
const sessionIntents = intents.filter((i) => i.type === 'onSession');
|
|
101
|
+
if (sessionIntents.length > 0) {
|
|
102
|
+
const hookName = 'event';
|
|
103
|
+
if (rawHooks.has(`opencode::${hookName}`)) {
|
|
104
|
+
warnings.push(`[opencode] raw hook for ${hookName} overrides onSession intent.`);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const body = this.buildSessionBody(sessionIntents);
|
|
108
|
+
this.addHookBody(hookBodies, hookName, body);
|
|
109
|
+
intentGeneratedHooks.add(hookName);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// --- onPermission intents ---
|
|
113
|
+
const permIntents = intents.filter((i) => i.type === 'onPermission');
|
|
114
|
+
if (permIntents.length > 0) {
|
|
115
|
+
const hookName = 'permission.ask';
|
|
116
|
+
if (rawHooks.has(`opencode::${hookName}`)) {
|
|
117
|
+
warnings.push(`[opencode] raw hook for ${hookName} overrides onPermission intent.`);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const body = this.buildPermissionBody(permIntents);
|
|
121
|
+
this.addHookBody(hookBodies, hookName, body);
|
|
122
|
+
intentGeneratedHooks.add(hookName);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// --- Apply extend hooks ---
|
|
126
|
+
for (const hookName of hookBodies.keys()) {
|
|
127
|
+
const key = `opencode::${hookName}`;
|
|
128
|
+
const extends_ = extendHooks.get(key);
|
|
129
|
+
if (extends_ && extends_.length > 0) {
|
|
130
|
+
for (const ext of extends_) {
|
|
131
|
+
this.addHookBody(hookBodies, hookName, ` // --- extend ---\n${ext.handler}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// --- Raw hooks: merge directly ---
|
|
136
|
+
for (const [key, reg] of rawHooks) {
|
|
137
|
+
if (!key.startsWith('opencode::'))
|
|
138
|
+
continue;
|
|
139
|
+
const hookName = key.split('::')[1];
|
|
140
|
+
if (intentGeneratedHooks.has(hookName)) {
|
|
141
|
+
warnings.push(`[opencode] raw hook for ${hookName} replaces intent-generated hook.`);
|
|
142
|
+
hookBodies.delete(hookName);
|
|
143
|
+
}
|
|
144
|
+
this.addHookBody(hookBodies, hookName, reg.handler);
|
|
145
|
+
}
|
|
146
|
+
// --- Generate the single plugin file ---
|
|
147
|
+
const files = {};
|
|
148
|
+
if (hookBodies.size > 0) {
|
|
149
|
+
files[`${toolName}-plugin.ts`] = this.buildPluginFile(toolName, hookBodies);
|
|
150
|
+
}
|
|
151
|
+
return { files, warnings, skipped };
|
|
152
|
+
}
|
|
153
|
+
getSettingsEntries() {
|
|
154
|
+
// OpenCode doesn't use settings.json for hooks
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
// -----------------------------------------------------------------------
|
|
158
|
+
// Private helpers
|
|
159
|
+
// -----------------------------------------------------------------------
|
|
160
|
+
addHookBody(map, hookName, body) {
|
|
161
|
+
const existing = map.get(hookName) ?? [];
|
|
162
|
+
existing.push(body);
|
|
163
|
+
map.set(hookName, existing);
|
|
164
|
+
}
|
|
165
|
+
buildInjectHookBody(intents) {
|
|
166
|
+
const perTurnParts = intents.map((i) => i.perTurn);
|
|
167
|
+
const sessionStartParts = intents.filter((i) => i.sessionStart).map((i) => i.sessionStart);
|
|
168
|
+
const hasSessionStart = sessionStartParts.length > 0;
|
|
169
|
+
const perTurnCombined = perTurnParts.join('\\n\\n');
|
|
170
|
+
const sessionStartCombined = hasSessionStart
|
|
171
|
+
? [...sessionStartParts, ...perTurnParts].join('\\n\\n')
|
|
172
|
+
: perTurnCombined;
|
|
173
|
+
return ` const messages = output.messages;
|
|
174
|
+
if (!messages || messages.length === 0) return;
|
|
175
|
+
|
|
176
|
+
const sessionID = messages[0]?.info?.sessionID;
|
|
177
|
+
const isNewSession = sessionID && !_seenSessions.has(sessionID);
|
|
178
|
+
if (sessionID) _seenSessions.add(sessionID);
|
|
179
|
+
|
|
180
|
+
const reminder = isNewSession
|
|
181
|
+
? \`${sessionStartCombined}\`
|
|
182
|
+
: \`${perTurnCombined}\`;
|
|
183
|
+
|
|
184
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
185
|
+
if (messages[i].info?.role === "user") {
|
|
186
|
+
messages[i].parts.push({ type: "text", text: reminder });
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}`;
|
|
190
|
+
}
|
|
191
|
+
buildBeforeToolCallBody(intents) {
|
|
192
|
+
const cases = intents.map((intent, i) => {
|
|
193
|
+
const regex = matcherToRegex(intent.match);
|
|
194
|
+
return ` // beforeToolCall intent #${i + 1}
|
|
195
|
+
if (${regex}.test(output.toolName || "")) {
|
|
196
|
+
// Handler evaluated at runtime via agent-kit
|
|
197
|
+
}`;
|
|
198
|
+
});
|
|
199
|
+
return cases.join('\n\n');
|
|
200
|
+
}
|
|
201
|
+
buildAfterToolCallBody(intents) {
|
|
202
|
+
const cases = intents.map((intent, i) => {
|
|
203
|
+
const regex = matcherToRegex(intent.match);
|
|
204
|
+
return ` // afterToolCall observer #${i + 1}
|
|
205
|
+
if (${regex}.test(output.toolName || "")) {
|
|
206
|
+
// Observer evaluated at runtime via agent-kit
|
|
207
|
+
}`;
|
|
208
|
+
});
|
|
209
|
+
return cases.join('\n\n');
|
|
210
|
+
}
|
|
211
|
+
buildSessionBody(intents) {
|
|
212
|
+
return ` const eventType = output.type || "";
|
|
213
|
+
if (eventType === "session.start") {
|
|
214
|
+
// onSession.start handlers
|
|
215
|
+
} else if (eventType === "session.end") {
|
|
216
|
+
// onSession.end handlers
|
|
217
|
+
}`;
|
|
218
|
+
}
|
|
219
|
+
buildPermissionBody(intents) {
|
|
220
|
+
const cases = intents.map((intent, i) => {
|
|
221
|
+
const regex = matcherToRegex(intent.match);
|
|
222
|
+
return ` // onPermission handler #${i + 1}
|
|
223
|
+
if (${regex}.test(output.toolName || "")) {
|
|
224
|
+
// Permission decision evaluated at runtime via agent-kit
|
|
225
|
+
}`;
|
|
226
|
+
});
|
|
227
|
+
return cases.join('\n\n');
|
|
228
|
+
}
|
|
229
|
+
buildPluginFile(toolName, hookBodies) {
|
|
230
|
+
const exportName = toPascalCase(toolName) + 'Plugin';
|
|
231
|
+
const hookEntries = Array.from(hookBodies.entries())
|
|
232
|
+
.map(([hookName, bodies]) => {
|
|
233
|
+
const combinedBody = bodies.join('\n\n');
|
|
234
|
+
return ` "${hookName}": async (_input: unknown, output: any) => {
|
|
235
|
+
${combinedBody}
|
|
236
|
+
}`;
|
|
237
|
+
})
|
|
238
|
+
.join(',\n\n');
|
|
239
|
+
return `/**
|
|
240
|
+
* ${capitalize(toolName)} Plugin for OpenCode
|
|
241
|
+
* Generated by @s_s/agent-kit
|
|
242
|
+
*/
|
|
243
|
+
|
|
244
|
+
const _seenSessions = new Set<string>();
|
|
245
|
+
|
|
246
|
+
export const ${exportName} = async () => {
|
|
247
|
+
return {
|
|
248
|
+
${hookEntries}
|
|
249
|
+
};
|
|
250
|
+
};
|
|
251
|
+
`;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/hook-translators/opencode.ts"],"names":[],"mappings":"AAYA,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,SAAS,YAAY,CAAC,GAAW;IAC7B,OAAO,GAAG;SACL,KAAK,CAAC,MAAM,CAAC;SACb,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;SAChE,IAAI,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC3B,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,cAAc,CAAC,KAAkC;IACtD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,GAAG;QAAE,OAAO,MAAM,CAAC;IACxD,IAAI,KAAK,YAAY,MAAM;QAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;IACrD,OAAO,IAAI,KAAK,GAAG,CAAC;AACxB,CAAC;AAED,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,OAAO,kBAAkB;IAC3B,SAAS,CACL,OAA8B,EAC9B,QAAkD,EAClD,WAAmE,EACnE,QAAgB;QAEhB,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAiC,EAAE,CAAC;QAEjD,sDAAsD;QACtD,MAAM,UAAU,GAA0B,IAAI,GAAG,EAAE,CAAC;QAEpD,sDAAsD;QACtD,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAU,CAAC;QAE/C,yBAAyB;QACzB,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAqB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;QACpF,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,sCAAsC,CAAC;YAExD,IAAI,QAAQ,CAAC,GAAG,CAAC,aAAa,QAAQ,EAAE,CAAC,EAAE,CAAC;gBACxC,QAAQ,CAAC,IAAI,CAAC,2BAA2B,QAAQ,2BAA2B,CAAC,CAAC;YAClF,CAAC;iBAAM,CAAC;gBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;gBACrD,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;gBAC7C,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACvC,CAAC;YAED,+CAA+C;YAC/C,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YAC9D,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,MAAM,WAAW,GAAG,iCAAiC,CAAC;gBACtD,IAAI,QAAQ,CAAC,GAAG,CAAC,aAAa,WAAW,EAAE,CAAC,EAAE,CAAC;oBAC3C,QAAQ,CAAC,IAAI,CAAC,2BAA2B,WAAW,sCAAsC,CAAC,CAAC;gBAChG,CAAC;qBAAM,CAAC;oBACJ,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBACtE,MAAM,IAAI,GAAG,qCAAqC,QAAQ,MAAM,CAAC;oBACjE,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;oBAChD,oBAAoB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;gBAC1C,CAAC;YACL,CAAC;YAED,QAAQ,CAAC,IAAI,CACT,+GAA+G,CAClH,CAAC;QACN,CAAC;QAED,iCAAiC;QACjC,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAA6B,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;QACpG,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,qBAAqB,CAAC;YACvC,IAAI,QAAQ,CAAC,GAAG,CAAC,aAAa,QAAQ,EAAE,CAAC,EAAE,CAAC;gBACxC,QAAQ,CAAC,IAAI,CAAC,2BAA2B,QAAQ,mCAAmC,CAAC,CAAC;YAC1F,CAAC;iBAAM,CAAC;gBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,uBAAuB,CAAC,aAAa,CAAC,CAAC;gBACzD,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;gBAC7C,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAEnC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;oBAClC,QAAQ,CAAC,IAAI,CACT,mGAAmG;wBAC/F,4FAA4F,CACnG,CAAC;gBACN,CAAC;YACL,CAAC;QACL,CAAC;QAED,gCAAgC;QAChC,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAA4B,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC;QACjG,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,oBAAoB,CAAC;YACtC,IAAI,QAAQ,CAAC,GAAG,CAAC,aAAa,QAAQ,EAAE,CAAC,EAAE,CAAC;gBACxC,QAAQ,CAAC,IAAI,CAAC,2BAA2B,QAAQ,kCAAkC,CAAC,CAAC;YACzF,CAAC;iBAAM,CAAC;gBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,sBAAsB,CAAC,YAAY,CAAC,CAAC;gBACvD,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;gBAC7C,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACvC,CAAC;QACL,CAAC;QAED,4BAA4B;QAC5B,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAwB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;QAC3F,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC;YACzB,IAAI,QAAQ,CAAC,GAAG,CAAC,aAAa,QAAQ,EAAE,CAAC,EAAE,CAAC;gBACxC,QAAQ,CAAC,IAAI,CAAC,2BAA2B,QAAQ,8BAA8B,CAAC,CAAC;YACrF,CAAC;iBAAM,CAAC;gBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;gBACnD,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;gBAC7C,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACvC,CAAC;QACL,CAAC;QAED,+BAA+B;QAC/B,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAA2B,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC;QAC9F,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,gBAAgB,CAAC;YAClC,IAAI,QAAQ,CAAC,GAAG,CAAC,aAAa,QAAQ,EAAE,CAAC,EAAE,CAAC;gBACxC,QAAQ,CAAC,IAAI,CAAC,2BAA2B,QAAQ,iCAAiC,CAAC,CAAC;YACxF,CAAC;iBAAM,CAAC;gBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;gBACnD,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;gBAC7C,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACvC,CAAC;QACL,CAAC;QAED,6BAA6B;QAC7B,KAAK,MAAM,QAAQ,IAAI,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;YACvC,MAAM,GAAG,GAAG,aAAa,QAAQ,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACtC,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;oBACzB,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,EAAE,kCAAkC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC5F,CAAC;YACL,CAAC;QACL,CAAC;QAED,oCAAoC;QACpC,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,QAAQ,EAAE,CAAC;YAChC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC;gBAAE,SAAS;YAC5C,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAEpC,IAAI,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACrC,QAAQ,CAAC,IAAI,CAAC,2BAA2B,QAAQ,kCAAkC,CAAC,CAAC;gBACrF,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAChC,CAAC;YAED,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QACxD,CAAC;QAED,0CAA0C;QAC1C,MAAM,KAAK,GAA2B,EAAE,CAAC;QACzC,IAAI,UAAU,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YACtB,KAAK,CAAC,GAAG,QAAQ,YAAY,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAChF,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IACxC,CAAC;IAED,kBAAkB;QACd,+CAA+C;QAC/C,OAAO,EAAE,CAAC;IACd,CAAC;IAED,0EAA0E;IAC1E,kBAAkB;IAClB,0EAA0E;IAElE,WAAW,CAAC,GAA0B,EAAE,QAAgB,EAAE,IAAY;QAC1E,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACzC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAChC,CAAC;IAEO,mBAAmB,CAAC,OAAuB;QAC/C,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACnD,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAa,CAAC,CAAC;QAE5F,MAAM,eAAe,GAAG,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC;QACrD,MAAM,eAAe,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpD,MAAM,oBAAoB,GAAG,eAAe;YACxC,CAAC,CAAC,CAAC,GAAG,iBAAiB,EAAE,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;YACxD,CAAC,CAAC,eAAe,CAAC;QAEtB,OAAO;;;;;;;;sBAQO,oBAAoB;sBACpB,eAAe;;;;;;;cAOvB,CAAC;IACX,CAAC;IAEO,uBAAuB,CAAC,OAA+B;QAC3D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACpC,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC3C,OAAO,yCAAyC,CAAC,GAAG,CAAC;kBAC/C,KAAK;;cAET,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAEO,sBAAsB,CAAC,OAA8B;QACzD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACpC,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC3C,OAAO,0CAA0C,CAAC,GAAG,CAAC;kBAChD,KAAK;;cAET,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAEO,gBAAgB,CAAC,OAA0B;QAC/C,OAAO;;;;;cAKD,CAAC;IACX,CAAC;IAEO,mBAAmB,CAAC,OAA6B;QACrD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACpC,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC3C,OAAO,wCAAwC,CAAC,GAAG,CAAC;kBAC9C,KAAK;;cAET,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAEO,eAAe,CAAC,QAAgB,EAAE,UAAiC;QACvE,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;QAErD,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;aAC/C,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE;YACxB,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzC,OAAO,YAAY,QAAQ;EACzC,YAAY;UACJ,CAAC;QACC,CAAC,CAAC;aACD,IAAI,CAAC,OAAO,CAAC,CAAC;QAEnB,OAAO;KACV,UAAU,CAAC,QAAQ,CAAC;;;;;;eAMV,UAAU;;EAEvB,WAAW;;;CAGZ,CAAC;IACE,CAAC;CACJ"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { HookIntent, RawHookRegistration, ExtendHookRegistration } from '../hook-types.js';
|
|
2
|
+
import type { SkippedIntent } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Result of translating intents into native hook files for a specific agent.
|
|
5
|
+
*/
|
|
6
|
+
export interface TranslationResult {
|
|
7
|
+
/** Map of filename → file content to write to the hook directory. */
|
|
8
|
+
files: Record<string, string>;
|
|
9
|
+
/** Warnings about degradation, conflicts, or partial support. */
|
|
10
|
+
warnings: string[];
|
|
11
|
+
/** Intents that were completely skipped (unsupported by this agent). */
|
|
12
|
+
skipped: SkippedIntent[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Describes a settings.json hook entry to merge.
|
|
16
|
+
* Used by agents that need hook config in a central settings file (Claude Code, Codex).
|
|
17
|
+
*/
|
|
18
|
+
export interface SettingsHookEntry {
|
|
19
|
+
/** Native hook event name (e.g. 'UserPromptSubmit', 'PreToolUse'). */
|
|
20
|
+
event: string;
|
|
21
|
+
/** Regex matcher string. Empty string matches all. */
|
|
22
|
+
matcher: string;
|
|
23
|
+
/** Handler type and command/URL. */
|
|
24
|
+
hook: {
|
|
25
|
+
type: 'command';
|
|
26
|
+
command: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Translates intent-based hook declarations into native hook files for a specific agent.
|
|
31
|
+
*
|
|
32
|
+
* Each agent has its own translator implementation that understands:
|
|
33
|
+
* - How to map intents to native hook event names
|
|
34
|
+
* - How to generate handler code (shell scripts, TypeScript plugins, etc.)
|
|
35
|
+
* - How to merge multiple intents targeting the same native hook
|
|
36
|
+
* - How to apply raw overrides and extend augmentations
|
|
37
|
+
* - What capabilities are partially or fully unsupported
|
|
38
|
+
*/
|
|
39
|
+
export interface AgentHookTranslator {
|
|
40
|
+
/**
|
|
41
|
+
* Translate all registered hook declarations into native files.
|
|
42
|
+
*
|
|
43
|
+
* @param intents - All registered intents from the hook registry.
|
|
44
|
+
* @param rawHooks - Raw hook registrations for this agent.
|
|
45
|
+
* @param extendHooks - Extend hook registrations for this agent.
|
|
46
|
+
* @param toolName - The registered tool name (used for file naming, markers, etc.)
|
|
47
|
+
* @returns Translation result with files, warnings, and skipped intents.
|
|
48
|
+
*/
|
|
49
|
+
translate(intents: readonly HookIntent[], rawHooks: ReadonlyMap<string, RawHookRegistration>, extendHooks: ReadonlyMap<string, readonly ExtendHookRegistration[]>, toolName: string): TranslationResult;
|
|
50
|
+
/**
|
|
51
|
+
* Get settings entries that need to be merged into the agent's settings file.
|
|
52
|
+
* Only applicable for agents that use a central settings file (Claude Code, Codex).
|
|
53
|
+
* Returns empty array for agents that don't need settings.json updates.
|
|
54
|
+
*
|
|
55
|
+
* @param hookDir - The directory where hook files are written.
|
|
56
|
+
* @param toolName - The registered tool name.
|
|
57
|
+
*/
|
|
58
|
+
getSettingsEntries(hookDir: string, toolName: string): SettingsHookEntry[];
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/hook-translators/types.ts"],"names":[],"mappings":""}
|