@weave_protocol/adapter-codex 0.0.0-stage → 0.1.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 +68 -2
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +108 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +45 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +75 -0
- package/dist/config.js.map +1 -0
- package/dist/hook.d.ts +35 -0
- package/dist/hook.d.ts.map +1 -0
- package/dist/hook.js +137 -0
- package/dist/hook.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/patch.d.ts +16 -0
- package/dist/patch.d.ts.map +1 -0
- package/dist/patch.js +23 -0
- package/dist/patch.js.map +1 -0
- package/dist/types.d.ts +53 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +28 -0
- package/dist/types.js.map +1 -0
- package/package.json +53 -4
package/README.md
CHANGED
|
@@ -1,3 +1,69 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 🛡️ @weave_protocol/adapter-codex
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Enforce [WARD.md](https://github.com/Tyox-all/Weave_Protocol/tree/main/ward) in **OpenAI Codex CLI** with its `PreToolUse` hook. Every shell command, file edit and MCP call is checked against your policy before it runs.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@weave_protocol/adapter-codex)
|
|
6
|
+
|
|
7
|
+
The same WARD.md you use with Claude Code, Antigravity, Microsoft Agent Framework and Gemini CLI.
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm i -g @weave_protocol/adapter-codex
|
|
13
|
+
weave-ward-codex init # adds the hook to ~/.codex/hooks.json
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Then, in Codex, run **`/hooks`** and trust **"Weave: checking WARD.md"**. Codex skips new or changed hooks until you trust them. Add a `WARD.md` to your project (`npx @weave_protocol/ward init`), or a user-wide one at `~/.codex/WARD.md`.
|
|
17
|
+
|
|
18
|
+
The command is `weave-ward-codex`, not `weave-codex`. The `weave-codex` npm name belongs to W&B Weave's Codex integration, which is a different product.
|
|
19
|
+
|
|
20
|
+
## What it checks
|
|
21
|
+
|
|
22
|
+
The hook uses Ward's shared evaluator (`evaluateToolCall`), so the rules match the other adapters exactly:
|
|
23
|
+
|
|
24
|
+
- **Shell commands** (`Bash`, including unified exec): the `shell_exec` capability, plus every URL and every absolute or `~` path in the command.
|
|
25
|
+
- **File edits** (`apply_patch`): the files the patch touches, read from its `*** Add File`, `*** Update File`, `*** Move to` and `*** Delete File` lines. Adds, updates and moves are writes; deletes are deletes. Text inside the patch is never treated as a target.
|
|
26
|
+
- **MCP tools** (`mcp__<server>__<tool>`): by name, plus their path and URL arguments.
|
|
27
|
+
- **`update_plan`** uses the `task_planning` capability, the same one the Gemini CLI adapter uses for planning tools.
|
|
28
|
+
|
|
29
|
+
Codex's hosted tools, such as web search, don't go through `PreToolUse`. Neither do some specialized paths, as Codex's docs note. Treat the hook as a guardrail, and combine it with Codex's own sandbox and approval settings.
|
|
30
|
+
|
|
31
|
+
## Decisions
|
|
32
|
+
|
|
33
|
+
| WARD decision | What Codex sees |
|
|
34
|
+
|---|---|
|
|
35
|
+
| allow | nothing: the call continues, and Codex's own approvals still apply |
|
|
36
|
+
| deny | `permissionDecision: "deny"` with the WARD reason, which the model sees |
|
|
37
|
+
| require_approval | a deny whose reason says approval is needed (Codex hooks don't support "ask") |
|
|
38
|
+
|
|
39
|
+
**Failure modes:**
|
|
40
|
+
- **An invalid WARD.md always denies**, so a typo can't silently switch enforcement off.
|
|
41
|
+
- **No WARD.md anywhere means no enforcement.**
|
|
42
|
+
- **Malformed payloads and evaluator errors** allow by default. `init --fail-closed` makes them deny.
|
|
43
|
+
|
|
44
|
+
WARD.md is looked up in this order:
|
|
45
|
+
1. `$WEAVE_WARD_PATH`
|
|
46
|
+
2. `<project>/WARD.md`
|
|
47
|
+
3. `<project>/.codex/WARD.md`
|
|
48
|
+
4. `<project>/.weave/WARD.md`
|
|
49
|
+
5. `$CODEX_HOME/WARD.md` (default `~/.codex/WARD.md`)
|
|
50
|
+
|
|
51
|
+
## Commands
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
weave-ward-codex init [--matcher=REGEX] [--timeout=SECONDS] [--fail-closed]
|
|
55
|
+
weave-ward-codex disable
|
|
56
|
+
weave-ward-codex status
|
|
57
|
+
weave-ward-codex test Bash --input='{"command":"cat secrets/key"}' # dry run
|
|
58
|
+
weave-ward-codex hook pre-tool-use # what Codex runs
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`init` writes to `$CODEX_HOME/hooks.json` (default `~/.codex/hooks.json`). It backs the file up, edits it atomically, and finds its own entry by its status message, so your other hooks are untouched.
|
|
62
|
+
|
|
63
|
+
## Verified
|
|
64
|
+
|
|
65
|
+
Built against Codex's [hooks documentation](https://developers.openai.com/codex/hooks): the `PreToolUse` payload, deny output, `apply_patch` and MCP tool naming. 12 fixture tests.
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
Apache-2.0
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* weave-ward-codex CLI
|
|
4
|
+
*
|
|
5
|
+
* weave-ward-codex init [--matcher=REGEX] [--timeout=SECONDS] [--fail-closed] Install the WARD hook
|
|
6
|
+
* weave-ward-codex disable Remove it
|
|
7
|
+
* weave-ward-codex status Hook + active WARD.md
|
|
8
|
+
* weave-ward-codex test <tool> [--input=JSON] Dry-run a tool call
|
|
9
|
+
* weave-ward-codex hook pre-tool-use [--fail-closed] Hook handler (run by Codex)
|
|
10
|
+
*
|
|
11
|
+
* (Not "weave-codex": that npm name belongs to W&B Weave's Codex integration.)
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* weave-ward-codex CLI
|
|
4
|
+
*
|
|
5
|
+
* weave-ward-codex init [--matcher=REGEX] [--timeout=SECONDS] [--fail-closed] Install the WARD hook
|
|
6
|
+
* weave-ward-codex disable Remove it
|
|
7
|
+
* weave-ward-codex status Hook + active WARD.md
|
|
8
|
+
* weave-ward-codex test <tool> [--input=JSON] Dry-run a tool call
|
|
9
|
+
* weave-ward-codex hook pre-tool-use [--fail-closed] Hook handler (run by Codex)
|
|
10
|
+
*
|
|
11
|
+
* (Not "weave-codex": that npm name belongs to W&B Weave's Codex integration.)
|
|
12
|
+
*/
|
|
13
|
+
import { installHook, removeHook, isHookInstalled, readHooks, hooksJsonPath, userWardPath } from './config.js';
|
|
14
|
+
import { resolveWardForCwd, evaluateCall, runPreToolUseHook } from './hook.js';
|
|
15
|
+
const tty = process.stderr.isTTY && !process.env.NO_COLOR;
|
|
16
|
+
const c = {
|
|
17
|
+
reset: tty ? '\x1b[0m' : '', bold: tty ? '\x1b[1m' : '', red: tty ? '\x1b[31m' : '',
|
|
18
|
+
green: tty ? '\x1b[32m' : '', yellow: tty ? '\x1b[33m' : '', cyan: tty ? '\x1b[36m' : '', gray: tty ? '\x1b[90m' : '',
|
|
19
|
+
};
|
|
20
|
+
const say = (s = '') => console.error(s);
|
|
21
|
+
const flag = (args, name) => args.includes(`--${name}`);
|
|
22
|
+
const option = (args, name) => args.find((a) => a.startsWith(`--${name}=`))?.slice(name.length + 3);
|
|
23
|
+
function help() {
|
|
24
|
+
say(`\n${c.cyan}${c.bold}🛡️ weave-ward-codex${c.reset} ${c.gray}WARD.md enforcement for OpenAI Codex CLI${c.reset}\n`);
|
|
25
|
+
say(`${c.bold}Commands:${c.reset}`);
|
|
26
|
+
say(` ${c.cyan}init${c.reset} ${c.gray}[--matcher=REGEX] [--timeout=SECONDS] [--fail-closed]${c.reset} Install the PreToolUse hook in ~/.codex/hooks.json`);
|
|
27
|
+
say(` ${c.cyan}disable${c.reset} Remove the hook`);
|
|
28
|
+
say(` ${c.cyan}status${c.reset} Show the hook and the active WARD.md`);
|
|
29
|
+
say(` ${c.cyan}test${c.reset} ${c.gray}<tool> [--input=JSON]${c.reset} Dry-run a tool call against WARD.md`);
|
|
30
|
+
say(` ${c.cyan}hook pre-tool-use${c.reset} ${c.gray}[--fail-closed]${c.reset} Hook handler (Codex runs this)\n`);
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
function init(args) {
|
|
34
|
+
const timeout = option(args, 'timeout');
|
|
35
|
+
installHook({
|
|
36
|
+
matcher: option(args, 'matcher'),
|
|
37
|
+
timeoutSeconds: timeout ? Number(timeout) : undefined,
|
|
38
|
+
failClosed: flag(args, 'fail-closed'),
|
|
39
|
+
});
|
|
40
|
+
say(`${c.green}✓${c.reset} WARD hook installed in ${hooksJsonPath()}`);
|
|
41
|
+
say(`${c.yellow}!${c.reset} Codex skips new hooks until you trust them: run ${c.bold}/hooks${c.reset} in Codex and trust "${'Weave: checking WARD.md'}".`);
|
|
42
|
+
const ward = safeResolve(process.cwd());
|
|
43
|
+
if (!ward) {
|
|
44
|
+
say(`${c.yellow}!${c.reset} No WARD.md found here or at ${userWardPath()}; calls are allowed until you add one.`);
|
|
45
|
+
}
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
function disable() {
|
|
49
|
+
const { removed } = removeHook();
|
|
50
|
+
say(removed ? `${c.green}✓${c.reset} Removed the WARD hook from ${hooksJsonPath()}` : 'No WARD hook was installed.');
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
function safeResolve(cwd) {
|
|
54
|
+
try {
|
|
55
|
+
return resolveWardForCwd(cwd);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
say(`${c.red}✗${c.reset} ${err instanceof Error ? err.message : String(err)}`);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function status() {
|
|
63
|
+
const installed = isHookInstalled(readHooks());
|
|
64
|
+
say(`Hook: ${installed ? `${c.green}installed${c.reset}` : `${c.yellow}not installed${c.reset}`} (${hooksJsonPath()})`);
|
|
65
|
+
const ward = safeResolve(process.cwd());
|
|
66
|
+
say(`WARD.md: ${ward ? ward.source : `${c.yellow}none found${c.reset}`}`);
|
|
67
|
+
return installed && ward ? 0 : 1;
|
|
68
|
+
}
|
|
69
|
+
function test(args) {
|
|
70
|
+
const tool = args.find((a) => !a.startsWith('--'));
|
|
71
|
+
if (!tool) {
|
|
72
|
+
say('Usage: weave-ward-codex test <tool> [--input=JSON]');
|
|
73
|
+
return 2;
|
|
74
|
+
}
|
|
75
|
+
const ward = safeResolve(process.cwd());
|
|
76
|
+
if (!ward) {
|
|
77
|
+
say('No WARD.md found; nothing to test against.');
|
|
78
|
+
return 2;
|
|
79
|
+
}
|
|
80
|
+
const input = JSON.parse(option(args, 'input') ?? '{}');
|
|
81
|
+
const result = evaluateCall(ward.policy, tool, input, process.cwd());
|
|
82
|
+
const color = result.decision === 'allow' ? c.green : result.decision === 'deny' ? c.red : c.yellow;
|
|
83
|
+
say(`${color}${result.decision}${c.reset} ${tool}`);
|
|
84
|
+
for (const r of result.reasons)
|
|
85
|
+
say(` ${c.gray}${r}${c.reset}`);
|
|
86
|
+
return result.decision === 'allow' ? 0 : 1;
|
|
87
|
+
}
|
|
88
|
+
async function main() {
|
|
89
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
90
|
+
switch (cmd) {
|
|
91
|
+
case 'init': return init(rest);
|
|
92
|
+
case 'disable':
|
|
93
|
+
case 'uninstall': return disable();
|
|
94
|
+
case 'status': return status();
|
|
95
|
+
case 'test': return test(rest);
|
|
96
|
+
case 'hook':
|
|
97
|
+
if (rest[0] === 'pre-tool-use' || !rest[0])
|
|
98
|
+
return runPreToolUseHook(flag(rest, 'fail-closed'));
|
|
99
|
+
// Other events: print nothing, so the call continues
|
|
100
|
+
return 0;
|
|
101
|
+
default: return help();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
main().then((code) => process.exit(code), (err) => {
|
|
105
|
+
say(`weave-ward-codex: ${err instanceof Error ? err.message : String(err)}`);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
});
|
|
108
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/G,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE/E,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC1D,MAAM,CAAC,GAAG;IACR,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;IACnF,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;CACtH,CAAC;AACF,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEzC,MAAM,IAAI,GAAG,CAAC,IAAc,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;AAC1E,MAAM,MAAM,GAAG,CAAC,IAAc,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAEtH,SAAS,IAAI;IACX,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,wBAAwB,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,2CAA2C,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IACzH,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IACpC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,wDAAwD,CAAC,CAAC,KAAK,sDAAsD,CAAC,CAAC;IAC9J,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,KAAK,+DAA+D,CAAC,CAAC;IACjG,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,KAAK,qFAAqF,CAAC,CAAC;IACtH,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,wBAAwB,CAAC,CAAC,KAAK,gEAAgE,CAAC,CAAC;IACxI,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,oBAAoB,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,KAAK,qDAAqD,CAAC,CAAC;IACpI,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,IAAI,CAAC,IAAc;IAC1B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACxC,WAAW,CAAC;QACV,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC;QAChC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;QACrD,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC;KACtC,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,2BAA2B,aAAa,EAAE,EAAE,CAAC,CAAC;IACvE,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,oDAAoD,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,KAAK,wBAAwB,yBAAyB,IAAI,CAAC,CAAC;IAC3J,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACxC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,gCAAgC,YAAY,EAAE,wCAAwC,CAAC,CAAC;IACpH,CAAC;IAED,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,OAAO;IACd,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,CAAC;IACjC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,+BAA+B,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC;IACrH,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,CAAC;QACH,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,IAAI,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/E,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,MAAM;IACb,MAAM,SAAS,GAAG,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC;IAC/C,GAAG,CAAC,aAAa,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,gBAAgB,CAAC,CAAC,KAAK,EAAE,KAAK,aAAa,EAAE,GAAG,CAAC,CAAC;IAC5H,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACxC,GAAG,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,aAAa,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3E,OAAO,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,IAAI,CAAC,IAAc;IAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IACnD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,GAAG,CAAC,oDAAoD,CAAC,CAAC;QAC1D,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACxC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,GAAG,CAAC,4CAA4C,CAAC,CAAC;QAClD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACrE,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACpG,GAAG,CAAC,GAAG,KAAK,GAAG,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC;IACpD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO;QAAE,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IACjE,OAAO,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7C,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,MAAM,EAAE,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,KAAK,SAAS,CAAC;QACf,KAAK,WAAW,EAAE,OAAO,OAAO,EAAE,CAAC;QACnC,KAAK,QAAQ,EAAE,OAAO,MAAM,EAAE,CAAC;QAC/B,KAAK,MAAM,EAAE,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,KAAK,MAAM;YACT,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,cAAc,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBAAE,OAAO,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC;YAChG,qDAAqD;YACrD,OAAO,CAAC,CAAC;QACX,SAAS,OAAO,IAAI,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE;IAChD,GAAG,CAAC,qBAAqB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manage $CODEX_HOME/hooks.json (default ~/.codex/hooks.json) — install,
|
|
3
|
+
* remove, inspect the WARD hook.
|
|
4
|
+
*
|
|
5
|
+
* Safety rules:
|
|
6
|
+
* - Back up hooks.json before changing it, and write atomically
|
|
7
|
+
* - Idempotent: init twice leaves one entry
|
|
8
|
+
* - Our entry is found by its statusMessage; other hooks are untouched
|
|
9
|
+
*
|
|
10
|
+
* Codex skips new or changed hooks until they are trusted: after init, run
|
|
11
|
+
* /hooks in Codex and trust the Weave hook.
|
|
12
|
+
*/
|
|
13
|
+
import type { CodexHookGroup } from './types.js';
|
|
14
|
+
export declare const STATUS_MESSAGE = "Weave: checking WARD.md";
|
|
15
|
+
export declare function codexHome(): string;
|
|
16
|
+
export declare function hooksJsonPath(): string;
|
|
17
|
+
/** User-global WARD.md, used when a project has none. */
|
|
18
|
+
export declare function userWardPath(): string;
|
|
19
|
+
export interface HooksFile {
|
|
20
|
+
description?: string;
|
|
21
|
+
hooks?: {
|
|
22
|
+
PreToolUse?: CodexHookGroup[];
|
|
23
|
+
[event: string]: CodexHookGroup[] | undefined;
|
|
24
|
+
};
|
|
25
|
+
[other: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
export declare function readHooks(path?: string): HooksFile;
|
|
28
|
+
export declare function writeHooks(file: HooksFile, path?: string): void;
|
|
29
|
+
export interface InstallOptions {
|
|
30
|
+
/** Command that runs this CLI. Default: "weave-ward-codex" */
|
|
31
|
+
binary?: string;
|
|
32
|
+
/** Regex of tool names to gate. Default: every tool */
|
|
33
|
+
matcher?: string;
|
|
34
|
+
/** Hook timeout in seconds (Codex's unit). Default 10 */
|
|
35
|
+
timeoutSeconds?: number;
|
|
36
|
+
/** Deny on malformed payloads and evaluator errors. Default: allow */
|
|
37
|
+
failClosed?: boolean;
|
|
38
|
+
}
|
|
39
|
+
export declare function isHookInstalled(file?: HooksFile): boolean;
|
|
40
|
+
export declare function installHook(opts?: InstallOptions): HooksFile;
|
|
41
|
+
export declare function removeHook(): {
|
|
42
|
+
removed: number;
|
|
43
|
+
file: HooksFile;
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,eAAO,MAAM,cAAc,4BAA4B,CAAC;AAExD,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,yDAAyD;AACzD,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE;QACN,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;QAC9B,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,EAAE,GAAG,SAAS,CAAC;KAC/C,CAAC;IACF,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,wBAAgB,SAAS,CAAC,IAAI,SAAkB,GAAG,SAAS,CAS3D;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,SAAkB,GAAG,IAAI,CAMxE;AAED,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAID,wBAAgB,eAAe,CAAC,IAAI,GAAE,SAAuB,GAAG,OAAO,CAEtE;AAED,wBAAgB,WAAW,CAAC,IAAI,GAAE,cAAmB,GAAG,SAAS,CAWhE;AAED,wBAAgB,UAAU,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,CAWjE"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manage $CODEX_HOME/hooks.json (default ~/.codex/hooks.json) — install,
|
|
3
|
+
* remove, inspect the WARD hook.
|
|
4
|
+
*
|
|
5
|
+
* Safety rules:
|
|
6
|
+
* - Back up hooks.json before changing it, and write atomically
|
|
7
|
+
* - Idempotent: init twice leaves one entry
|
|
8
|
+
* - Our entry is found by its statusMessage; other hooks are untouched
|
|
9
|
+
*
|
|
10
|
+
* Codex skips new or changed hooks until they are trusted: after init, run
|
|
11
|
+
* /hooks in Codex and trust the Weave hook.
|
|
12
|
+
*/
|
|
13
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, renameSync, copyFileSync } from 'node:fs';
|
|
14
|
+
import { dirname, join, resolve } from 'node:path';
|
|
15
|
+
import { homedir } from 'node:os';
|
|
16
|
+
export const STATUS_MESSAGE = 'Weave: checking WARD.md';
|
|
17
|
+
export function codexHome() {
|
|
18
|
+
return process.env.CODEX_HOME ? resolve(process.env.CODEX_HOME) : join(homedir(), '.codex');
|
|
19
|
+
}
|
|
20
|
+
export function hooksJsonPath() {
|
|
21
|
+
return join(codexHome(), 'hooks.json');
|
|
22
|
+
}
|
|
23
|
+
/** User-global WARD.md, used when a project has none. */
|
|
24
|
+
export function userWardPath() {
|
|
25
|
+
return join(codexHome(), 'WARD.md');
|
|
26
|
+
}
|
|
27
|
+
export function readHooks(path = hooksJsonPath()) {
|
|
28
|
+
if (!existsSync(path))
|
|
29
|
+
return {};
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
throw new Error(`Failed to parse ${path}; fix the JSON or move it aside and re-run. ${err instanceof Error ? err.message : String(err)}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function writeHooks(file, path = hooksJsonPath()) {
|
|
38
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
39
|
+
if (existsSync(path))
|
|
40
|
+
copyFileSync(path, `${path}.weave-backup`);
|
|
41
|
+
const tmp = `${path}.tmp`;
|
|
42
|
+
writeFileSync(tmp, JSON.stringify(file, null, 2) + '\n', 'utf8');
|
|
43
|
+
renameSync(tmp, path);
|
|
44
|
+
}
|
|
45
|
+
const ours = (g) => g.hooks?.some((h) => h.statusMessage === STATUS_MESSAGE);
|
|
46
|
+
export function isHookInstalled(file = readHooks()) {
|
|
47
|
+
return (file.hooks?.PreToolUse ?? []).some(ours);
|
|
48
|
+
}
|
|
49
|
+
export function installHook(opts = {}) {
|
|
50
|
+
const file = readHooks();
|
|
51
|
+
const command = `${opts.binary ?? 'weave-ward-codex'} hook pre-tool-use${opts.failClosed ? ' --fail-closed' : ''}`;
|
|
52
|
+
const group = {
|
|
53
|
+
matcher: opts.matcher ?? '*',
|
|
54
|
+
hooks: [{ type: 'command', command, timeout: opts.timeoutSeconds ?? 10, statusMessage: STATUS_MESSAGE }],
|
|
55
|
+
};
|
|
56
|
+
const hooks = (file.hooks ??= {});
|
|
57
|
+
hooks.PreToolUse = [...(hooks.PreToolUse ?? []).filter((g) => !ours(g)), group];
|
|
58
|
+
writeHooks(file);
|
|
59
|
+
return file;
|
|
60
|
+
}
|
|
61
|
+
export function removeHook() {
|
|
62
|
+
const file = readHooks();
|
|
63
|
+
const before = file.hooks?.PreToolUse ?? [];
|
|
64
|
+
const after = before.filter((g) => !ours(g));
|
|
65
|
+
const removed = before.length - after.length;
|
|
66
|
+
if (removed > 0 && file.hooks) {
|
|
67
|
+
if (after.length)
|
|
68
|
+
file.hooks.PreToolUse = after;
|
|
69
|
+
else
|
|
70
|
+
delete file.hooks.PreToolUse;
|
|
71
|
+
writeHooks(file);
|
|
72
|
+
}
|
|
73
|
+
return { removed, file };
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/hook.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PreToolUse hook handler: reads Codex's payload from stdin, finds the
|
|
3
|
+
* active WARD.md, decides with Ward's shared evaluator, and prints a deny or
|
|
4
|
+
* nothing.
|
|
5
|
+
*
|
|
6
|
+
* WARD.md resolution (cwd = the payload's cwd):
|
|
7
|
+
* 1. $WEAVE_WARD_PATH
|
|
8
|
+
* 2. <cwd>/WARD.md
|
|
9
|
+
* 3. <cwd>/.codex/WARD.md
|
|
10
|
+
* 4. <cwd>/.weave/WARD.md
|
|
11
|
+
* 5. $CODEX_HOME/WARD.md (default ~/.codex/WARD.md)
|
|
12
|
+
*
|
|
13
|
+
* Failure modes:
|
|
14
|
+
* - A WARD.md that exists but is invalid always denies: a typo must not
|
|
15
|
+
* silently switch enforcement off.
|
|
16
|
+
* - Malformed payloads and evaluator errors allow by default (with a note
|
|
17
|
+
* on stderr); --fail-closed denies instead.
|
|
18
|
+
*/
|
|
19
|
+
import { type WardPolicy } from '@weave_protocol/ward';
|
|
20
|
+
import { type CodexHookOutput } from './types.js';
|
|
21
|
+
export interface ResolvedWard {
|
|
22
|
+
policy: WardPolicy;
|
|
23
|
+
source: string;
|
|
24
|
+
}
|
|
25
|
+
export interface HookDecision {
|
|
26
|
+
decision: 'allow' | 'deny' | 'require_approval';
|
|
27
|
+
reasons: string[];
|
|
28
|
+
}
|
|
29
|
+
export declare function resolveWardForCwd(cwd: string): ResolvedWard | null;
|
|
30
|
+
/** Decide a Codex tool call against a WARD policy. */
|
|
31
|
+
export declare function evaluateCall(policy: WardPolicy, toolName: string, toolInput: unknown, cwd?: string): HookDecision;
|
|
32
|
+
/** WARD decision → Codex output; undefined means print nothing (continue). */
|
|
33
|
+
export declare function toHookOutput(result: HookDecision, source: string): CodexHookOutput | undefined;
|
|
34
|
+
export declare function runPreToolUseHook(failClosed: boolean): Promise<never>;
|
|
35
|
+
//# sourceMappingURL=hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAAsC,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAsC,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAItF,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,kBAAkB,CAAC;IAChD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAmBlE;AAID,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,GAAE,MAAsB,GAAG,YAAY,CA0BhI;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAM9F;AAmBD,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAoC3E"}
|
package/dist/hook.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PreToolUse hook handler: reads Codex's payload from stdin, finds the
|
|
3
|
+
* active WARD.md, decides with Ward's shared evaluator, and prints a deny or
|
|
4
|
+
* nothing.
|
|
5
|
+
*
|
|
6
|
+
* WARD.md resolution (cwd = the payload's cwd):
|
|
7
|
+
* 1. $WEAVE_WARD_PATH
|
|
8
|
+
* 2. <cwd>/WARD.md
|
|
9
|
+
* 3. <cwd>/.codex/WARD.md
|
|
10
|
+
* 4. <cwd>/.weave/WARD.md
|
|
11
|
+
* 5. $CODEX_HOME/WARD.md (default ~/.codex/WARD.md)
|
|
12
|
+
*
|
|
13
|
+
* Failure modes:
|
|
14
|
+
* - A WARD.md that exists but is invalid always denies: a typo must not
|
|
15
|
+
* silently switch enforcement off.
|
|
16
|
+
* - Malformed payloads and evaluator errors allow by default (with a note
|
|
17
|
+
* on stderr); --fail-closed denies instead.
|
|
18
|
+
*/
|
|
19
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
20
|
+
import { join, resolve } from 'node:path';
|
|
21
|
+
import { parseAndValidate, evaluateToolCall } from '@weave_protocol/ward';
|
|
22
|
+
import { TOOL_MAPPINGS } from './types.js';
|
|
23
|
+
import { patchTargets } from './patch.js';
|
|
24
|
+
import { userWardPath } from './config.js';
|
|
25
|
+
export function resolveWardForCwd(cwd) {
|
|
26
|
+
const candidates = [
|
|
27
|
+
process.env.WEAVE_WARD_PATH,
|
|
28
|
+
cwd && join(cwd, 'WARD.md'),
|
|
29
|
+
cwd && join(cwd, '.codex', 'WARD.md'),
|
|
30
|
+
cwd && join(cwd, '.weave', 'WARD.md'),
|
|
31
|
+
userWardPath(),
|
|
32
|
+
].filter((p) => !!p);
|
|
33
|
+
for (const path of candidates) {
|
|
34
|
+
const full = resolve(path);
|
|
35
|
+
if (!existsSync(full))
|
|
36
|
+
continue;
|
|
37
|
+
const result = parseAndValidate(readFileSync(full, 'utf8'));
|
|
38
|
+
if (!result.valid || !result.policy) {
|
|
39
|
+
throw new Error(`Invalid WARD.md at ${full}: ${result.errors.map((e) => e.message).join('; ')}`);
|
|
40
|
+
}
|
|
41
|
+
return { policy: result.policy, source: full };
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const RANK = { allow: 0, require_approval: 1, deny: 2 };
|
|
46
|
+
/** Decide a Codex tool call against a WARD policy. */
|
|
47
|
+
export function evaluateCall(policy, toolName, toolInput, cwd = process.cwd()) {
|
|
48
|
+
const input = toolInput && typeof toolInput === 'object' && !Array.isArray(toolInput)
|
|
49
|
+
? toolInput
|
|
50
|
+
: { command: toolInput };
|
|
51
|
+
const opts = { mappings: TOOL_MAPPINGS, cwd };
|
|
52
|
+
// apply_patch: the files the patch writes and deletes, not its text
|
|
53
|
+
if (toolName === 'apply_patch') {
|
|
54
|
+
const { writes, deletes } = patchTargets(String(input.command ?? ''));
|
|
55
|
+
const results = [
|
|
56
|
+
evaluateToolCall(policy, 'apply_patch', { target: writes }, {
|
|
57
|
+
...opts, mappings: { apply_patch: { capability: 'file_write', pathField: 'target', fsOp: 'write' } },
|
|
58
|
+
}),
|
|
59
|
+
...(deletes.length
|
|
60
|
+
? [evaluateToolCall(policy, 'apply_patch', { target: deletes }, {
|
|
61
|
+
...opts, mappings: { apply_patch: { capability: 'file_write', pathField: 'target', fsOp: 'delete' } },
|
|
62
|
+
})]
|
|
63
|
+
: []),
|
|
64
|
+
];
|
|
65
|
+
const worst = results.reduce((a, b) => (RANK[b.decision] > RANK[a.decision] ? b : a));
|
|
66
|
+
return { decision: worst.decision, reasons: results.flatMap((r) => r.reasons) };
|
|
67
|
+
}
|
|
68
|
+
const { decision, reasons } = evaluateToolCall(policy, toolName, input, opts);
|
|
69
|
+
return { decision, reasons };
|
|
70
|
+
}
|
|
71
|
+
/** WARD decision → Codex output; undefined means print nothing (continue). */
|
|
72
|
+
export function toHookOutput(result, source) {
|
|
73
|
+
if (result.decision === 'allow')
|
|
74
|
+
return undefined;
|
|
75
|
+
const reason = result.decision === 'deny'
|
|
76
|
+
? `WARD: ${result.reasons.join(' | ')} (policy: ${source})`
|
|
77
|
+
: `WARD requires approval before this call: ${result.reasons.join(' | ')} (policy: ${source}). Ask the user to approve it or update WARD.md.`;
|
|
78
|
+
return { hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason } };
|
|
79
|
+
}
|
|
80
|
+
async function readStdin() {
|
|
81
|
+
if (process.stdin.isTTY)
|
|
82
|
+
return '';
|
|
83
|
+
let data = '';
|
|
84
|
+
process.stdin.setEncoding('utf8');
|
|
85
|
+
for await (const chunk of process.stdin)
|
|
86
|
+
data += chunk;
|
|
87
|
+
return data;
|
|
88
|
+
}
|
|
89
|
+
function emit(output) {
|
|
90
|
+
if (output)
|
|
91
|
+
process.stdout.write(JSON.stringify(output));
|
|
92
|
+
process.exit(0);
|
|
93
|
+
}
|
|
94
|
+
const denyWith = (reason) => ({
|
|
95
|
+
hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason },
|
|
96
|
+
});
|
|
97
|
+
export async function runPreToolUseHook(failClosed) {
|
|
98
|
+
const raw = await readStdin();
|
|
99
|
+
if (!raw.trim())
|
|
100
|
+
emit();
|
|
101
|
+
let payload;
|
|
102
|
+
try {
|
|
103
|
+
payload = JSON.parse(raw);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
if (failClosed)
|
|
107
|
+
emit(denyWith('WARD hook: malformed payload from Codex'));
|
|
108
|
+
process.stderr.write('weave-ward-codex: malformed hook payload, allowing\n');
|
|
109
|
+
emit();
|
|
110
|
+
}
|
|
111
|
+
if (!payload.tool_name)
|
|
112
|
+
emit();
|
|
113
|
+
const cwd = payload.cwd || process.cwd();
|
|
114
|
+
let resolved;
|
|
115
|
+
try {
|
|
116
|
+
resolved = resolveWardForCwd(cwd);
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
// A policy exists but can't be used: deny rather than run unprotected.
|
|
120
|
+
emit(denyWith(`WARD policy could not be loaded: ${err instanceof Error ? err.message : String(err)}. Fix WARD.md to continue.`));
|
|
121
|
+
}
|
|
122
|
+
if (!resolved)
|
|
123
|
+
emit();
|
|
124
|
+
let result;
|
|
125
|
+
try {
|
|
126
|
+
result = evaluateCall(resolved.policy, payload.tool_name, payload.tool_input, cwd);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
130
|
+
if (failClosed)
|
|
131
|
+
emit(denyWith(`WARD evaluation failed: ${msg}`));
|
|
132
|
+
process.stderr.write(`weave-ward-codex: WARD evaluation failed (${msg}), allowing\n`);
|
|
133
|
+
emit();
|
|
134
|
+
}
|
|
135
|
+
emit(toHookOutput(result, resolved.source));
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=hook.js.map
|
package/dist/hook.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @weave_protocol/adapter-codex — WARD.md enforcement for OpenAI Codex CLI.
|
|
3
|
+
*/
|
|
4
|
+
export * from './types.js';
|
|
5
|
+
export { patchTargets } from './patch.js';
|
|
6
|
+
export type { PatchTargets } from './patch.js';
|
|
7
|
+
export { STATUS_MESSAGE, codexHome, hooksJsonPath, userWardPath, readHooks, writeHooks, installHook, removeHook, isHookInstalled, } from './config.js';
|
|
8
|
+
export type { HooksFile, InstallOptions } from './config.js';
|
|
9
|
+
export { resolveWardForCwd, evaluateCall, toHookOutput } from './hook.js';
|
|
10
|
+
export type { ResolvedWard, HookDecision } from './hook.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EACL,cAAc,EACd,SAAS,EACT,aAAa,EACb,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,EACX,UAAU,EACV,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC1E,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @weave_protocol/adapter-codex — WARD.md enforcement for OpenAI Codex CLI.
|
|
3
|
+
*/
|
|
4
|
+
export * from './types.js';
|
|
5
|
+
export { patchTargets } from './patch.js';
|
|
6
|
+
export { STATUS_MESSAGE, codexHome, hooksJsonPath, userWardPath, readHooks, writeHooks, installHook, removeHook, isHookInstalled, } from './config.js';
|
|
7
|
+
export { resolveWardForCwd, evaluateCall, toHookOutput } from './hook.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EACL,cAAc,EACd,SAAS,EACT,aAAa,EACb,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,EACX,UAAU,EACV,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/patch.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The files a Codex apply_patch touches. The patch format marks each file:
|
|
3
|
+
*
|
|
4
|
+
* *** Add File: <path> new file → write
|
|
5
|
+
* *** Update File: <path> edit in place → write
|
|
6
|
+
* *** Move to: <path> rename target → write
|
|
7
|
+
* *** Delete File: <path> removal → delete
|
|
8
|
+
*
|
|
9
|
+
* Paths are relative to the session cwd unless absolute.
|
|
10
|
+
*/
|
|
11
|
+
export interface PatchTargets {
|
|
12
|
+
writes: string[];
|
|
13
|
+
deletes: string[];
|
|
14
|
+
}
|
|
15
|
+
export declare function patchTargets(patch: string): PatchTargets;
|
|
16
|
+
//# sourceMappingURL=patch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patch.d.ts","sourceRoot":"","sources":["../src/patch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAID,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CASxD"}
|
package/dist/patch.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The files a Codex apply_patch touches. The patch format marks each file:
|
|
3
|
+
*
|
|
4
|
+
* *** Add File: <path> new file → write
|
|
5
|
+
* *** Update File: <path> edit in place → write
|
|
6
|
+
* *** Move to: <path> rename target → write
|
|
7
|
+
* *** Delete File: <path> removal → delete
|
|
8
|
+
*
|
|
9
|
+
* Paths are relative to the session cwd unless absolute.
|
|
10
|
+
*/
|
|
11
|
+
const MARKER = /^\*\*\* (Add File|Update File|Move to|Delete File):\s*(.+?)\s*$/;
|
|
12
|
+
export function patchTargets(patch) {
|
|
13
|
+
const writes = [];
|
|
14
|
+
const deletes = [];
|
|
15
|
+
for (const line of patch.split(/\r?\n/)) {
|
|
16
|
+
const m = MARKER.exec(line);
|
|
17
|
+
if (!m)
|
|
18
|
+
continue;
|
|
19
|
+
(m[1] === 'Delete File' ? deletes : writes).push(m[2]);
|
|
20
|
+
}
|
|
21
|
+
return { writes, deletes };
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=patch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patch.js","sourceRoot":"","sources":["../src/patch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,MAAM,MAAM,GAAG,iEAAiE,CAAC;AAEjF,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex CLI hook contract (https://developers.openai.com/codex/hooks):
|
|
3
|
+
*
|
|
4
|
+
* stdin { session_id, transcript_path, cwd, hook_event_name, model,
|
|
5
|
+
* turn_id, tool_name, tool_use_id, tool_input, permission_mode }
|
|
6
|
+
* stdout { hookSpecificOutput: { hookEventName: "PreToolUse",
|
|
7
|
+
* permissionDecision: "deny", permissionDecisionReason } }
|
|
8
|
+
* or nothing (the call continues)
|
|
9
|
+
*
|
|
10
|
+
* Shell commands (including unified exec) arrive as tool_name "Bash" with
|
|
11
|
+
* tool_input.command; file edits as "apply_patch" with the patch text in
|
|
12
|
+
* tool_input.command; MCP tools as mcp__<server>__<tool>. "ask" is not
|
|
13
|
+
* supported, so a WARD require_approval is a deny whose reason says so.
|
|
14
|
+
* Hosted tools (web search) never reach PreToolUse.
|
|
15
|
+
*/
|
|
16
|
+
import type { ToolMapping } from '@weave_protocol/ward';
|
|
17
|
+
export interface CodexHookInput {
|
|
18
|
+
session_id?: string;
|
|
19
|
+
transcript_path?: string | null;
|
|
20
|
+
cwd?: string;
|
|
21
|
+
hook_event_name?: string;
|
|
22
|
+
model?: string;
|
|
23
|
+
turn_id?: string;
|
|
24
|
+
tool_name?: string;
|
|
25
|
+
tool_use_id?: string;
|
|
26
|
+
tool_input?: unknown;
|
|
27
|
+
permission_mode?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface CodexHookOutput {
|
|
30
|
+
hookSpecificOutput?: {
|
|
31
|
+
hookEventName: 'PreToolUse';
|
|
32
|
+
permissionDecision: 'deny';
|
|
33
|
+
permissionDecisionReason: string;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Codex's local tools. apply_patch is decided from the files its patch
|
|
38
|
+
* touches (see patch.ts); unknown tools, including MCP tools, use their own
|
|
39
|
+
* name as the capability and Ward checks their path and URL arguments.
|
|
40
|
+
*/
|
|
41
|
+
export declare const TOOL_MAPPINGS: Record<string, ToolMapping>;
|
|
42
|
+
/** One PreToolUse matcher group in hooks.json. */
|
|
43
|
+
export interface CodexHookGroup {
|
|
44
|
+
matcher?: string;
|
|
45
|
+
hooks: Array<{
|
|
46
|
+
type: 'command' | 'mcp_tool';
|
|
47
|
+
command?: string;
|
|
48
|
+
timeout?: number;
|
|
49
|
+
statusMessage?: string;
|
|
50
|
+
async?: boolean;
|
|
51
|
+
}>;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,kBAAkB,CAAC,EAAE;QACnB,aAAa,EAAE,YAAY,CAAC;QAC5B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,wBAAwB,EAAE,MAAM,CAAC;KAClC,CAAC;CACH;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAMrD,CAAC;AAEF,kDAAkD;AAClD,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,SAAS,GAAG,UAAU,CAAC;QAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC,CAAC;CACJ"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex CLI hook contract (https://developers.openai.com/codex/hooks):
|
|
3
|
+
*
|
|
4
|
+
* stdin { session_id, transcript_path, cwd, hook_event_name, model,
|
|
5
|
+
* turn_id, tool_name, tool_use_id, tool_input, permission_mode }
|
|
6
|
+
* stdout { hookSpecificOutput: { hookEventName: "PreToolUse",
|
|
7
|
+
* permissionDecision: "deny", permissionDecisionReason } }
|
|
8
|
+
* or nothing (the call continues)
|
|
9
|
+
*
|
|
10
|
+
* Shell commands (including unified exec) arrive as tool_name "Bash" with
|
|
11
|
+
* tool_input.command; file edits as "apply_patch" with the patch text in
|
|
12
|
+
* tool_input.command; MCP tools as mcp__<server>__<tool>. "ask" is not
|
|
13
|
+
* supported, so a WARD require_approval is a deny whose reason says so.
|
|
14
|
+
* Hosted tools (web search) never reach PreToolUse.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Codex's local tools. apply_patch is decided from the files its patch
|
|
18
|
+
* touches (see patch.ts); unknown tools, including MCP tools, use their own
|
|
19
|
+
* name as the capability and Ward checks their path and URL arguments.
|
|
20
|
+
*/
|
|
21
|
+
export const TOOL_MAPPINGS = {
|
|
22
|
+
Bash: { capability: 'shell_exec', commandField: 'command' },
|
|
23
|
+
apply_patch: { capability: 'file_write' },
|
|
24
|
+
view_image: { capability: 'file_read', pathField: 'path', fsOp: 'read' },
|
|
25
|
+
update_plan: { capability: 'task_planning' },
|
|
26
|
+
spawn_agent: { capability: 'subagent' },
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAyBH;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAgC;IACxD,IAAI,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE;IAC3D,WAAW,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE;IACzC,UAAU,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;IACxE,WAAW,EAAE,EAAE,UAAU,EAAE,eAAe,EAAE;IAC5C,WAAW,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE;CACxC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weave_protocol/adapter-codex",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Weave Protocol adapter for OpenAI Codex CLI - enforces WARD.md policies via Codex's PreToolUse hook",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"weave-ward-codex": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"test": "npm run build && node --test test/*.test.mjs",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"weave-protocol",
|
|
19
|
+
"ward",
|
|
20
|
+
"codex",
|
|
21
|
+
"codex-cli",
|
|
22
|
+
"openai",
|
|
23
|
+
"agent-security",
|
|
24
|
+
"ai-security",
|
|
25
|
+
"hooks",
|
|
26
|
+
"harness-adapter",
|
|
27
|
+
"policy-enforcement",
|
|
28
|
+
"ward-md"
|
|
29
|
+
],
|
|
30
|
+
"author": "Trent Yoxall",
|
|
31
|
+
"license": "Apache-2.0",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/Tyox-all/Weave_Protocol.git",
|
|
35
|
+
"directory": "adapter-codex"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/Tyox-all/Weave_Protocol/tree/main/adapter-codex#readme",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/Tyox-all/Weave_Protocol/issues"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@weave_protocol/ward": "^0.3.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^26.6.6",
|
|
46
|
+
"typescript": "^7.0.2"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18.0.0"
|
|
50
|
+
},
|
|
51
|
+
"files": [
|
|
52
|
+
"dist/",
|
|
53
|
+
"README.md"
|
|
54
|
+
]
|
|
55
|
+
}
|