@goodfoot/agent-hooks 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 +137 -0
- package/dist/agents/antigravity/events.js +42 -0
- package/dist/agents/antigravity/hooks.js +59 -0
- package/dist/agents/antigravity/index.js +28 -0
- package/dist/agents/antigravity/outputs.js +81 -0
- package/dist/agents/antigravity/transport.js +84 -0
- package/dist/agents/antigravity/types.js +11 -0
- package/dist/agents/claude-code/env.js +27 -0
- package/dist/agents/claude-code/events.js +87 -0
- package/dist/agents/claude-code/hooks.js +1000 -0
- package/dist/agents/claude-code/index.js +57 -0
- package/dist/agents/claude-code/outputs.js +579 -0
- package/dist/agents/claude-code/tool-helpers.js +840 -0
- package/dist/agents/claude-code/transport.js +254 -0
- package/dist/agents/claude-code/types.js +11 -0
- package/dist/agents/codex/cli-support.js +318 -0
- package/dist/agents/codex/constants.js +29 -0
- package/dist/agents/codex/events.js +68 -0
- package/dist/agents/codex/hooks.js +93 -0
- package/dist/agents/codex/index.js +21 -0
- package/dist/agents/codex/outputs.js +189 -0
- package/dist/agents/codex/scaffold.js +273 -0
- package/dist/agents/codex/transport.js +139 -0
- package/dist/agents/codex/types.js +1 -0
- package/dist/cli.js +1357 -0
- package/dist/constants.js +39 -0
- package/dist/core/define-hook.js +61 -0
- package/dist/core/env.js +186 -0
- package/dist/core/logger.js +508 -0
- package/dist/core/stdin.js +38 -0
- package/dist/core/transport.js +231 -0
- package/dist/core/types.js +10 -0
- package/dist/index.js +17 -0
- package/dist/scaffold.js +512 -0
- package/package.json +61 -0
- package/types/agents/antigravity/events.d.ts +50 -0
- package/types/agents/antigravity/hooks.d.ts +76 -0
- package/types/agents/antigravity/index.d.ts +27 -0
- package/types/agents/antigravity/outputs.d.ts +107 -0
- package/types/agents/antigravity/transport.d.ts +47 -0
- package/types/agents/antigravity/types.d.ts +58 -0
- package/types/agents/claude-code/env.d.ts +27 -0
- package/types/agents/claude-code/events.d.ts +69 -0
- package/types/agents/claude-code/hooks.d.ts +1182 -0
- package/types/agents/claude-code/index.d.ts +23 -0
- package/types/agents/claude-code/outputs.d.ts +1160 -0
- package/types/agents/claude-code/tool-helpers.d.ts +807 -0
- package/types/agents/claude-code/transport.d.ts +119 -0
- package/types/agents/claude-code/types.d.ts +557 -0
- package/types/agents/codex/cli-support.d.ts +105 -0
- package/types/agents/codex/constants.d.ts +10 -0
- package/types/agents/codex/events.d.ts +63 -0
- package/types/agents/codex/hooks.d.ts +135 -0
- package/types/agents/codex/index.d.ts +19 -0
- package/types/agents/codex/outputs.d.ts +190 -0
- package/types/agents/codex/scaffold.d.ts +14 -0
- package/types/agents/codex/transport.d.ts +74 -0
- package/types/agents/codex/types.d.ts +131 -0
- package/types/cli.d.ts +315 -0
- package/types/constants.d.ts +9 -0
- package/types/core/define-hook.d.ts +39 -0
- package/types/core/env.d.ts +150 -0
- package/types/core/logger.d.ts +476 -0
- package/types/core/stdin.d.ts +21 -0
- package/types/core/transport.d.ts +131 -0
- package/types/core/types.d.ts +137 -0
- package/types/index.d.ts +18 -0
- package/types/scaffold.d.ts +46 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex-specific CLI internals: AST analysis (with `statusMessage`), bundle
|
|
3
|
+
* compilation linking the Codex runtime module, command-context detection
|
|
4
|
+
* (`.codex-plugin` marker / `.codex` local mode / absolute), hooks.json
|
|
5
|
+
* generation with Codex's matcher/timeout-seconds/statusMessage rules, and
|
|
6
|
+
* plugin-mode stable-names default.
|
|
7
|
+
*
|
|
8
|
+
* Driver-level primitives (loader parsing, glob discovery, content hashing,
|
|
9
|
+
* symlink re-rooting, stale-bundle pruning) are imported from the shared CLI
|
|
10
|
+
* module — never re-derived here.
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import * as esbuild from "esbuild";
|
|
14
|
+
import type { HookEventName } from "./types.js";
|
|
15
|
+
/** Codex CLI arguments accepted on top of the shared `--agent codex` gate. */
|
|
16
|
+
export interface CodexCliArgs {
|
|
17
|
+
input: string;
|
|
18
|
+
output: string;
|
|
19
|
+
executable?: string;
|
|
20
|
+
loaderFlags: string[];
|
|
21
|
+
pluginRoot: boolean;
|
|
22
|
+
stableNames?: boolean;
|
|
23
|
+
sourcemap?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export type CommandMode = "plugin" | "codex-local" | "absolute";
|
|
26
|
+
export interface CommandContext {
|
|
27
|
+
mode: CommandMode;
|
|
28
|
+
pluginRoot?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface CodexHookMetadata {
|
|
31
|
+
hookEventName: HookEventName;
|
|
32
|
+
matcher?: string;
|
|
33
|
+
timeout?: number;
|
|
34
|
+
statusMessage?: string;
|
|
35
|
+
}
|
|
36
|
+
interface CompiledHook {
|
|
37
|
+
sourcePath: string;
|
|
38
|
+
outputPath: string;
|
|
39
|
+
outputFilename: string;
|
|
40
|
+
metadata: CodexHookMetadata;
|
|
41
|
+
}
|
|
42
|
+
interface HookConfigEntry {
|
|
43
|
+
type: "command";
|
|
44
|
+
command: string;
|
|
45
|
+
timeout?: number;
|
|
46
|
+
statusMessage?: string;
|
|
47
|
+
}
|
|
48
|
+
export interface CodexMatcherEntry {
|
|
49
|
+
matcher?: string;
|
|
50
|
+
hooks: HookConfigEntry[];
|
|
51
|
+
}
|
|
52
|
+
export interface CodexHooksJson {
|
|
53
|
+
hooks: Partial<Record<HookEventName, CodexMatcherEntry[]>>;
|
|
54
|
+
}
|
|
55
|
+
type HookLoaderMap = Record<string, esbuild.Loader>;
|
|
56
|
+
/**
|
|
57
|
+
* Extracts Codex hook metadata (event name, matcher, timeout in
|
|
58
|
+
* milliseconds, status message) from a TypeScript source file's default
|
|
59
|
+
* export of a hook factory call.
|
|
60
|
+
*/
|
|
61
|
+
export declare function analyzeCodexHookFile(sourcePath: string): CodexHookMetadata | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Compiles one Codex hook to a self-contained ESM executable whose entry
|
|
64
|
+
* wrapper imports this package's Codex runtime module (`execute`).
|
|
65
|
+
*/
|
|
66
|
+
export declare function compileCodexHook(sourcePath: string, loaders: HookLoaderMap, sourcemap?: boolean): Promise<{
|
|
67
|
+
content: string;
|
|
68
|
+
contentHash: string;
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* Detects the command context: `.codex-plugin/` marker found by walking up
|
|
72
|
+
* from the output → plugin mode; explicit `--plugin-root` flag → plugin mode
|
|
73
|
+
* anchored at the output's parent; output under a `/.codex` segment →
|
|
74
|
+
* codex-local mode; otherwise absolute.
|
|
75
|
+
*/
|
|
76
|
+
export declare function detectCodexCommandContext(outputPath: string, pluginRootFlag: boolean): CommandContext;
|
|
77
|
+
/** Generates Codex hooks.json: matchers only where the event supports them, timeouts in seconds, statusMessage when set. */
|
|
78
|
+
export declare function generateCodexHooksJson(compiledHooks: CompiledHook[], outputPath: string, executable?: string, context?: CommandContext): CodexHooksJson;
|
|
79
|
+
/**
|
|
80
|
+
* Validates Codex build/scaffold arguments beyond the shared `--agent` gate:
|
|
81
|
+
* `-i` and `-o` required for build mode; scaffold requires `--hooks` and
|
|
82
|
+
* `-o`.
|
|
83
|
+
*/
|
|
84
|
+
export declare function validateCodexArgs(args: CodexCliArgs & {
|
|
85
|
+
scaffold?: string;
|
|
86
|
+
hooks?: string;
|
|
87
|
+
}): string | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Runs the Codex build/scaffold branch of the unified CLI. Plugin mode
|
|
90
|
+
* defaults to hash-free stable filenames; every other mode defaults to
|
|
91
|
+
* hashed names unless `--stable-names` is passed explicitly (source
|
|
92
|
+
* parity).
|
|
93
|
+
*/
|
|
94
|
+
export declare function runCodexCli(args: {
|
|
95
|
+
input: string;
|
|
96
|
+
output: string;
|
|
97
|
+
executable?: string;
|
|
98
|
+
loaderFlags: string[];
|
|
99
|
+
pluginRoot: boolean;
|
|
100
|
+
stableNames?: boolean;
|
|
101
|
+
sourcemap?: boolean;
|
|
102
|
+
scaffold?: string;
|
|
103
|
+
hooks?: string;
|
|
104
|
+
}): Promise<void>;
|
|
105
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { HookEventName } from "./types.js";
|
|
2
|
+
export declare const PACKAGE_NAME = "@goodfoot/agent-hooks";
|
|
3
|
+
export declare const DEFAULT_TIMEOUT_MS = 600000;
|
|
4
|
+
export declare const DEFAULT_STATUS_MESSAGE: undefined;
|
|
5
|
+
export declare const DEFAULT_ESBUILD_LOADERS: {
|
|
6
|
+
readonly ".md": "text";
|
|
7
|
+
};
|
|
8
|
+
export declare const HOOK_FACTORY_TO_EVENT: Record<string, HookEventName>;
|
|
9
|
+
export declare const EVENTS_WITH_MATCHER: Set<HookEventName>;
|
|
10
|
+
export declare const EVENTS_WITH_TEXT_OUTPUT: Set<HookEventName>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex hook event names and the advisory fail-open allow-list.
|
|
3
|
+
*
|
|
4
|
+
* `HOOK_EVENT_NAMES` mirrors the `HookEventName` union in `types.ts` (10
|
|
5
|
+
* events). The advisory allow-list is **not** authored here: per the plan's
|
|
6
|
+
* derivation rule it is transcribed from `codex-hooks/README.md` — quoted
|
|
7
|
+
* below above the provenance notes — and `ADVISORY_EVENTS` is derived
|
|
8
|
+
* mechanically as "every event except the exclusion set". The unit test in
|
|
9
|
+
* `tests/agents/codex/` transcribes the same sentence a second time,
|
|
10
|
+
* independently, so the runtime list and the test oracle are two copies of
|
|
11
|
+
* the citation rather than one list read twice.
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import type { UnexpectedErrorPolicy } from "../../core/types.js";
|
|
15
|
+
import type { HookEventName } from "./types.js";
|
|
16
|
+
/**
|
|
17
|
+
* All Codex hook event names as a readonly array (same order as the
|
|
18
|
+
* `HookEventName` union).
|
|
19
|
+
*/
|
|
20
|
+
export declare const HOOK_EVENT_NAMES: readonly ["PreToolUse", "PostToolUse", "PermissionRequest", "UserPromptSubmit", "SessionStart", "SubagentStart", "Stop", "SubagentStop", "PreCompact", "PostCompact"];
|
|
21
|
+
/**
|
|
22
|
+
* Events never allowed the fail-open `unexpectedError: "continue"` policy.
|
|
23
|
+
*
|
|
24
|
+
* Transcribed verbatim from codex-hooks/README.md (Fail-Open Execution
|
|
25
|
+
* section):
|
|
26
|
+
*
|
|
27
|
+
* > Only opt in for **advisory enrichment hooks** — ones that add optional
|
|
28
|
+
* > context and whose failure should be invisible to the user (e.g.
|
|
29
|
+
* > `UserPromptSubmit`, `SessionStart`, `SubagentStart` context nudges). Do
|
|
30
|
+
* > not use `"continue"` for hooks that make permission, safety, or policy
|
|
31
|
+
* > decisions (`PreToolUse`, `PermissionRequest`, blocking
|
|
32
|
+
* > `PostToolUse`/`Stop`/`SubagentStop` checks) — silently swallowing a
|
|
33
|
+
* > failure there means the hook's decision was silently skipped.
|
|
34
|
+
*
|
|
35
|
+
* Provenance of each element:
|
|
36
|
+
*
|
|
37
|
+
* - `PreToolUse`, `PermissionRequest`, blocking `PostToolUse`/`Stop`/
|
|
38
|
+
* `SubagentStop` — named verbatim in the README sentence above.
|
|
39
|
+
* - `PreCompact`, `PostCompact` — **not mentioned anywhere in the README**;
|
|
40
|
+
* excluded by default (fail-closed) until a future card's docs justify an
|
|
41
|
+
* entry. This is a stated default, not a silent gap (plan Decisions).
|
|
42
|
+
*/
|
|
43
|
+
export declare const EXCLUDED_FROM_ADVISORY: readonly ["PreToolUse", "PostToolUse", "PermissionRequest", "Stop", "SubagentStop", "PreCompact", "PostCompact"];
|
|
44
|
+
/** The exclusion set as a literal union. */
|
|
45
|
+
export type ExcludedEventName = (typeof EXCLUDED_FROM_ADVISORY)[number];
|
|
46
|
+
/** Type-level membership check: `true` only for excluded event names. */
|
|
47
|
+
export type IsExcludedEvent<TEventName extends HookEventName> = TEventName extends ExcludedEventName ? true : false;
|
|
48
|
+
/** The advisory allow-list as a literal union: every event except {@link ExcludedEventName}. */
|
|
49
|
+
export type AdvisoryEventName = Exclude<HookEventName, ExcludedEventName>;
|
|
50
|
+
/**
|
|
51
|
+
* The advisory allow-list: every Codex event except
|
|
52
|
+
* {@link EXCLUDED_FROM_ADVISORY} — exactly the README's three named
|
|
53
|
+
* enrichment hooks. Only these accept `unexpectedError: "continue"`,
|
|
54
|
+
* enforced at factory-call time by the injected policy gate and at compile
|
|
55
|
+
* time by the excluded events' narrowed config types.
|
|
56
|
+
*/
|
|
57
|
+
export declare const ADVISORY_EVENTS: readonly AdvisoryEventName[];
|
|
58
|
+
/**
|
|
59
|
+
* The policy type an event may carry, narrowed by allow-list membership:
|
|
60
|
+
* advisory events keep `"error" | "continue"`; every excluded event collapses
|
|
61
|
+
* to `"error"`.
|
|
62
|
+
*/
|
|
63
|
+
export type AllowedUnexpectedErrorPolicy<TEventName extends HookEventName> = IsExcludedEvent<TEventName> extends true ? Exclude<UnexpectedErrorPolicy, "continue"> : UnexpectedErrorPolicy;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed factory functions for Codex hooks, built on the shared core
|
|
3
|
+
* {@link ../core/define-hook.ts|defineHook}.
|
|
4
|
+
*
|
|
5
|
+
* Public surface mirrors the source codex-hooks package 1.3.0: same factory names,
|
|
6
|
+
* config shapes (`MatcherHookConfig`/`NoMatcherHookConfig`, including
|
|
7
|
+
* `statusMessage`), result unions, and `hookEventName` metadata property.
|
|
8
|
+
* Two deliberate additions carry the consolidation contract:
|
|
9
|
+
*
|
|
10
|
+
* - every factory injects the advisory allow-list policy gate, so
|
|
11
|
+
* `unexpectedError: "continue"` fails closed at factory-call time for any
|
|
12
|
+
* event not on {@link ADVISORY_EVENTS};
|
|
13
|
+
* - non-advisory events' config types narrow the policy field via
|
|
14
|
+
* {@link MatcherHookConfigFor}/{@link NoMatcherHookConfigFor}, rejecting
|
|
15
|
+
* `"continue"` at compile time as well.
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import type { HookContext, UnexpectedErrorHandler, UnexpectedErrorPolicy } from "../../core/types.js";
|
|
19
|
+
import { type AllowedUnexpectedErrorPolicy } from "./events.js";
|
|
20
|
+
import type { PermissionRequestOutput, PostCompactOutput, PostToolUseOutput, PreCompactOutput, PreToolUseOutput, SessionStartOutput, StopOutput, SubagentStartOutput, SubagentStopOutput, UserPromptSubmitOutput } from "./outputs.js";
|
|
21
|
+
import type { HookEventName, PermissionRequestInput, PostCompactInput, PostToolUseInput, PreCompactInput, PreToolUseInput, SessionStartInput, StopInput, SubagentStartInput, SubagentStopInput, UserPromptSubmitInput } from "./types.js";
|
|
22
|
+
/**
|
|
23
|
+
* Policy/phase/diagnostic vocabulary is shared across agents and owned by the
|
|
24
|
+
* core; re-exported here so the Codex surface keeps its historical import
|
|
25
|
+
* site (`hooks.js`). See the Claude Code surface's documentation of the same
|
|
26
|
+
* vocabulary for the full fail-open contract.
|
|
27
|
+
*/
|
|
28
|
+
export type { HookContext, UnexpectedErrorHandler, UnexpectedErrorPolicy };
|
|
29
|
+
/**
|
|
30
|
+
* The base config shapes from the source package. `statusMessage` is a Codex
|
|
31
|
+
*-specific field: it flows into generated `hooks.json` entries by the CLI.
|
|
32
|
+
*/
|
|
33
|
+
export interface MatcherHookConfig {
|
|
34
|
+
matcher?: string;
|
|
35
|
+
timeout?: number;
|
|
36
|
+
statusMessage?: string;
|
|
37
|
+
unexpectedError?: UnexpectedErrorPolicy;
|
|
38
|
+
onUnexpectedError?: UnexpectedErrorHandler;
|
|
39
|
+
}
|
|
40
|
+
export interface NoMatcherHookConfig {
|
|
41
|
+
timeout?: number;
|
|
42
|
+
statusMessage?: string;
|
|
43
|
+
unexpectedError?: UnexpectedErrorPolicy;
|
|
44
|
+
onUnexpectedError?: UnexpectedErrorHandler;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Per-event matcher config with the fail-open policy narrowed by the advisory
|
|
48
|
+
* allow-list: excluded events collapse `unexpectedError` to `"error"` only.
|
|
49
|
+
* @template TEvent - The event the factory binds.
|
|
50
|
+
*/
|
|
51
|
+
export type MatcherHookConfigFor<TEvent extends HookEventName> = Omit<MatcherHookConfig, "unexpectedError"> & {
|
|
52
|
+
unexpectedError?: AllowedUnexpectedErrorPolicy<TEvent>;
|
|
53
|
+
};
|
|
54
|
+
/** Per-event no-matcher variant of {@link MatcherHookConfigFor}. @template TEvent - The event the factory binds. */
|
|
55
|
+
export type NoMatcherHookConfigFor<TEvent extends HookEventName> = Omit<NoMatcherHookConfig, "unexpectedError"> & {
|
|
56
|
+
unexpectedError?: AllowedUnexpectedErrorPolicy<TEvent>;
|
|
57
|
+
};
|
|
58
|
+
type PreToolUseResult = PreToolUseOutput | undefined;
|
|
59
|
+
type PostToolUseResult = PostToolUseOutput | undefined;
|
|
60
|
+
type PermissionRequestResult = PermissionRequestOutput | undefined;
|
|
61
|
+
type UserPromptSubmitResult = UserPromptSubmitOutput | string | undefined;
|
|
62
|
+
type SessionStartResult = SessionStartOutput | string | undefined;
|
|
63
|
+
type SubagentStartResult = SubagentStartOutput | string | undefined;
|
|
64
|
+
type StopResult = StopOutput | undefined;
|
|
65
|
+
type SubagentStopResult = SubagentStopOutput | undefined;
|
|
66
|
+
type PreCompactResult = PreCompactOutput | undefined;
|
|
67
|
+
type PostCompactResult = PostCompactOutput | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* The result of a hook factory — a function wrapping the handler, carrying
|
|
70
|
+
* its metadata for the driver and the CLI's AST analysis. Preserves the
|
|
71
|
+
* source package's `hookEventName` property name alongside the core's
|
|
72
|
+
* `eventName`.
|
|
73
|
+
* @template TInput - The input type for this hook
|
|
74
|
+
* @template TOutput - The output type for this hook
|
|
75
|
+
* @template TEvent - The literal event name this hook is bound to
|
|
76
|
+
*/
|
|
77
|
+
export interface HookFunction<TInput, TOutput, TEvent extends string> {
|
|
78
|
+
/**
|
|
79
|
+
* Execute the hook handler with the given input and context.
|
|
80
|
+
*/
|
|
81
|
+
(input: TInput, context: HookContext): Promise<TOutput | null>;
|
|
82
|
+
/**
|
|
83
|
+
* The Codex event name this hook is for (source-package property name).
|
|
84
|
+
*/
|
|
85
|
+
hookEventName: TEvent;
|
|
86
|
+
/**
|
|
87
|
+
* The core driver's event-name property; identical value.
|
|
88
|
+
*/
|
|
89
|
+
eventName: string;
|
|
90
|
+
/**
|
|
91
|
+
* The matcher pattern, if configured.
|
|
92
|
+
*/
|
|
93
|
+
matcher?: string;
|
|
94
|
+
/**
|
|
95
|
+
* The timeout in milliseconds, if configured.
|
|
96
|
+
*/
|
|
97
|
+
timeout?: number;
|
|
98
|
+
/**
|
|
99
|
+
* Codex-specific status message shown while the hook runs.
|
|
100
|
+
*/
|
|
101
|
+
statusMessage?: string;
|
|
102
|
+
/**
|
|
103
|
+
* The fail-open policy, if configured.
|
|
104
|
+
*/
|
|
105
|
+
unexpectedError?: UnexpectedErrorPolicy;
|
|
106
|
+
/**
|
|
107
|
+
* The diagnostic callback for the "continue" policy, if configured.
|
|
108
|
+
*/
|
|
109
|
+
onUnexpectedError?: UnexpectedErrorHandler;
|
|
110
|
+
/**
|
|
111
|
+
* Optional context factory (unused by the Codex surface today; part of the
|
|
112
|
+
* shared core function shape).
|
|
113
|
+
*/
|
|
114
|
+
createContext?: (input: TInput) => HookContext;
|
|
115
|
+
}
|
|
116
|
+
/** Creates a PreToolUse hook handler. Excluded from the advisory list. */
|
|
117
|
+
export declare function preToolUseHook(config: MatcherHookConfigFor<"PreToolUse">, handler: (input: PreToolUseInput, context: HookContext) => PreToolUseResult | Promise<PreToolUseResult>): HookFunction<PreToolUseInput, PreToolUseResult, "PreToolUse">;
|
|
118
|
+
/** Creates a PostToolUse hook handler. Blocking variant excluded from the advisory list. */
|
|
119
|
+
export declare function postToolUseHook(config: MatcherHookConfigFor<"PostToolUse">, handler: (input: PostToolUseInput, context: HookContext) => PostToolUseResult | Promise<PostToolUseResult>): HookFunction<PostToolUseInput, PostToolUseResult, "PostToolUse">;
|
|
120
|
+
/** Creates a PermissionRequest hook handler. Excluded from the advisory list. */
|
|
121
|
+
export declare function permissionRequestHook(config: MatcherHookConfigFor<"PermissionRequest">, handler: (input: PermissionRequestInput, context: HookContext) => PermissionRequestResult | Promise<PermissionRequestResult>): HookFunction<PermissionRequestInput, PermissionRequestResult, "PermissionRequest">;
|
|
122
|
+
/** Creates a UserPromptSubmit hook handler. Advisory enrichment hook. */
|
|
123
|
+
export declare function userPromptSubmitHook(config: NoMatcherHookConfigFor<"UserPromptSubmit">, handler: (input: UserPromptSubmitInput, context: HookContext) => UserPromptSubmitResult | Promise<UserPromptSubmitResult>): HookFunction<UserPromptSubmitInput, UserPromptSubmitResult, "UserPromptSubmit">;
|
|
124
|
+
/** Creates a SessionStart hook handler. Advisory enrichment hook. */
|
|
125
|
+
export declare function sessionStartHook(config: MatcherHookConfigFor<"SessionStart">, handler: (input: SessionStartInput, context: HookContext) => SessionStartResult | Promise<SessionStartResult>): HookFunction<SessionStartInput, SessionStartResult, "SessionStart">;
|
|
126
|
+
/** Creates a SubagentStart hook handler. Advisory enrichment hook. */
|
|
127
|
+
export declare function subagentStartHook(config: MatcherHookConfigFor<"SubagentStart">, handler: (input: SubagentStartInput, context: HookContext) => SubagentStartResult | Promise<SubagentStartResult>): HookFunction<SubagentStartInput, SubagentStartResult, "SubagentStart">;
|
|
128
|
+
/** Creates a Stop hook handler. Blocking variant excluded from the advisory list. */
|
|
129
|
+
export declare function stopHook(config: NoMatcherHookConfigFor<"Stop">, handler: (input: StopInput, context: HookContext) => StopResult | Promise<StopResult>): HookFunction<StopInput, StopResult, "Stop">;
|
|
130
|
+
/** Creates a SubagentStop hook handler. Blocking variant excluded from the advisory list. */
|
|
131
|
+
export declare function subagentStopHook(config: MatcherHookConfigFor<"SubagentStop">, handler: (input: SubagentStopInput, context: HookContext) => SubagentStopResult | Promise<SubagentStopResult>): HookFunction<SubagentStopInput, SubagentStopResult, "SubagentStop">;
|
|
132
|
+
/** Creates a PreCompact hook handler. Excluded by default pending doc clarification. */
|
|
133
|
+
export declare function preCompactHook(config: MatcherHookConfigFor<"PreCompact">, handler: (input: PreCompactInput, context: HookContext) => PreCompactResult | Promise<PreCompactResult>): HookFunction<PreCompactInput, PreCompactResult, "PreCompact">;
|
|
134
|
+
/** Creates a PostCompact hook handler. Excluded by default pending doc clarification. */
|
|
135
|
+
export declare function postCompactHook(config: MatcherHookConfigFor<"PostCompact">, handler: (input: PostCompactInput, context: HookContext) => PostCompactResult | Promise<PostCompactResult>): HookFunction<PostCompactInput, PostCompactResult, "PostCompact">;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@goodfoot/agent-hooks/codex` — the Codex agent surface.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports all 10 hook factories, their output builders (reserved fields
|
|
5
|
+
* emitted only when passed), the `BlockError` block signal, input/output
|
|
6
|
+
* types, constants, the advisory allow-list events module, Logger, and the
|
|
7
|
+
* runtime `execute` entry point. No default export.
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
export type { LogEvent, LogEventHandler, LoggerConfig, LogLevel, Unsubscribe } from "../../core/logger.js";
|
|
11
|
+
export { LOG_LEVELS, Logger, logger } from "../../core/logger.js";
|
|
12
|
+
export { DEFAULT_ESBUILD_LOADERS, DEFAULT_TIMEOUT_MS, EVENTS_WITH_MATCHER, EVENTS_WITH_TEXT_OUTPUT, HOOK_FACTORY_TO_EVENT, PACKAGE_NAME, } from "./constants.js";
|
|
13
|
+
export type { AdvisoryEventName, AllowedUnexpectedErrorPolicy, ExcludedEventName, IsExcludedEvent, } from "./events.js";
|
|
14
|
+
export { ADVISORY_EVENTS, EXCLUDED_FROM_ADVISORY, HOOK_EVENT_NAMES } from "./events.js";
|
|
15
|
+
export type { HookContext, HookFunction, MatcherHookConfig, MatcherHookConfigFor, NoMatcherHookConfig, NoMatcherHookConfigFor, UnexpectedErrorHandler, UnexpectedErrorPolicy, } from "./hooks.js";
|
|
16
|
+
export { permissionRequestHook, postCompactHook, postToolUseHook, preCompactHook, preToolUseHook, sessionStartHook, stopHook, subagentStartHook, subagentStopHook, userPromptSubmitHook, } from "./hooks.js";
|
|
17
|
+
export { BlockError, EXIT_CODES, type ExitCode, type HookOutput, type HookSpecificOutput, type PermissionRequestBehavior, type PermissionRequestDecision, type PermissionRequestHookSpecificOutput, type PermissionRequestOptions, type PermissionRequestOutput, type PostCompactOptions, type PostCompactOutput, type PostToolUseHookSpecificOutput, type PostToolUseOptions, type PostToolUseOutput, type PreCompactOptions, type PreCompactOutput, type PreToolUseHookSpecificOutput, type PreToolUseLegacyBlockOptions, type PreToolUseOptions, type PreToolUseOutput, type PreToolUsePermissionDecision, permissionRequestOutput, postCompactOutput, postToolUseOutput, preCompactOutput, preToolUseLegacyBlockOutput, preToolUseOutput, type RawOutput, rawOutput, type SessionStartHookSpecificOutput, type SessionStartOptions, type SessionStartOutput, type SpecificHookOutput, type StopOptions, type StopOutput, type SubagentStartHookSpecificOutput, type SubagentStartOptions, type SubagentStartOutput, type SubagentStopOptions, type SubagentStopOutput, type SyncHookJSONOutput, sessionStartOutput, stopOutput, subagentStartOutput, subagentStopOutput, type UserPromptSubmitHookSpecificOutput, type UserPromptSubmitOptions, type UserPromptSubmitOutput, userPromptSubmitOutput, } from "./outputs.js";
|
|
18
|
+
export { convertToHookOutput, createCodexTransport, execute } from "./transport.js";
|
|
19
|
+
export type { BaseHookInput, HookErrorPhase, HookEventName, HookInput, PermissionMode, PermissionRequestInput, PostCompactInput, PostToolUseInput, PreCompactInput, PreCompactTrigger, PreToolUseInput, SessionStartInput, SessionStartSource, StopInput, SubagentStartInput, SubagentStopInput, UserPromptSubmitInput, } from "./types.js";
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { HookBlockError } from "../../core/transport.js";
|
|
2
|
+
export declare const EXIT_CODES: {
|
|
3
|
+
readonly SUCCESS: 0;
|
|
4
|
+
readonly ERROR: 1;
|
|
5
|
+
readonly BLOCK: 2;
|
|
6
|
+
};
|
|
7
|
+
export type ExitCode = (typeof EXIT_CODES)[keyof typeof EXIT_CODES];
|
|
8
|
+
interface BaseSpecificOutput<T extends string> {
|
|
9
|
+
readonly _type: T;
|
|
10
|
+
readonly stdout: SyncHookJSONOutput;
|
|
11
|
+
readonly stderr?: string;
|
|
12
|
+
}
|
|
13
|
+
export type RawOutput = BaseSpecificOutput<"Raw">;
|
|
14
|
+
export type PreToolUseOutput = BaseSpecificOutput<"PreToolUse">;
|
|
15
|
+
export type PostToolUseOutput = BaseSpecificOutput<"PostToolUse">;
|
|
16
|
+
export type PermissionRequestOutput = BaseSpecificOutput<"PermissionRequest">;
|
|
17
|
+
export type UserPromptSubmitOutput = BaseSpecificOutput<"UserPromptSubmit">;
|
|
18
|
+
export type SessionStartOutput = BaseSpecificOutput<"SessionStart">;
|
|
19
|
+
export type SubagentStartOutput = BaseSpecificOutput<"SubagentStart">;
|
|
20
|
+
export type StopOutput = BaseSpecificOutput<"Stop">;
|
|
21
|
+
export type SubagentStopOutput = BaseSpecificOutput<"SubagentStop">;
|
|
22
|
+
export type PreCompactOutput = BaseSpecificOutput<"PreCompact">;
|
|
23
|
+
export type PostCompactOutput = BaseSpecificOutput<"PostCompact">;
|
|
24
|
+
export type SpecificHookOutput = RawOutput | PreToolUseOutput | PostToolUseOutput | PermissionRequestOutput | UserPromptSubmitOutput | SessionStartOutput | SubagentStartOutput | StopOutput | SubagentStopOutput | PreCompactOutput | PostCompactOutput;
|
|
25
|
+
export interface HookOutput {
|
|
26
|
+
stdout: SyncHookJSONOutput;
|
|
27
|
+
stderr?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface SyncHookJSONOutput {
|
|
30
|
+
continue?: boolean;
|
|
31
|
+
decision?: "approve" | "block";
|
|
32
|
+
hookSpecificOutput?: HookSpecificOutput;
|
|
33
|
+
reason?: string;
|
|
34
|
+
stopReason?: string;
|
|
35
|
+
suppressOutput?: boolean;
|
|
36
|
+
systemMessage?: string;
|
|
37
|
+
}
|
|
38
|
+
export type HookSpecificOutput = PreToolUseHookSpecificOutput | PostToolUseHookSpecificOutput | PermissionRequestHookSpecificOutput | UserPromptSubmitHookSpecificOutput | SessionStartHookSpecificOutput | SubagentStartHookSpecificOutput;
|
|
39
|
+
export type PreToolUsePermissionDecision = "allow" | "deny" | "ask";
|
|
40
|
+
export interface PreToolUseHookSpecificOutput {
|
|
41
|
+
hookEventName: "PreToolUse";
|
|
42
|
+
additionalContext?: string;
|
|
43
|
+
permissionDecision?: PreToolUsePermissionDecision;
|
|
44
|
+
permissionDecisionReason?: string;
|
|
45
|
+
updatedInput?: unknown;
|
|
46
|
+
}
|
|
47
|
+
export interface PostToolUseHookSpecificOutput {
|
|
48
|
+
hookEventName: "PostToolUse";
|
|
49
|
+
additionalContext?: string;
|
|
50
|
+
updatedMCPToolOutput?: unknown;
|
|
51
|
+
}
|
|
52
|
+
export type PermissionRequestBehavior = "allow" | "deny";
|
|
53
|
+
export interface PermissionRequestDecision {
|
|
54
|
+
behavior: PermissionRequestBehavior;
|
|
55
|
+
message?: string;
|
|
56
|
+
interrupt?: boolean;
|
|
57
|
+
updatedInput?: unknown;
|
|
58
|
+
updatedPermissions?: unknown;
|
|
59
|
+
}
|
|
60
|
+
export interface PermissionRequestHookSpecificOutput {
|
|
61
|
+
hookEventName: "PermissionRequest";
|
|
62
|
+
decision?: PermissionRequestDecision;
|
|
63
|
+
}
|
|
64
|
+
export interface UserPromptSubmitHookSpecificOutput {
|
|
65
|
+
hookEventName: "UserPromptSubmit";
|
|
66
|
+
additionalContext?: string;
|
|
67
|
+
}
|
|
68
|
+
export interface SessionStartHookSpecificOutput {
|
|
69
|
+
hookEventName: "SessionStart";
|
|
70
|
+
additionalContext?: string;
|
|
71
|
+
}
|
|
72
|
+
export interface SubagentStartHookSpecificOutput {
|
|
73
|
+
hookEventName: "SubagentStart";
|
|
74
|
+
additionalContext?: string;
|
|
75
|
+
}
|
|
76
|
+
export interface PreToolUseOptions {
|
|
77
|
+
continue?: boolean;
|
|
78
|
+
stopReason?: string;
|
|
79
|
+
suppressOutput?: boolean;
|
|
80
|
+
systemMessage?: string;
|
|
81
|
+
decision?: "approve" | "block";
|
|
82
|
+
reason?: string;
|
|
83
|
+
additionalContext?: string;
|
|
84
|
+
permissionDecision?: PreToolUsePermissionDecision;
|
|
85
|
+
permissionDecisionReason?: string;
|
|
86
|
+
updatedInput?: unknown;
|
|
87
|
+
}
|
|
88
|
+
export interface PreToolUseLegacyBlockOptions {
|
|
89
|
+
systemMessage?: string;
|
|
90
|
+
decision: "block";
|
|
91
|
+
reason: string;
|
|
92
|
+
}
|
|
93
|
+
export interface PostToolUseOptions {
|
|
94
|
+
continue?: boolean;
|
|
95
|
+
stopReason?: string;
|
|
96
|
+
suppressOutput?: boolean;
|
|
97
|
+
systemMessage?: string;
|
|
98
|
+
decision?: "block";
|
|
99
|
+
reason?: string;
|
|
100
|
+
additionalContext?: string;
|
|
101
|
+
updatedMCPToolOutput?: unknown;
|
|
102
|
+
}
|
|
103
|
+
export interface PermissionRequestOptions {
|
|
104
|
+
continue?: boolean;
|
|
105
|
+
stopReason?: string;
|
|
106
|
+
suppressOutput?: boolean;
|
|
107
|
+
systemMessage?: string;
|
|
108
|
+
behavior: PermissionRequestBehavior;
|
|
109
|
+
message?: string;
|
|
110
|
+
interrupt?: boolean;
|
|
111
|
+
updatedInput?: unknown;
|
|
112
|
+
updatedPermissions?: unknown;
|
|
113
|
+
}
|
|
114
|
+
export interface UserPromptSubmitOptions {
|
|
115
|
+
continue?: boolean;
|
|
116
|
+
stopReason?: string;
|
|
117
|
+
suppressOutput?: boolean;
|
|
118
|
+
systemMessage?: string;
|
|
119
|
+
decision?: "block";
|
|
120
|
+
reason?: string;
|
|
121
|
+
additionalContext?: string;
|
|
122
|
+
}
|
|
123
|
+
export interface SessionStartOptions {
|
|
124
|
+
continue?: boolean;
|
|
125
|
+
stopReason?: string;
|
|
126
|
+
suppressOutput?: boolean;
|
|
127
|
+
systemMessage?: string;
|
|
128
|
+
additionalContext?: string;
|
|
129
|
+
}
|
|
130
|
+
export interface SubagentStartOptions {
|
|
131
|
+
continue?: boolean;
|
|
132
|
+
stopReason?: string;
|
|
133
|
+
suppressOutput?: boolean;
|
|
134
|
+
systemMessage?: string;
|
|
135
|
+
additionalContext?: string;
|
|
136
|
+
}
|
|
137
|
+
export interface StopOptions {
|
|
138
|
+
continue?: boolean;
|
|
139
|
+
stopReason?: string;
|
|
140
|
+
suppressOutput?: boolean;
|
|
141
|
+
systemMessage?: string;
|
|
142
|
+
decision?: "block";
|
|
143
|
+
reason?: string;
|
|
144
|
+
}
|
|
145
|
+
export interface SubagentStopOptions {
|
|
146
|
+
continue?: boolean;
|
|
147
|
+
stopReason?: string;
|
|
148
|
+
suppressOutput?: boolean;
|
|
149
|
+
systemMessage?: string;
|
|
150
|
+
decision?: "block";
|
|
151
|
+
reason?: string;
|
|
152
|
+
}
|
|
153
|
+
export interface PreCompactOptions {
|
|
154
|
+
continue?: boolean;
|
|
155
|
+
stopReason?: string;
|
|
156
|
+
suppressOutput?: boolean;
|
|
157
|
+
systemMessage?: string;
|
|
158
|
+
}
|
|
159
|
+
export interface PostCompactOptions {
|
|
160
|
+
continue?: boolean;
|
|
161
|
+
stopReason?: string;
|
|
162
|
+
suppressOutput?: boolean;
|
|
163
|
+
systemMessage?: string;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* The Codex block signal, carried into the new package as a subclass of the
|
|
167
|
+
* shared core {@link ../core/transport.ts|HookBlockError} so `drive()`
|
|
168
|
+
* classifies it **before** consulting `unexpectedError` policy — carrying an
|
|
169
|
+
* ordering the source runtime already implemented (`runtime.ts` tested
|
|
170
|
+
* `instanceof BlockError` ahead of the policy branch). Public surface is
|
|
171
|
+
* preserved: `name`, `reason`, and `instanceof BlockError` semantics are
|
|
172
|
+
* unchanged, and `instanceof HookBlockError` now also holds.
|
|
173
|
+
*/
|
|
174
|
+
export declare class BlockError extends HookBlockError {
|
|
175
|
+
readonly reason: string;
|
|
176
|
+
constructor(reason: string);
|
|
177
|
+
}
|
|
178
|
+
export declare function rawOutput(stdout: SyncHookJSONOutput, stderr?: string): SpecificHookOutput;
|
|
179
|
+
export declare function preToolUseOutput(options?: PreToolUseOptions): PreToolUseOutput;
|
|
180
|
+
export declare function preToolUseLegacyBlockOutput(options: PreToolUseLegacyBlockOptions): PreToolUseOutput;
|
|
181
|
+
export declare function postToolUseOutput(options?: PostToolUseOptions): PostToolUseOutput;
|
|
182
|
+
export declare function permissionRequestOutput(options: PermissionRequestOptions): PermissionRequestOutput;
|
|
183
|
+
export declare function userPromptSubmitOutput(options?: UserPromptSubmitOptions): UserPromptSubmitOutput;
|
|
184
|
+
export declare function sessionStartOutput(options?: SessionStartOptions): SessionStartOutput;
|
|
185
|
+
export declare function subagentStartOutput(options?: SubagentStartOptions): SubagentStartOutput;
|
|
186
|
+
export declare function stopOutput(options?: StopOptions): StopOutput;
|
|
187
|
+
export declare function subagentStopOutput(options?: SubagentStopOptions): SubagentStopOutput;
|
|
188
|
+
export declare function preCompactOutput(options?: PreCompactOptions): PreCompactOutput;
|
|
189
|
+
export declare function postCompactOutput(options?: PostCompactOptions): PostCompactOutput;
|
|
190
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { HookEventName } from "./types.js";
|
|
2
|
+
export interface ScaffoldOptions {
|
|
3
|
+
directory: string;
|
|
4
|
+
hooks: string[];
|
|
5
|
+
outputPath: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function validateHookNames(hookNames: string[]): {
|
|
8
|
+
valid: true;
|
|
9
|
+
normalized: HookEventName[];
|
|
10
|
+
} | {
|
|
11
|
+
valid: false;
|
|
12
|
+
error: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function scaffoldProject(options: ScaffoldOptions): void;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire transport for Codex hooks, rewritten against the core
|
|
3
|
+
* `drive()`/`Transport` interface; the wire semantics carry over
|
|
4
|
+
* `codex-hooks/src/runtime.ts` verbatim:
|
|
5
|
+
*
|
|
6
|
+
* - **BlockError → its reason written to stderr + exit 2, regardless of
|
|
7
|
+
* policy** — a single translation for every event including
|
|
8
|
+
* `SubagentStart`; there is deliberately no per-event table here (Codex
|
|
9
|
+
* has no narrower native deny shape than the stderr channel). The source
|
|
10
|
+
* runtime already classified `BlockError` ahead of the policy branch; that
|
|
11
|
+
* precedence now lives in `drive()` via {@link BlockError} extending the
|
|
12
|
+
* core `HookBlockError`.
|
|
13
|
+
* - every other unexpected failure (stdin read, parse, handler, serialize,
|
|
14
|
+
* write, cleanup) under the default `"error"` policy → stacktrace on
|
|
15
|
+
* stderr + exit 1 (`ERROR`) — note Codex exits **1**, unlike Claude Code's
|
|
16
|
+
* handler-error exit 2; under `"continue"` → reported and swallowed to the
|
|
17
|
+
* event's valid empty output `{}` at exit 0. Malformed stdin is therefore
|
|
18
|
+
* NOT unconditionally fail-open on Codex — the policy decides, exactly as
|
|
19
|
+
* in the source runtime.
|
|
20
|
+
* - success → `JSON.stringify(output.stdout)` at exit 0; a `null`/`undefined`
|
|
21
|
+
* result serializes as `{}`, valid for every event's output schema.
|
|
22
|
+
* - a returned `stderr` **field** on an output object is carried by
|
|
23
|
+
* `convertToHookOutput` but discarded by the success path — the source
|
|
24
|
+
* runtime only ever serialized `output.stdout`; blocking is expressed
|
|
25
|
+
* exclusively through the thrown-`BlockError` channel.
|
|
26
|
+
*
|
|
27
|
+
* String returns (`"Loaded from text"`) are normalized into the event's
|
|
28
|
+
* additionalContext output for the three text-output events; any other event
|
|
29
|
+
* rejecting plain text throws exactly like the source, flowing through the
|
|
30
|
+
* standard policy-gated error path.
|
|
31
|
+
* @module
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* // In a compiled hook file
|
|
35
|
+
* import { execute } from './transport.js';
|
|
36
|
+
* import myHook from './my-hook.js';
|
|
37
|
+
*
|
|
38
|
+
* execute(myHook);
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
import type { Transport } from "../../core/transport.js";
|
|
42
|
+
import type { HookFunction } from "./hooks.js";
|
|
43
|
+
import { type SpecificHookOutput } from "./outputs.js";
|
|
44
|
+
import type { HookEventName, HookInput } from "./types.js";
|
|
45
|
+
/**
|
|
46
|
+
* Converts a SpecificHookOutput to the wire shape by stripping the `_type`
|
|
47
|
+
* discriminator (source parity: builders produce wire-format directly).
|
|
48
|
+
*/
|
|
49
|
+
export declare function convertToHookOutput(output: SpecificHookOutput): {
|
|
50
|
+
stdout: SpecificHookOutput["stdout"];
|
|
51
|
+
stderr?: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Normalizes a plain-string handler return into the event's additionalContext
|
|
55
|
+
* output; non-text events reject strings with the source package's exact
|
|
56
|
+
* error, which then flows through the standard policy-gated error path.
|
|
57
|
+
*/
|
|
58
|
+
export declare function normalizeStringOutput(hookEventName: HookEventName, result: string): SpecificHookOutput;
|
|
59
|
+
/**
|
|
60
|
+
* Builds the Codex wire transport. Unlike the Claude Code adapter there is no
|
|
61
|
+
* per-event block-shape table: every caught {@link BlockError} translates to
|
|
62
|
+
* `stderr: reason + "\n"` at exit 2 under every policy value, and no
|
|
63
|
+
* `rawStdout` predicate exists because Codex has no plain-text-stdout
|
|
64
|
+
* protocol events (the `rawOutput()` builder is ordinary JSON passthrough).
|
|
65
|
+
*/
|
|
66
|
+
export declare function createCodexTransport(): Transport<SpecificHookOutput | undefined>;
|
|
67
|
+
/**
|
|
68
|
+
* Executes a hook handler with full runtime orchestration (delegates to the
|
|
69
|
+
* shared core driver with this agent's transport). String returns are
|
|
70
|
+
* normalized before the driver sees them so that a plain-text violation
|
|
71
|
+
* classifies through the same policy gate as any other handler failure,
|
|
72
|
+
* matching the source runtime's observable wire behaviour.
|
|
73
|
+
*/
|
|
74
|
+
export declare function execute<TInput extends HookInput, TOutput>(hookFn: HookFunction<TInput, TOutput, HookEventName>): Promise<void>;
|