@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,139 @@
|
|
|
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 { drive } from "../../core/transport.js";
|
|
42
|
+
import { EVENTS_WITH_TEXT_OUTPUT } from "./constants.js";
|
|
43
|
+
import { BlockError, EXIT_CODES, sessionStartOutput, subagentStartOutput, userPromptSubmitOutput, } from "./outputs.js";
|
|
44
|
+
/**
|
|
45
|
+
* Converts a SpecificHookOutput to the wire shape by stripping the `_type`
|
|
46
|
+
* discriminator (source parity: builders produce wire-format directly).
|
|
47
|
+
*/
|
|
48
|
+
export function convertToHookOutput(output) {
|
|
49
|
+
return output.stderr !== undefined ? { stdout: output.stdout, stderr: output.stderr } : { stdout: output.stdout };
|
|
50
|
+
}
|
|
51
|
+
function formatErrorText(error) {
|
|
52
|
+
return error instanceof Error ? `${error.stack ?? error.message}\n` : `${String(error)}\n`;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Normalizes a plain-string handler return into the event's additionalContext
|
|
56
|
+
* output; non-text events reject strings with the source package's exact
|
|
57
|
+
* error, which then flows through the standard policy-gated error path.
|
|
58
|
+
*/
|
|
59
|
+
export function normalizeStringOutput(hookEventName, result) {
|
|
60
|
+
if (!EVENTS_WITH_TEXT_OUTPUT.has(hookEventName)) {
|
|
61
|
+
throw new Error(`${hookEventName} hooks cannot return plain text`);
|
|
62
|
+
}
|
|
63
|
+
if (hookEventName === "SessionStart") {
|
|
64
|
+
return sessionStartOutput({ additionalContext: result });
|
|
65
|
+
}
|
|
66
|
+
if (hookEventName === "SubagentStart") {
|
|
67
|
+
return subagentStartOutput({ additionalContext: result });
|
|
68
|
+
}
|
|
69
|
+
return userPromptSubmitOutput({ additionalContext: result });
|
|
70
|
+
}
|
|
71
|
+
// ============================================================================
|
|
72
|
+
// Transport
|
|
73
|
+
// ============================================================================
|
|
74
|
+
/**
|
|
75
|
+
* Builds the Codex wire transport. Unlike the Claude Code adapter there is no
|
|
76
|
+
* per-event block-shape table: every caught {@link BlockError} translates to
|
|
77
|
+
* `stderr: reason + "\n"` at exit 2 under every policy value, and no
|
|
78
|
+
* `rawStdout` predicate exists because Codex has no plain-text-stdout
|
|
79
|
+
* protocol events (the `rawOutput()` builder is ordinary JSON passthrough).
|
|
80
|
+
*/
|
|
81
|
+
export function createCodexTransport() {
|
|
82
|
+
return {
|
|
83
|
+
finalize(outcome) {
|
|
84
|
+
switch (outcome.kind) {
|
|
85
|
+
case "response":
|
|
86
|
+
case "rawStdout": {
|
|
87
|
+
// The rawStdout outcome cannot occur for Codex (no plain-text
|
|
88
|
+
// protocol events, no rawStdout predicate) but the union demands
|
|
89
|
+
// handling; it serializes as the empty response.
|
|
90
|
+
const stdoutJson = outcome.kind === "response" && outcome.output !== null && outcome.output !== undefined
|
|
91
|
+
? JSON.stringify(convertToHookOutput(outcome.output).stdout)
|
|
92
|
+
: "{}";
|
|
93
|
+
return { stdout: stdoutJson, exitCode: EXIT_CODES.SUCCESS };
|
|
94
|
+
}
|
|
95
|
+
case "block": {
|
|
96
|
+
const reason = outcome.error instanceof BlockError ? outcome.error.reason : outcome.error.message;
|
|
97
|
+
return { stderr: `${reason}\n`, exitCode: EXIT_CODES.BLOCK };
|
|
98
|
+
}
|
|
99
|
+
case "handlerError": {
|
|
100
|
+
// Codex surfaces EVERY unexpected failure — stdin read/parse
|
|
101
|
+
// included — through one policy gate exiting ERROR(1) on the
|
|
102
|
+
// default policy; malformed stdin is not unconditionally fail-open
|
|
103
|
+
// here (that is Claude Code's rule, not Codex's).
|
|
104
|
+
return { stderr: formatErrorText(outcome.error), exitCode: EXIT_CODES.ERROR };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// Execute
|
|
112
|
+
// ============================================================================
|
|
113
|
+
/**
|
|
114
|
+
* Executes a hook handler with full runtime orchestration (delegates to the
|
|
115
|
+
* shared core driver with this agent's transport). String returns are
|
|
116
|
+
* normalized before the driver sees them so that a plain-text violation
|
|
117
|
+
* classifies through the same policy gate as any other handler failure,
|
|
118
|
+
* matching the source runtime's observable wire behaviour.
|
|
119
|
+
*/
|
|
120
|
+
export async function execute(hookFn) {
|
|
121
|
+
const eventName = hookFn.hookEventName;
|
|
122
|
+
const composed = ((input, context) => {
|
|
123
|
+
const result = hookFn(input, context);
|
|
124
|
+
const normalize = (value) => {
|
|
125
|
+
if (typeof value === "string") {
|
|
126
|
+
return normalizeStringOutput(eventName, value);
|
|
127
|
+
}
|
|
128
|
+
return value;
|
|
129
|
+
};
|
|
130
|
+
return result instanceof Promise ? result.then(normalize) : normalize(result);
|
|
131
|
+
});
|
|
132
|
+
composed.eventName = hookFn.eventName ?? eventName;
|
|
133
|
+
composed.matcher = hookFn.matcher;
|
|
134
|
+
composed.timeout = hookFn.timeout;
|
|
135
|
+
composed.unexpectedError = hookFn.unexpectedError;
|
|
136
|
+
composed.onUnexpectedError = hookFn.onUnexpectedError;
|
|
137
|
+
composed.createContext = hookFn.createContext;
|
|
138
|
+
await drive(createCodexTransport(), composed);
|
|
139
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|