agent-base-kit 0.1.0 → 0.3.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 +100 -152
- package/dist/index.d.mts +197 -38
- package/dist/index.mjs +436 -123
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* What a hook declares it checks. Each kind selects the agents' tools that
|
|
3
3
|
* make that change, and is the `kind` of the {@link ToolCall} the check gets.
|
|
4
|
+
* `tool` selects the tools the definition names in `tools`, such as an MCP
|
|
5
|
+
* server's.
|
|
4
6
|
*/
|
|
5
|
-
type ToolKind = 'shell' | 'write' | 'edit' | 'patch';
|
|
7
|
+
type ToolKind = 'shell' | 'write' | 'edit' | 'patch' | 'tool';
|
|
6
8
|
/**
|
|
7
9
|
* An agent's tool call, reduced to what a check needs. `shell` is Bash in
|
|
8
|
-
* either agent; `write` is Claude Code's Write or NotebookEdit; `edit` is Edit
|
|
9
|
-
* or MultiEdit,
|
|
10
|
-
* apply_patch, the whole patch text, which can add, change and delete
|
|
10
|
+
* either agent; `write` is Claude Code's Write or NotebookEdit; `edit` is Edit,
|
|
11
|
+
* or one edit of a MultiEdit, which the check gets edit by edit; `patch` is
|
|
12
|
+
* Codex's apply_patch, the whole patch text, which can add, change and delete
|
|
13
|
+
* files; `tool` is one of the tools named in `tools`, with its input as the
|
|
14
|
+
* agent sent it, an object.
|
|
11
15
|
*/
|
|
12
16
|
type ToolCall = {
|
|
13
17
|
kind: 'shell';
|
|
@@ -24,6 +28,10 @@ type ToolCall = {
|
|
|
24
28
|
} | {
|
|
25
29
|
kind: 'patch';
|
|
26
30
|
patch: string;
|
|
31
|
+
} | {
|
|
32
|
+
kind: 'tool';
|
|
33
|
+
name: string;
|
|
34
|
+
input: Readonly<Record<string, unknown>>;
|
|
27
35
|
};
|
|
28
36
|
/** What a check declared with kinds `K` receives: only the matching shapes of {@link ToolCall}. */
|
|
29
37
|
type ToolCallOf<K extends ToolKind> = Extract<ToolCall, {
|
|
@@ -45,6 +53,65 @@ interface HookContext {
|
|
|
45
53
|
/** The agent's working directory, from the payload, else the hook's own. */
|
|
46
54
|
cwd: string;
|
|
47
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* The agent events a hook takes part in. Every hook has PreToolUse, which
|
|
58
|
+
* fails closed; Stop and UserPromptSubmit are optional and fail open, since a
|
|
59
|
+
* hook that cannot run must not trap the session in a loop or swallow every
|
|
60
|
+
* prompt.
|
|
61
|
+
*/
|
|
62
|
+
type HookEvent = 'PreToolUse' | 'Stop' | 'UserPromptSubmit';
|
|
63
|
+
/** What a Stop check gets: the reply the agent is about to end its turn on. */
|
|
64
|
+
interface StopInput {
|
|
65
|
+
reply: string;
|
|
66
|
+
}
|
|
67
|
+
/** What a UserPromptSubmit check gets: the prompt the user sent. */
|
|
68
|
+
interface PromptInput {
|
|
69
|
+
prompt: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* A check on one event other than PreToolUse. A block makes the agent take
|
|
73
|
+
* the reason instead: at Stop it keeps going with the reason as its next
|
|
74
|
+
* instruction, at UserPromptSubmit it drops the prompt and shows the reason.
|
|
75
|
+
* A check that throws or returns anything but a verdict lets the event pass.
|
|
76
|
+
*/
|
|
77
|
+
interface EventDefinition<I> {
|
|
78
|
+
check: (input: I, context: HookContext) => HookVerdict | Promise<HookVerdict>;
|
|
79
|
+
/** What the agent shows while the check runs. Defaults to the hook's `statusMessage`. */
|
|
80
|
+
statusMessage?: string;
|
|
81
|
+
/** Seconds the agent waits. Defaults to the hook's `timeout`; past it, the event passes. */
|
|
82
|
+
timeout?: number;
|
|
83
|
+
}
|
|
84
|
+
interface PromptDefinition extends EventDefinition<PromptInput> {
|
|
85
|
+
/**
|
|
86
|
+
* Keeps Claude Code from printing the blocked prompt back under the reason,
|
|
87
|
+
* for a check that blocks a prompt because of what it holds, such as a
|
|
88
|
+
* secret.
|
|
89
|
+
*/
|
|
90
|
+
hidePrompt?: boolean;
|
|
91
|
+
}
|
|
92
|
+
/** The events a hook adds on top of PreToolUse. */
|
|
93
|
+
interface EventDefinitions {
|
|
94
|
+
Stop?: EventDefinition<StopInput>;
|
|
95
|
+
UserPromptSubmit?: PromptDefinition;
|
|
96
|
+
}
|
|
97
|
+
/** Where {@link HookDefinition.onInstall} and `onUninstall` run. */
|
|
98
|
+
interface InstallPlace {
|
|
99
|
+
agent: Agent;
|
|
100
|
+
scope: Scope;
|
|
101
|
+
home: string;
|
|
102
|
+
cwd: string;
|
|
103
|
+
/** The built bin install runs from, to find files shipped beside it. */
|
|
104
|
+
script: string;
|
|
105
|
+
/** The agent config just written. */
|
|
106
|
+
file: string;
|
|
107
|
+
}
|
|
108
|
+
/** Lines an install step adds to what the command line prints. */
|
|
109
|
+
interface InstallNotes {
|
|
110
|
+
/** Printed to stdout after the config file. */
|
|
111
|
+
notes?: readonly string[];
|
|
112
|
+
/** Printed to stderr. */
|
|
113
|
+
warnings?: readonly string[];
|
|
114
|
+
}
|
|
48
115
|
/** What a plugin author writes; {@link defineHook} checks it and fills in the defaults. */
|
|
49
116
|
interface HookDefinition<K extends ToolKind> {
|
|
50
117
|
/**
|
|
@@ -73,6 +140,38 @@ interface HookDefinition<K extends ToolKind> {
|
|
|
73
140
|
* the call run, and Claude Code blocks it.
|
|
74
141
|
*/
|
|
75
142
|
timeout?: number;
|
|
143
|
+
/**
|
|
144
|
+
* Commands an earlier version of the hook wrote in a form install no longer
|
|
145
|
+
* recognizes, such as a path that does not sit in a directory named after
|
|
146
|
+
* the hook. A command any pattern matches is taken as this hook's own:
|
|
147
|
+
* install replaces it and uninstall removes it. A pattern must match the
|
|
148
|
+
* whole command, not a part of it, and may not carry the `g`, `m` or `y`
|
|
149
|
+
* flag.
|
|
150
|
+
*/
|
|
151
|
+
ownCommands?: readonly RegExp[];
|
|
152
|
+
/**
|
|
153
|
+
* Tools no kind covers, by exact name, such as
|
|
154
|
+
* `mcp__github__create_pull_request`. They reach the check as `tool` calls,
|
|
155
|
+
* so `kinds` must list `tool` exactly when this names any.
|
|
156
|
+
*/
|
|
157
|
+
tools?: readonly string[];
|
|
158
|
+
/** Checks on events other than PreToolUse, installed beside it. */
|
|
159
|
+
events?: EventDefinitions;
|
|
160
|
+
/**
|
|
161
|
+
* Runs after install writes the config, to set up what else the hook needs,
|
|
162
|
+
* such as files in the agent's directory. Throwing puts the config and the
|
|
163
|
+
* `current` link back as they were and fails the install. Not run for a
|
|
164
|
+
* Claude Code plugin, which Claude Code installs itself.
|
|
165
|
+
*/
|
|
166
|
+
onInstall?: (place: InstallPlace) => InstallNotes | void;
|
|
167
|
+
/** Runs after uninstall, even when the config held no entry; throwing puts the config back. */
|
|
168
|
+
onUninstall?: (place: InstallPlace) => InstallNotes | void;
|
|
169
|
+
}
|
|
170
|
+
/** An event hook with its defaults filled in. */
|
|
171
|
+
interface EventHook<I> {
|
|
172
|
+
readonly check: (input: I, context: HookContext) => HookVerdict | Promise<HookVerdict>;
|
|
173
|
+
readonly statusMessage: string;
|
|
174
|
+
readonly timeout: number;
|
|
76
175
|
}
|
|
77
176
|
/** A checked hook definition, as {@link defineHook} returns it. */
|
|
78
177
|
interface HookPlugin {
|
|
@@ -81,6 +180,16 @@ interface HookPlugin {
|
|
|
81
180
|
readonly kinds: readonly ToolKind[];
|
|
82
181
|
readonly statusMessage: string;
|
|
83
182
|
readonly timeout: number;
|
|
183
|
+
readonly ownCommands: readonly RegExp[];
|
|
184
|
+
readonly tools: readonly string[];
|
|
185
|
+
readonly events: Readonly<{
|
|
186
|
+
Stop?: EventHook<StopInput>;
|
|
187
|
+
UserPromptSubmit?: EventHook<PromptInput> & {
|
|
188
|
+
readonly hidePrompt: boolean;
|
|
189
|
+
};
|
|
190
|
+
}>;
|
|
191
|
+
readonly onInstall?: (place: InstallPlace) => InstallNotes | void;
|
|
192
|
+
readonly onUninstall?: (place: InstallPlace) => InstallNotes | void;
|
|
84
193
|
/** Called only with a call whose kind is in `kinds`. */
|
|
85
194
|
readonly check: (call: ToolCall, context: HookContext) => HookVerdict | Promise<HookVerdict>;
|
|
86
195
|
}
|
|
@@ -130,10 +239,12 @@ interface ClaudePluginOptions {
|
|
|
130
239
|
* to the package root: `.claude-plugin/plugin.json`, `hooks/hooks.json`, and
|
|
131
240
|
* with `marketplace`, `.claude-plugin/marketplace.json`.
|
|
132
241
|
*
|
|
133
|
-
* The hook runs `node "${CLAUDE_PLUGIN_ROOT}/<entry>" hook
|
|
134
|
-
* `onFailure: "block"`, so a plugin that cannot start or times out blocks
|
|
135
|
-
* call
|
|
136
|
-
*
|
|
242
|
+
* The PreToolUse hook runs `node "${CLAUDE_PLUGIN_ROOT}/<entry>" hook --event
|
|
243
|
+
* PreToolUse --agent claude || exit 2` with `onFailure: "block"`, so a plugin that cannot start or times out blocks
|
|
244
|
+
* the call; each of the plugin's other events runs the same command, naming
|
|
245
|
+
* its own event, without either, so it passes instead. Claude Code copies the plugin and installs
|
|
246
|
+
* nothing into it, and the plugin's `onInstall` does not run, so the entry's
|
|
247
|
+
* directory must hold the whole build. Throws when the plugin checks
|
|
137
248
|
* no tool Claude Code has, or a field would make Claude Code refuse the
|
|
138
249
|
* plugin.
|
|
139
250
|
*/
|
|
@@ -170,13 +281,19 @@ interface CliOptions {
|
|
|
170
281
|
type CliMain = (argv: readonly string[], io: CliIO) => Promise<number>;
|
|
171
282
|
/**
|
|
172
283
|
* Builds the plugin's command line: `install` and `uninstall <claude|codex>
|
|
173
|
-
* [--project]`, and `hook
|
|
284
|
+
* [--project]`, and `hook [--event <event>] [--agent <claude|codex>]`, which
|
|
285
|
+
* reads the payload from `io.stdin` and hands the flags to {@link runHook}.
|
|
174
286
|
*
|
|
175
|
-
* Exit codes: `hook` returns what {@link runHook} returns, 0 or 2
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
287
|
+
* Exit codes: `hook` returns what {@link runHook} returns, 0 or 2; an
|
|
288
|
+
* argument it does not take is a fault, 0 at Stop or UserPromptSubmit and 2
|
|
289
|
+
* otherwise. `install`
|
|
290
|
+
* and `uninstall` return 0, or 1 with the reason on stderr; the notes the
|
|
291
|
+
* plugin's `onInstall` or `onUninstall` returns follow the config file on
|
|
292
|
+
* stdout, its warnings go to stderr. Anything else, including an unknown flag
|
|
293
|
+
* or an extra argument, prints the usage and returns 1. On a Node.js older
|
|
294
|
+
* than 22, `hook` returns 2 for PreToolUse and 0 for Stop and
|
|
295
|
+
* UserPromptSubmit, and `install` 1, each with a message naming the fix;
|
|
296
|
+
* `uninstall` still runs.
|
|
180
297
|
*/
|
|
181
298
|
export declare function createCli(plugin: HookPlugin, options?: CliOptions): CliMain;
|
|
182
299
|
/**
|
|
@@ -191,9 +308,10 @@ export declare function readStdin(stream?: AsyncIterable<unknown>): Promise<stri
|
|
|
191
308
|
* `hook`, and sets `process.exitCode`. Call it without `await`, passing the
|
|
192
309
|
* bin's own `import.meta.url`, which is what install copies and runs.
|
|
193
310
|
*
|
|
194
|
-
* For `hook` the exit code is 2 until a verdict is in. Node.js
|
|
195
|
-
* nothing is left to run, so a check whose promise never settles
|
|
196
|
-
* otherwise let the call run.
|
|
311
|
+
* For a PreToolUse `hook` the exit code is 2 until a verdict is in. Node.js
|
|
312
|
+
* exits 0 once nothing is left to run, so a check whose promise never settles
|
|
313
|
+
* would otherwise let the call run. A Stop or UserPromptSubmit check that
|
|
314
|
+
* never settles exits 0, as any other fault there does.
|
|
197
315
|
*/
|
|
198
316
|
export declare function runCli(plugin: HookPlugin, entryUrl: string, options?: CliOptions): Promise<void>;
|
|
199
317
|
/**
|
|
@@ -208,16 +326,45 @@ interface RunHookOptions {
|
|
|
208
326
|
cwd?: string;
|
|
209
327
|
/** Receives the block reason or the error, newline-terminated. */
|
|
210
328
|
stderr?: (text: string) => void;
|
|
329
|
+
/** Receives the decision a Stop or UserPromptSubmit check blocks with, as a JSON line. */
|
|
330
|
+
stdout?: (text: string) => void;
|
|
331
|
+
/**
|
|
332
|
+
* The event the agent runs the hook for, as the installed command names it
|
|
333
|
+
* with `--event`. Given, it decides how a fault exits without reading the
|
|
334
|
+
* payload, so a Stop or UserPromptSubmit payload that is cut short or not
|
|
335
|
+
* JSON passes, and a payload naming another event is a fault. Absent, the
|
|
336
|
+
* event comes from the payload's `hook_event_name`.
|
|
337
|
+
*/
|
|
338
|
+
event?: HookEvent;
|
|
339
|
+
/**
|
|
340
|
+
* The agent that runs the hook, as the installed command names it with
|
|
341
|
+
* `--agent`. Absent, a UserPromptSubmit payload carrying `turn_id`, which
|
|
342
|
+
* only Codex sends, reads as Codex.
|
|
343
|
+
*/
|
|
344
|
+
agent?: Agent;
|
|
211
345
|
}
|
|
212
346
|
/**
|
|
213
|
-
* Runs one
|
|
214
|
-
* agent reads
|
|
347
|
+
* Runs one hook payload through the plugin and returns the exit code the
|
|
348
|
+
* agent reads.
|
|
349
|
+
*
|
|
350
|
+
* A PreToolUse call returns 2 to block it and 0 to let it run, and fails
|
|
351
|
+
* closed: a payload that is not JSON or names no tool, a field of the wrong
|
|
352
|
+
* shape, a check that throws or rejects, and a result that is not a verdict
|
|
353
|
+
* all return 2 with the error on stderr, because any other exit lets the call
|
|
354
|
+
* run unchecked. A tool the plugin did not ask for returns 0 without calling
|
|
355
|
+
* the check. A MultiEdit calls the check once per edit and blocks on the first
|
|
356
|
+
* edit it blocks. A payload with no `hook_event_name` is read as PreToolUse;
|
|
357
|
+
* one naming any event other than PreToolUse, Stop or UserPromptSubmit, or
|
|
358
|
+
* a `hook_event_name` that is not a string, returns 2.
|
|
359
|
+
*
|
|
360
|
+
* Stop and UserPromptSubmit always return 0. A block goes to stdout as
|
|
361
|
+
* `{"decision":"block","reason":…}`, and a fault to stderr, letting the event
|
|
362
|
+
* pass. A Stop with `stop_hook_active` set passes unchecked, and so does an
|
|
363
|
+
* event the plugin has no check for.
|
|
215
364
|
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
* the call run unchecked. A tool the plugin did not ask for returns 0 without
|
|
220
|
-
* calling the check.
|
|
365
|
+
* With `options.event`, the event is the one named, not the payload's: a
|
|
366
|
+
* Stop or UserPromptSubmit returns 0 on any fault, a payload that is not JSON
|
|
367
|
+
* included, and a payload naming another event is a fault for that event.
|
|
221
368
|
*/
|
|
222
369
|
export declare function runHook(plugin: HookPlugin, stdin: string, options?: RunHookOptions): Promise<number>;
|
|
223
370
|
/** Where {@link uninstall} looks: everything is passed in, so nothing reaches past what the caller names. */
|
|
@@ -237,10 +384,17 @@ interface InstallOptions extends UninstallOptions {
|
|
|
237
384
|
/** The Node.js a user-scope hook keeps running on, as `process.execPath` gives it. */
|
|
238
385
|
execPath: string;
|
|
239
386
|
}
|
|
240
|
-
/** The config file written and, for an install, the
|
|
387
|
+
/** The config file written and, for an install, the commands in it. */
|
|
241
388
|
interface InstallResult {
|
|
242
389
|
file: string;
|
|
390
|
+
/** The PreToolUse command. */
|
|
243
391
|
command?: string;
|
|
392
|
+
/** The command written for each event. */
|
|
393
|
+
commands?: Partial<Record<HookEvent, string>>;
|
|
394
|
+
/** What the plugin's `onInstall` or `onUninstall` returned, for stdout. */
|
|
395
|
+
notes: string[];
|
|
396
|
+
/** And for stderr. */
|
|
397
|
+
warnings: string[];
|
|
244
398
|
}
|
|
245
399
|
/** The agent config a scope writes: `~/.claude/settings.json`, `<cwd>/.codex/hooks.json` and so on. */
|
|
246
400
|
export declare function configFile(agent: Agent, scope: Scope, place: {
|
|
@@ -248,26 +402,31 @@ export declare function configFile(agent: Agent, scope: Scope, place: {
|
|
|
248
402
|
cwd: string;
|
|
249
403
|
}): string;
|
|
250
404
|
/**
|
|
251
|
-
* Adds the plugin's
|
|
252
|
-
* it wrote before
|
|
405
|
+
* Adds the plugin's hooks to one agent's config, PreToolUse and each event in
|
|
406
|
+
* its `events`, replacing any entry it wrote before, for any event, and
|
|
407
|
+
* keeping every other one.
|
|
253
408
|
*
|
|
254
409
|
* The user scope copies the bin's directory to `~/.<name>/<build-id>/`, checks
|
|
255
410
|
* the copy runs, points `~/.<name>/current` at it and runs it from there on
|
|
256
411
|
* `execPath`. The project scope runs `npx --no-install <packageName> hook`.
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
412
|
+
* Each command names its event and agent, `hook --event <event> --agent
|
|
413
|
+
* <agent>`, and the PreToolUse one ends in `|| exit 2`, so a hook that cannot start
|
|
414
|
+
* blocks the call, and the Claude Code entry sets `onFailure: "block"` for one
|
|
415
|
+
* that times out. The other events' commands do not, so they pass instead.
|
|
416
|
+
* Then the plugin's `onInstall` runs.
|
|
260
417
|
*
|
|
261
|
-
* Throws, and leaves the config as
|
|
262
|
-
* object it can extend, when the plugin's kinds leave tools
|
|
263
|
-
* to it unchecked,
|
|
418
|
+
* Throws, and leaves the config and `current` as they were, when the config
|
|
419
|
+
* is not a settings object it can extend, when the plugin's kinds leave tools
|
|
420
|
+
* the agent routes to it unchecked, when the build cannot be copied or does
|
|
421
|
+
* not run, or when `onInstall` throws.
|
|
264
422
|
*/
|
|
265
423
|
export declare function install(options: InstallOptions): InstallResult;
|
|
266
424
|
/**
|
|
267
|
-
* Removes the plugin's
|
|
268
|
-
* install wrote,
|
|
269
|
-
*
|
|
270
|
-
* a settings
|
|
425
|
+
* Removes the plugin's hooks from one agent's config, for every event and
|
|
426
|
+
* whichever form an earlier install wrote, keeps every other entry, and runs
|
|
427
|
+
* the plugin's `onUninstall`. The stable copy stays: another agent may still
|
|
428
|
+
* run it. Throws, and leaves the file as it was, when it is not a settings
|
|
429
|
+
* object or `onUninstall` throws.
|
|
271
430
|
*/
|
|
272
431
|
export declare function uninstall(options: UninstallOptions): InstallResult;
|
|
273
|
-
export type { Agent, ClaudePluginOptions, ClaudePluginPerson, CliIO, CliMain, CliOptions, HookContext, HookDefinition, HookPlugin, HookVerdict, InstallOptions, InstallResult, RunHookOptions, Scope, ToolCall, ToolCallOf, ToolKind, UninstallOptions };
|
|
432
|
+
export type { Agent, ClaudePluginOptions, ClaudePluginPerson, CliIO, CliMain, CliOptions, EventDefinition, EventDefinitions, EventHook, HookContext, HookDefinition, HookEvent, HookPlugin, HookVerdict, InstallNotes, InstallOptions, InstallPlace, InstallResult, PromptDefinition, PromptInput, RunHookOptions, Scope, StopInput, ToolCall, ToolCallOf, ToolKind, UninstallOptions };
|