@weave_protocol/adapter-claudecode 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 ADDED
@@ -0,0 +1,254 @@
1
+ # 🛡️ @weave_protocol/adapter-claudecode
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@weave_protocol/adapter-claudecode.svg)](https://www.npmjs.com/package/@weave_protocol/adapter-claudecode)
4
+ [![npm](https://img.shields.io/npm/dm/@weave_protocol/adapter-claudecode.svg)](https://www.npmjs.com/package/@weave_protocol/adapter-claudecode)
5
+ [![license](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
6
+
7
+ **WARD.md enforcement for Claude Code, via Claude Code's native hook system.**
8
+
9
+ > *AGENTS.md tells your agent what to do. SKILL.md tells your agent how to do it. **WARD.md tells your agent what it can't.** This package makes Claude Code listen.*
10
+
11
+ Part of the [Weave Protocol](https://github.com/Tyox-all/Weave_Protocol) security suite. First in a planned series of cross-platform harness adapters (Claude Code → Antigravity → MDASH).
12
+
13
+ ---
14
+
15
+ ## What it does
16
+
17
+ When Claude Code is about to use a tool (Bash, Edit, Write, Read, WebFetch, etc.), this adapter intercepts via Claude Code's `PreToolUse` hook, reads your project's `WARD.md`, and blocks the call if it violates the declared policy.
18
+
19
+ ```
20
+ You: "Delete all the SSH keys"
21
+ Claude Code: [about to run Bash with `rm -rf ~/.ssh`]
22
+ ↓
23
+ PreToolUse hook fires
24
+ ↓
25
+ weave-claude-code reads ./WARD.md
26
+ ↓
27
+ checkFilesystem('delete', '~/.ssh/**') → DENY
28
+ ↓
29
+ Returns { "decision": "block", "reason": "🛡️ WARD: ..." }
30
+ ↓
31
+ Claude Code refuses, shows reason
32
+ ```
33
+
34
+ No code changes needed in your project. Just a `WARD.md` file and a one-time hook install.
35
+
36
+ ---
37
+
38
+ ## Quick start
39
+
40
+ ```bash
41
+ # Install once
42
+ npm install -g @weave_protocol/adapter-claudecode
43
+
44
+ # Wire it into Claude Code's hook config
45
+ weave-claude-code init
46
+
47
+ # Drop a WARD.md in your project root
48
+ npx @weave_protocol/ward init
49
+
50
+ # Done. Open Claude Code in that project — every tool call is now gated by WARD.
51
+ ```
52
+
53
+ Verify with:
54
+
55
+ ```bash
56
+ weave-claude-code status
57
+ ```
58
+
59
+ ---
60
+
61
+ ## How WARD.md is resolved
62
+
63
+ When the hook fires, it looks for a WARD.md in this order:
64
+
65
+ 1. `$WEAVE_WARD_PATH` — explicit env var override
66
+ 2. `<project>/WARD.md` — project-level (CWD from the hook payload)
67
+ 3. `<project>/.weave/WARD.md` — alternate project location
68
+ 4. `~/.claude/WARD.md` — **user-global fallback** (applies to every Claude Code session)
69
+
70
+ The first one that exists wins. If none exists, the hook silently passes through — zero impact on workflows that haven't adopted WARD yet.
71
+
72
+ ---
73
+
74
+ ## Tool mapping
75
+
76
+ Claude Code's tools are mapped to generic capability names so a single WARD.md works across platforms:
77
+
78
+ | Claude Code tool | WARD capability | Path arg | Implicit fs op |
79
+ |---|---|---|---|
80
+ | `Bash` | `shell_exec` | (heuristic scan of command) | varies |
81
+ | `Edit` / `MultiEdit` / `Write` | `file_write` | `file_path` | `write` |
82
+ | `Read` | `file_read` | `file_path` | `read` |
83
+ | `Grep` / `LS` | `file_read` / `file_list` | `path` | `read` / `list` |
84
+ | `Glob` | `file_list` | `path` | `list` |
85
+ | `WebFetch` | `http_request` | (uses `url`) | — |
86
+ | `WebSearch` | `web_search` | — | — |
87
+ | `Task` | `subagent` | — | — |
88
+ | `TodoWrite` | `todo_write` | — | — |
89
+ | `NotebookEdit` | `notebook_edit` | `notebook_path` | `write` |
90
+
91
+ Your WARD.md can use either name — `Bash` or `shell_exec`, `Edit` or `file_write`. The stricter rule wins.
92
+
93
+ For `Bash`, the adapter also runs a light heuristic scan of the command string to catch obvious violations (URLs to denied domains, references to sensitive paths like `~/.ssh`, `~/.aws`, `/etc/`).
94
+
95
+ ---
96
+
97
+ ## Commands
98
+
99
+ ```bash
100
+ weave-claude-code init [--matcher=X] [--fail-closed]
101
+ Install the WARD pre-tool-use hook.
102
+ --matcher=Bash|Edit|... Restrict to specific tools (default: all)
103
+ --fail-closed Block on policy errors (default: fail-open)
104
+
105
+ weave-claude-code disable
106
+ Remove the WARD hook from ~/.claude/settings.json
107
+ (your other hooks are not touched)
108
+
109
+ weave-claude-code status
110
+ Show hook installation state + active WARD policy for current dir
111
+
112
+ weave-claude-code test <tool> [--input=JSON]
113
+ Dry-run a tool call against your WARD.md without invoking Claude Code
114
+
115
+ weave-claude-code help
116
+ ```
117
+
118
+ ### Examples
119
+
120
+ Test whether `rm -rf ~/.ssh` would be allowed:
121
+
122
+ ```bash
123
+ weave-claude-code test Bash --input='{"command":"rm -rf ~/.ssh"}'
124
+ ```
125
+
126
+ Test a file write to /etc/:
127
+
128
+ ```bash
129
+ weave-claude-code test Write --input='{"file_path":"/etc/passwd","content":"..."}'
130
+ ```
131
+
132
+ Test a fetch to a disallowed domain:
133
+
134
+ ```bash
135
+ weave-claude-code test WebFetch --input='{"url":"https://evil.example.com/exfil"}'
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Fail-open vs fail-closed
141
+
142
+ By default, the hook is **fail-open**: if WARD.md is missing, malformed, or evaluation throws, the tool call is **allowed** and a warning is written to stderr. This is the right default for adoption — broken policy files shouldn't break your workflow.
143
+
144
+ For higher-stakes contexts, install with `--fail-closed`:
145
+
146
+ ```bash
147
+ weave-claude-code init --fail-closed
148
+ ```
149
+
150
+ Then a missing or broken policy blocks the call.
151
+
152
+ ---
153
+
154
+ ## What gets installed
155
+
156
+ `weave-claude-code init` adds an entry to `~/.claude/settings.json`:
157
+
158
+ ```json
159
+ {
160
+ "hooks": {
161
+ "PreToolUse": [
162
+ {
163
+ "matcher": "*",
164
+ "hooks": [
165
+ {
166
+ "type": "command",
167
+ "command": "weave-claude-code hook pre-tool-use # WEAVE_WARD_HOOK",
168
+ "timeout": 5
169
+ }
170
+ ]
171
+ }
172
+ ]
173
+ }
174
+ }
175
+ ```
176
+
177
+ The `# WEAVE_WARD_HOOK` marker is how `disable` finds and removes only our entry without affecting other hooks you've added manually.
178
+
179
+ A backup of your existing `settings.json` is written to `settings.json.weave-backup` before any modification.
180
+
181
+ ---
182
+
183
+ ## A sample WARD.md for Claude Code
184
+
185
+ ```markdown
186
+ ---
187
+ ward: "1.0"
188
+ agent: my-coding-agent
189
+ ---
190
+
191
+ # WARD.md
192
+
193
+ ## Filesystem
194
+
195
+ allow:
196
+ - read: /Users/me/projects/**
197
+ - write: /Users/me/projects/**
198
+ deny:
199
+ - read: ~/.ssh/**
200
+ - read: ~/.aws/**
201
+ - write: /etc/**
202
+ default: deny
203
+
204
+ ## Network
205
+
206
+ allow:
207
+ - url: "https://api.github.com/**"
208
+ - url: "https://registry.npmjs.org/**"
209
+ default: deny
210
+
211
+ ## Capabilities
212
+
213
+ allow:
214
+ - file_read
215
+ - file_write
216
+ - file_list
217
+ requireApproval:
218
+ - shell_exec
219
+ - http_request
220
+ deny:
221
+ - subagent
222
+ default: deny
223
+
224
+ ## Behavioral Limits
225
+
226
+ maxIterations: 50
227
+ maxCostUSD: 10.00
228
+ ```
229
+
230
+ With this loaded, Claude Code is allowed to read/write inside `~/projects` but cannot touch SSH/AWS keys, will require approval before running shell commands, and is hard-blocked from spawning subagents.
231
+
232
+ ---
233
+
234
+ ## Programmatic use
235
+
236
+ ```typescript
237
+ import {
238
+ resolveWardForCwd,
239
+ evaluateCall,
240
+ installHook,
241
+ } from '@weave_protocol/adapter-claudecode';
242
+
243
+ const resolved = resolveWardForCwd(process.cwd());
244
+ if (resolved) {
245
+ const decision = evaluateCall(resolved.policy, 'Bash', { command: 'rm -rf /' });
246
+ console.log(decision.decision); // "deny"
247
+ }
248
+ ```
249
+
250
+ ---
251
+
252
+ ## License
253
+
254
+ Apache 2.0 — see [LICENSE](../LICENSE).
package/SKILL.md ADDED
@@ -0,0 +1,83 @@
1
+ ---
2
+ name: adapter-claudecode
3
+ description: Use this skill when the user wants to enforce a WARD.md security policy inside Claude Code via its native hook system. Triggers on requests to "secure my Claude Code session", "block Claude Code from doing X", "install WARD hooks in Claude Code", "make Claude Code respect my policy file", or any work involving the `weave-claude-code` command. Also useful when reviewing a user's `~/.claude/settings.json` for hook configuration, or when a user reports that Claude Code is doing things they want stopped.
4
+ ---
5
+
6
+ # Claude Code adapter for Weave Protocol
7
+
8
+ The `@weave_protocol/adapter-claudecode` package enforces [WARD.md](https://www.npmjs.com/package/@weave_protocol/ward) policies inside Claude Code via the `PreToolUse` hook system. When Claude Code is about to use a tool, the adapter reads the active WARD.md and blocks the call if it violates the policy.
9
+
10
+ ## When to use
11
+
12
+ - User runs Claude Code and wants visibility/control over what it does
13
+ - User has a WARD.md and wants it enforced inside Claude Code (not just on MCP servers)
14
+ - User wants to lock down a sensitive project so Claude Code can't escape its bounds
15
+ - User has a global `~/.claude/WARD.md` they want applied to every session
16
+ - User wants to test what their WARD policy would do before deploying it
17
+
18
+ ## Commands
19
+
20
+ ```bash
21
+ weave-claude-code init [--matcher=X] [--fail-closed] # Install hook
22
+ weave-claude-code disable # Remove hook
23
+ weave-claude-code status # Show config + active policy
24
+ weave-claude-code test <tool> [--input=JSON] # Dry-run a tool call
25
+ weave-claude-code help
26
+ ```
27
+
28
+ ## WARD resolution order
29
+
30
+ When the hook fires:
31
+
32
+ 1. `$WEAVE_WARD_PATH` — explicit override
33
+ 2. `<cwd>/WARD.md` — project root
34
+ 3. `<cwd>/.weave/WARD.md` — alternate location
35
+ 4. `~/.claude/WARD.md` — user-global fallback
36
+
37
+ First match wins. If none exists, the hook passes through silently.
38
+
39
+ ## Tool mapping
40
+
41
+ Claude Code → WARD capability:
42
+
43
+ - `Bash` → `shell_exec` (also scans command string heuristically)
44
+ - `Edit`, `MultiEdit`, `Write` → `file_write`
45
+ - `Read` → `file_read`
46
+ - `Grep`, `LS`, `Glob` → `file_read` / `file_list`
47
+ - `WebFetch` → `http_request` (checks `url`)
48
+ - `WebSearch` → `web_search`
49
+ - `Task` → `subagent`
50
+ - `NotebookEdit` → `notebook_edit`
51
+
52
+ WARD.md can use either the literal Claude tool name (e.g., `Bash`) or the generic capability (`shell_exec`). The stricter rule wins.
53
+
54
+ ## Decision rules
55
+
56
+ | Situation | Action |
57
+ |---|---|
58
+ | User wants to enforce WARD in Claude Code | `weave-claude-code init` |
59
+ | User wants to test their policy | `weave-claude-code test <tool>` |
60
+ | User wants global policy across all projects | Write `~/.claude/WARD.md` |
61
+ | User wants project-specific policy | Write `<project>/WARD.md` |
62
+ | User wants stricter failure mode | `init --fail-closed` |
63
+ | User wants to uninstall | `weave-claude-code disable` |
64
+ | User reports Claude Code blocked unexpectedly | `weave-claude-code status` (shows active policy and source) |
65
+
66
+ ## Fail modes
67
+
68
+ - **fail-open** (default): broken or missing WARD.md → allow the call, warn to stderr
69
+ - **fail-closed** (`--fail-closed`): broken or missing WARD.md → block the call
70
+
71
+ Default is fail-open because broken policy files shouldn't break the user's workflow. Recommend fail-closed only for high-stakes environments (production deployment agents, etc.).
72
+
73
+ ## Pairs with
74
+
75
+ - `@weave_protocol/ward` — the policy format being enforced
76
+ - `@weave_protocol/hundredmen` — enforces the same WARD.md on MCP servers (complementary)
77
+ - `@weave_protocol/cli` — `weave init` scaffolds projects with a WARD.md
78
+
79
+ ## Anti-patterns
80
+
81
+ - **Don't hand-edit `~/.claude/settings.json` to add the hook.** Use `weave-claude-code init` so it backs up your config and stays idempotent.
82
+ - **Don't ship a project with `--fail-closed` and no WARD.md.** That blocks every tool call. Either ship a WARD.md or stay fail-open.
83
+ - **Don't expect WARD to catch semantic intent drift.** WARD is policy-as-code. For drift between declared intent and actual behavior, pair this with `hundredmen_declare_intent`.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * weave-claude-code CLI
4
+ *
5
+ * weave-claude-code init [--matcher=X] [--fail-closed] Install the WARD hook
6
+ * weave-claude-code disable Remove the WARD hook
7
+ * weave-claude-code status Show current config + WARD
8
+ * weave-claude-code test <tool> [--input=JSON] Dry-run a tool call
9
+ * weave-claude-code hook <event> [--fail-closed] Hook handler (called by CC)
10
+ * weave-claude-code help
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}
package/dist/cli.js ADDED
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * weave-claude-code CLI
4
+ *
5
+ * weave-claude-code init [--matcher=X] [--fail-closed] Install the WARD hook
6
+ * weave-claude-code disable Remove the WARD hook
7
+ * weave-claude-code status Show current config + WARD
8
+ * weave-claude-code test <tool> [--input=JSON] Dry-run a tool call
9
+ * weave-claude-code hook <event> [--fail-closed] Hook handler (called by CC)
10
+ * weave-claude-code help
11
+ */
12
+ import { existsSync } from 'node:fs';
13
+ import { resolve } from 'node:path';
14
+ import { installHook, removeHook, readSettings, isHookInstalled, claudeSettingsPath, claudeConfigDir, userWardPath, } from './config.js';
15
+ import { resolveWardForCwd, evaluateCall, runPreToolUseHook } from './hook.js';
16
+ // ─── ANSI colors ───────────────────────────────────────────────
17
+ const tty = process.stdout.isTTY && !process.env.NO_COLOR;
18
+ const c = {
19
+ reset: tty ? '\x1b[0m' : '',
20
+ bold: tty ? '\x1b[1m' : '',
21
+ dim: tty ? '\x1b[2m' : '',
22
+ red: tty ? '\x1b[31m' : '',
23
+ green: tty ? '\x1b[32m' : '',
24
+ yellow: tty ? '\x1b[33m' : '',
25
+ blue: tty ? '\x1b[34m' : '',
26
+ cyan: tty ? '\x1b[36m' : '',
27
+ gray: tty ? '\x1b[90m' : '',
28
+ };
29
+ function banner() {
30
+ console.error(`
31
+ ${c.cyan}${c.bold}🛡️ weave-claude-code${c.reset}
32
+ ${c.gray}WARD.md enforcement for Claude Code via hooks${c.reset}
33
+ `);
34
+ }
35
+ // ─── help ──────────────────────────────────────────────────────
36
+ function help() {
37
+ banner();
38
+ console.error(`${c.bold}Usage:${c.reset} weave-claude-code <command> [options]\n`);
39
+ console.error(`${c.bold}Commands:${c.reset}`);
40
+ console.error(` ${c.cyan}init${c.reset} ${c.gray}[--matcher=X] [--fail-closed]${c.reset} Install the WARD pre-tool-use hook`);
41
+ console.error(` ${c.cyan}disable${c.reset} Remove the WARD hook`);
42
+ console.error(` ${c.cyan}status${c.reset} Show hook installation + active WARD policy`);
43
+ console.error(` ${c.cyan}test${c.reset} ${c.gray}<tool> [--input=JSON]${c.reset} Dry-run a tool call against your WARD.md`);
44
+ console.error(` ${c.cyan}hook${c.reset} ${c.gray}<event>${c.reset} Internal: called by Claude Code as a hook`);
45
+ console.error(` ${c.cyan}help${c.reset} Show this message\n`);
46
+ console.error(`${c.bold}Examples:${c.reset}`);
47
+ console.error(` ${c.gray}$${c.reset} weave-claude-code init`);
48
+ console.error(` ${c.gray}$${c.reset} weave-claude-code status`);
49
+ console.error(` ${c.gray}$${c.reset} weave-claude-code test Bash --input='{"command":"rm -rf ~/.ssh"}'`);
50
+ console.error(` ${c.gray}$${c.reset} weave-claude-code disable\n`);
51
+ console.error(`${c.gray}Docs: https://github.com/Tyox-all/Weave_Protocol/tree/main/adapter-claudecode${c.reset}\n`);
52
+ }
53
+ // ─── init ──────────────────────────────────────────────────────
54
+ function parseFlag(args, name) {
55
+ for (const a of args) {
56
+ if (a === `--${name}`)
57
+ return '';
58
+ if (a.startsWith(`--${name}=`))
59
+ return a.slice(`--${name}=`.length);
60
+ }
61
+ return undefined;
62
+ }
63
+ function hasFlag(args, name) {
64
+ return args.some((a) => a === `--${name}` || a.startsWith(`--${name}=`));
65
+ }
66
+ function runInit(args) {
67
+ banner();
68
+ const matcher = parseFlag(args, 'matcher') || undefined;
69
+ const failClosed = hasFlag(args, 'fail-closed');
70
+ const settings = readSettings();
71
+ const wasInstalled = isHookInstalled(settings);
72
+ installHook({
73
+ toolMatcher: matcher,
74
+ failClosed,
75
+ timeoutSeconds: 5,
76
+ });
77
+ const verb = wasInstalled ? 'Updated' : 'Installed';
78
+ console.error(`${c.green}✓${c.reset} ${verb} WARD hook in ${c.cyan}${claudeSettingsPath()}${c.reset}`);
79
+ console.error(` ${c.gray}matcher:${c.reset} ${matcher || '*'}`);
80
+ console.error(` ${c.gray}fail mode:${c.reset} ${failClosed ? c.red + 'closed' + c.reset : c.green + 'open' + c.reset}`);
81
+ console.error('');
82
+ console.error(`Next:`);
83
+ console.error(` ${c.gray}1.${c.reset} Drop a ${c.cyan}WARD.md${c.reset} in your project root (or at ${c.cyan}~/.claude/WARD.md${c.reset} for a user-global policy)`);
84
+ console.error(` ${c.gray}2.${c.reset} Open Claude Code in that project — the hook will gate tool calls automatically`);
85
+ console.error(` ${c.gray}3.${c.reset} Run ${c.cyan}weave-claude-code status${c.reset} to verify`);
86
+ console.error('');
87
+ return 0;
88
+ }
89
+ // ─── disable ───────────────────────────────────────────────────
90
+ function runDisable() {
91
+ banner();
92
+ const result = removeHook();
93
+ if (result.removed === 0) {
94
+ console.error(`${c.yellow}⚠${c.reset} No WARD hooks found in ${claudeSettingsPath()}.`);
95
+ return 0;
96
+ }
97
+ console.error(`${c.green}✓${c.reset} Removed ${result.removed} WARD hook entry from ${c.cyan}${claudeSettingsPath()}${c.reset}`);
98
+ console.error(`${c.gray} (your other hooks were not touched)${c.reset}`);
99
+ return 0;
100
+ }
101
+ // ─── status ────────────────────────────────────────────────────
102
+ function runStatus() {
103
+ banner();
104
+ const settingsPath = claudeSettingsPath();
105
+ const exists = existsSync(settingsPath);
106
+ console.error(`${c.bold}Claude Code config${c.reset}`);
107
+ console.error(`${c.gray}─${c.reset}`.repeat(60));
108
+ console.error(` ${c.gray}Config dir:${c.reset} ${c.cyan}${claudeConfigDir()}${c.reset}`);
109
+ console.error(` ${c.gray}settings.json:${c.reset} ${exists ? c.green + 'present' + c.reset : c.red + 'missing' + c.reset}`);
110
+ if (exists) {
111
+ const settings = readSettings();
112
+ const installed = isHookInstalled(settings);
113
+ console.error(` ${c.gray}WARD hook:${c.reset} ${installed ? c.green + 'installed' + c.reset : c.yellow + 'not installed' + c.reset}`);
114
+ }
115
+ console.error('');
116
+ console.error(`${c.bold}Active WARD policy${c.reset}`);
117
+ console.error(`${c.gray}─${c.reset}`.repeat(60));
118
+ try {
119
+ const resolved = resolveWardForCwd(process.cwd());
120
+ if (!resolved) {
121
+ console.error(` ${c.yellow}No WARD.md found${c.reset}`);
122
+ console.error(` ${c.gray}Looked at:${c.reset}`);
123
+ if (process.env.WEAVE_WARD_PATH)
124
+ console.error(` ${c.gray}•${c.reset} ${process.env.WEAVE_WARD_PATH} ${c.gray}(WEAVE_WARD_PATH)${c.reset}`);
125
+ console.error(` ${c.gray}•${c.reset} ${resolve(process.cwd(), 'WARD.md')}`);
126
+ console.error(` ${c.gray}•${c.reset} ${resolve(process.cwd(), '.weave', 'WARD.md')}`);
127
+ console.error(` ${c.gray}•${c.reset} ${userWardPath()} ${c.gray}(user-global)${c.reset}`);
128
+ }
129
+ else {
130
+ console.error(` ${c.gray}Source:${c.reset} ${c.cyan}${resolved.source}${c.reset}`);
131
+ console.error(` ${c.gray}Name:${c.reset} ${resolved.policy.name || c.gray + '(unnamed)' + c.reset}`);
132
+ console.error(` ${c.gray}Agent:${c.reset} ${resolved.policy.agent || c.gray + '(none)' + c.reset}`);
133
+ console.error(` ${c.gray}WARD version:${c.reset} ${resolved.policy.version}`);
134
+ }
135
+ }
136
+ catch (err) {
137
+ console.error(` ${c.red}Error loading WARD.md:${c.reset} ${err instanceof Error ? err.message : String(err)}`);
138
+ return 1;
139
+ }
140
+ console.error('');
141
+ return 0;
142
+ }
143
+ // ─── test ──────────────────────────────────────────────────────
144
+ function runTest(args) {
145
+ const tool = args[0];
146
+ if (!tool) {
147
+ console.error(`${c.red}✗${c.reset} Usage: weave-claude-code test <tool> [--input='{"file_path":"..."}']`);
148
+ return 2;
149
+ }
150
+ banner();
151
+ const inputArg = parseFlag(args, 'input');
152
+ let toolInput = {};
153
+ if (inputArg) {
154
+ try {
155
+ toolInput = JSON.parse(inputArg);
156
+ }
157
+ catch {
158
+ console.error(`${c.red}✗${c.reset} --input must be valid JSON`);
159
+ return 2;
160
+ }
161
+ }
162
+ const resolved = resolveWardForCwd(process.cwd());
163
+ if (!resolved) {
164
+ console.error(`${c.yellow}⚠${c.reset} No WARD.md found — call would be allowed by default.`);
165
+ return 0;
166
+ }
167
+ console.error(`Testing ${c.bold}${tool}${c.reset}${inputArg ? ' with ' + c.cyan + JSON.stringify(toolInput) + c.reset : ''}`);
168
+ console.error(`Policy: ${c.cyan}${resolved.source}${c.reset}\n`);
169
+ const result = evaluateCall(resolved.policy, tool, toolInput);
170
+ const colorMap = {
171
+ allow: c.green,
172
+ deny: c.red,
173
+ require_approval: c.yellow,
174
+ };
175
+ const iconMap = { allow: '✓', deny: '✗', require_approval: '⚠' };
176
+ console.error(`Decision: ${colorMap[result.decision]}${iconMap[result.decision]} ${result.decision.toUpperCase()}${c.reset}`);
177
+ if (result.reasons.length > 0) {
178
+ console.error(`\nReasons:`);
179
+ for (const r of result.reasons)
180
+ console.error(` ${c.gray}•${c.reset} ${r}`);
181
+ }
182
+ console.error('');
183
+ return result.decision === 'deny' ? 1 : 0;
184
+ }
185
+ // ─── router ────────────────────────────────────────────────────
186
+ async function main() {
187
+ const [, , cmd, ...rest] = process.argv;
188
+ let code = 0;
189
+ try {
190
+ switch (cmd) {
191
+ case 'init':
192
+ code = runInit(rest);
193
+ break;
194
+ case 'disable':
195
+ case 'uninstall':
196
+ code = runDisable();
197
+ break;
198
+ case 'status':
199
+ code = runStatus();
200
+ break;
201
+ case 'test':
202
+ code = runTest(rest);
203
+ break;
204
+ case 'hook': {
205
+ const event = rest[0];
206
+ const failClosed = hasFlag(rest, 'fail-closed');
207
+ if (event === 'pre-tool-use' || !event) {
208
+ await runPreToolUseHook(failClosed);
209
+ // runPreToolUseHook calls process.exit, but TS doesn't know
210
+ return;
211
+ }
212
+ // Other hook events: silently allow for now (forward compat)
213
+ process.stdout.write('{}');
214
+ process.exit(0);
215
+ }
216
+ case 'help':
217
+ case '--help':
218
+ case '-h':
219
+ case undefined:
220
+ help();
221
+ break;
222
+ default:
223
+ console.error(`${c.red}Unknown command: ${cmd}${c.reset}\n`);
224
+ help();
225
+ code = 2;
226
+ }
227
+ }
228
+ catch (err) {
229
+ console.error(`${c.red}Error:${c.reset} ${err instanceof Error ? err.message : String(err)}`);
230
+ if (process.env.DEBUG)
231
+ console.error(err);
232
+ code = 2;
233
+ }
234
+ process.exit(code);
235
+ }
236
+ main();
237
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Manage ~/.claude/settings.json — install, remove, inspect the WARD hook.
3
+ *
4
+ * Safety rules:
5
+ * - Always back up existing settings.json before modifying
6
+ * - Use atomic writes (write to .tmp then rename)
7
+ * - Idempotent: running `init` twice doesn't duplicate hook entries
8
+ * - Preserve unknown keys (other hooks, other config) untouched
9
+ */
10
+ import type { ClaudeSettingsHooksEntry } from './types.js';
11
+ export declare function claudeConfigDir(): string;
12
+ export declare function claudeSettingsPath(): string;
13
+ export declare function userWardPath(): string;
14
+ export interface ClaudeSettings {
15
+ hooks?: {
16
+ PreToolUse?: ClaudeSettingsHooksEntry[];
17
+ PostToolUse?: ClaudeSettingsHooksEntry[];
18
+ Stop?: ClaudeSettingsHooksEntry[];
19
+ SessionStart?: ClaudeSettingsHooksEntry[];
20
+ [other: string]: ClaudeSettingsHooksEntry[] | undefined;
21
+ };
22
+ [other: string]: unknown;
23
+ }
24
+ export declare function readSettings(): ClaudeSettings;
25
+ export declare function writeSettings(settings: ClaudeSettings): void;
26
+ /**
27
+ * The unique tag we put inside the hook command so we can find and remove
28
+ * our own entries without affecting hooks the user added manually.
29
+ */
30
+ export declare const WARD_HOOK_MARKER = "# WEAVE_WARD_HOOK";
31
+ export interface InstallOptions {
32
+ /** Path to the weave-claude-code binary. Defaults to "weave-claude-code". */
33
+ binary?: string;
34
+ /** Restrict the hook to specific tool names. Default: all tools. */
35
+ toolMatcher?: string;
36
+ /** Hook timeout in seconds. */
37
+ timeoutSeconds?: number;
38
+ /** Block on error or fail-open? Default: fail-open (false). */
39
+ failClosed?: boolean;
40
+ }
41
+ export declare function isHookInstalled(settings: ClaudeSettings): boolean;
42
+ export declare function installHook(opts?: InstallOptions): ClaudeSettings;
43
+ export declare function removeHook(): {
44
+ removed: number;
45
+ settings: ClaudeSettings;
46
+ };
47
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAM3D,wBAAgB,eAAe,IAAI,MAAM,CAIxC;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAMD,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE;QACN,UAAU,CAAC,EAAE,wBAAwB,EAAE,CAAC;QACxC,WAAW,CAAC,EAAE,wBAAwB,EAAE,CAAC;QACzC,IAAI,CAAC,EAAE,wBAAwB,EAAE,CAAC;QAClC,YAAY,CAAC,EAAE,wBAAwB,EAAE,CAAC;QAC1C,CAAC,KAAK,EAAE,MAAM,GAAG,wBAAwB,EAAE,GAAG,SAAS,CAAC;KACzD,CAAC;IACF,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,wBAAgB,YAAY,IAAI,cAAc,CAY7C;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAc5D;AAMD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,sBAAsB,CAAC;AAEpD,MAAM,WAAW,cAAc;IAC7B,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAKjE;AAED,wBAAgB,WAAW,CAAC,IAAI,GAAE,cAAmB,GAAG,cAAc,CAiCrE;AAED,wBAAgB,UAAU,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAA;CAAE,CAY1E"}
package/dist/config.js ADDED
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Manage ~/.claude/settings.json — install, remove, inspect the WARD hook.
3
+ *
4
+ * Safety rules:
5
+ * - Always back up existing settings.json before modifying
6
+ * - Use atomic writes (write to .tmp then rename)
7
+ * - Idempotent: running `init` twice doesn't duplicate hook entries
8
+ * - Preserve unknown keys (other hooks, other config) untouched
9
+ */
10
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, renameSync, copyFileSync } from 'node:fs';
11
+ import { dirname, join, resolve } from 'node:path';
12
+ import { homedir } from 'node:os';
13
+ // ============================================================================
14
+ // Paths
15
+ // ============================================================================
16
+ export function claudeConfigDir() {
17
+ return process.env.CLAUDE_CONFIG_DIR
18
+ ? resolve(process.env.CLAUDE_CONFIG_DIR)
19
+ : join(homedir(), '.claude');
20
+ }
21
+ export function claudeSettingsPath() {
22
+ return join(claudeConfigDir(), 'settings.json');
23
+ }
24
+ export function userWardPath() {
25
+ return join(claudeConfigDir(), 'WARD.md');
26
+ }
27
+ export function readSettings() {
28
+ const path = claudeSettingsPath();
29
+ if (!existsSync(path))
30
+ return {};
31
+ try {
32
+ return JSON.parse(readFileSync(path, 'utf8'));
33
+ }
34
+ catch (err) {
35
+ throw new Error(`Failed to parse ${path} — please fix the JSON syntax or back it up and re-run. Original: ${err instanceof Error ? err.message : String(err)}`);
36
+ }
37
+ }
38
+ export function writeSettings(settings) {
39
+ const path = claudeSettingsPath();
40
+ mkdirSync(dirname(path), { recursive: true });
41
+ // Backup existing
42
+ if (existsSync(path)) {
43
+ const backup = `${path}.weave-backup`;
44
+ copyFileSync(path, backup);
45
+ }
46
+ // Atomic write
47
+ const tmp = `${path}.tmp`;
48
+ writeFileSync(tmp, JSON.stringify(settings, null, 2) + '\n', 'utf8');
49
+ renameSync(tmp, path);
50
+ }
51
+ // ============================================================================
52
+ // Hook install / remove
53
+ // ============================================================================
54
+ /**
55
+ * The unique tag we put inside the hook command so we can find and remove
56
+ * our own entries without affecting hooks the user added manually.
57
+ */
58
+ export const WARD_HOOK_MARKER = '# WEAVE_WARD_HOOK';
59
+ export function isHookInstalled(settings) {
60
+ const entries = settings.hooks?.PreToolUse || [];
61
+ return entries.some((e) => e.hooks?.some((h) => h.command.includes(WARD_HOOK_MARKER)));
62
+ }
63
+ export function installHook(opts = {}) {
64
+ const settings = readSettings();
65
+ const binary = opts.binary || 'weave-claude-code';
66
+ const matcher = opts.toolMatcher || '*';
67
+ const failFlag = opts.failClosed ? ' --fail-closed' : '';
68
+ // Construct the command with our marker
69
+ const command = `${binary} hook pre-tool-use${failFlag} ${WARD_HOOK_MARKER}`;
70
+ const entry = {
71
+ matcher,
72
+ hooks: [
73
+ {
74
+ type: 'command',
75
+ command,
76
+ timeout: opts.timeoutSeconds ?? 5,
77
+ },
78
+ ],
79
+ };
80
+ if (!settings.hooks)
81
+ settings.hooks = {};
82
+ if (!settings.hooks.PreToolUse)
83
+ settings.hooks.PreToolUse = [];
84
+ // Remove any existing WARD entries first (idempotent)
85
+ settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter((e) => !e.hooks?.some((h) => h.command.includes(WARD_HOOK_MARKER)));
86
+ // Add our new entry
87
+ settings.hooks.PreToolUse.push(entry);
88
+ writeSettings(settings);
89
+ return settings;
90
+ }
91
+ export function removeHook() {
92
+ const settings = readSettings();
93
+ if (!settings.hooks?.PreToolUse)
94
+ return { removed: 0, settings };
95
+ const before = settings.hooks.PreToolUse.length;
96
+ settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter((e) => !e.hooks?.some((h) => h.command.includes(WARD_HOOK_MARKER)));
97
+ const removed = before - settings.hooks.PreToolUse.length;
98
+ if (removed > 0)
99
+ writeSettings(settings);
100
+ return { removed, settings };
101
+ }
102
+ //# 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,31 @@
1
+ /**
2
+ * Hook handler.
3
+ *
4
+ * This is what Claude Code actually invokes when a tool is about to be used.
5
+ * Reads the hook payload from stdin, looks up the active WARD policy,
6
+ * evaluates the proposed tool call, and writes the decision to stdout.
7
+ *
8
+ * Resolution order for WARD.md:
9
+ * 1. $WEAVE_WARD_PATH if set
10
+ * 2. <cwd>/WARD.md (from the hook payload)
11
+ * 3. <cwd>/.weave/WARD.md
12
+ * 4. ~/.claude/WARD.md (user-global fallback)
13
+ *
14
+ * Failure mode (when WARD parse fails):
15
+ * - default: fail OPEN (write a warning to stderr, allow the call)
16
+ * - --fail-closed: fail CLOSED (block the call with the error reason)
17
+ */
18
+ import { type WardPolicy } from '@weave_protocol/ward';
19
+ export interface ResolvedWard {
20
+ policy: WardPolicy;
21
+ source: string;
22
+ }
23
+ export declare function resolveWardForCwd(cwd: string): ResolvedWard | null;
24
+ export interface HookDecision {
25
+ decision: 'allow' | 'deny' | 'require_approval';
26
+ reasons: string[];
27
+ policySource?: string;
28
+ }
29
+ export declare function evaluateCall(policy: WardPolicy, toolName: string, toolInput: Record<string, unknown> | undefined): HookDecision;
30
+ export declare function runPreToolUseHook(failClosed: boolean): Promise<never>;
31
+ //# sourceMappingURL=hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAKL,KAAK,UAAU,EAEhB,MAAM,sBAAsB,CAAC;AA2B9B,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAmBlE;AAMD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,kBAAkB,CAAC;IAChD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC7C,YAAY,CA8Dd;AAmGD,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAkE3E"}
package/dist/hook.js ADDED
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Hook handler.
3
+ *
4
+ * This is what Claude Code actually invokes when a tool is about to be used.
5
+ * Reads the hook payload from stdin, looks up the active WARD policy,
6
+ * evaluates the proposed tool call, and writes the decision to stdout.
7
+ *
8
+ * Resolution order for WARD.md:
9
+ * 1. $WEAVE_WARD_PATH if set
10
+ * 2. <cwd>/WARD.md (from the hook payload)
11
+ * 3. <cwd>/.weave/WARD.md
12
+ * 4. ~/.claude/WARD.md (user-global fallback)
13
+ *
14
+ * Failure mode (when WARD parse fails):
15
+ * - default: fail OPEN (write a warning to stderr, allow the call)
16
+ * - --fail-closed: fail CLOSED (block the call with the error reason)
17
+ */
18
+ import { readFileSync, existsSync } from 'node:fs';
19
+ import { join, resolve } from 'node:path';
20
+ import { parseWard, checkCapability, checkFilesystem, checkNetwork, } from '@weave_protocol/ward';
21
+ import { TOOL_MAPPINGS, } from './types.js';
22
+ import { userWardPath } from './config.js';
23
+ // ============================================================================
24
+ // stdin reader
25
+ // ============================================================================
26
+ async function readStdin() {
27
+ if (process.stdin.isTTY)
28
+ return '';
29
+ return new Promise((resolveStdin) => {
30
+ let data = '';
31
+ process.stdin.setEncoding('utf8');
32
+ process.stdin.on('data', (chunk) => (data += chunk));
33
+ process.stdin.on('end', () => resolveStdin(data));
34
+ });
35
+ }
36
+ export function resolveWardForCwd(cwd) {
37
+ const candidates = [];
38
+ if (process.env.WEAVE_WARD_PATH)
39
+ candidates.push(process.env.WEAVE_WARD_PATH);
40
+ if (cwd) {
41
+ candidates.push(join(cwd, 'WARD.md'));
42
+ candidates.push(join(cwd, '.weave', 'WARD.md'));
43
+ }
44
+ candidates.push(userWardPath());
45
+ for (const path of candidates) {
46
+ const resolved = resolve(path);
47
+ if (existsSync(resolved)) {
48
+ const source = readFileSync(resolved, 'utf8');
49
+ const policy = parseWard(source);
50
+ return { policy, source: resolved };
51
+ }
52
+ }
53
+ return null;
54
+ }
55
+ export function evaluateCall(policy, toolName, toolInput) {
56
+ const reasons = [];
57
+ let decision = 'allow';
58
+ const mapping = TOOL_MAPPINGS[toolName] || { capability: toolName };
59
+ // 1. Capability check (try mapped name first, then raw tool name)
60
+ const capByMapping = checkCapability(policy, mapping.capability);
61
+ const capByRaw = checkCapability(policy, toolName);
62
+ // Smart merge: explicit rules (allow/deny/approval list) beat default decisions.
63
+ // The user can use either the Claude tool name (Bash) or the generic
64
+ // capability (shell_exec) in their WARD.md — either explicit match wins.
65
+ const cap = mergeCapability(capByMapping, capByRaw);
66
+ if (cap.decision === 'deny') {
67
+ return { decision: 'deny', reasons: [cap.reason] };
68
+ }
69
+ if (cap.decision === 'require_approval') {
70
+ decision = 'require_approval';
71
+ reasons.push(cap.reason);
72
+ }
73
+ // 2. Filesystem check
74
+ if (mapping.pathField && toolInput && typeof toolInput[mapping.pathField] === 'string') {
75
+ const path = toolInput[mapping.pathField];
76
+ const fs = checkFilesystem(policy, mapping.fsOp || 'read', path);
77
+ if (fs.decision === 'deny') {
78
+ return { decision: 'deny', reasons: [fs.reason] };
79
+ }
80
+ if (fs.decision === 'require_approval' && decision !== 'require_approval') {
81
+ decision = 'require_approval';
82
+ reasons.push(fs.reason);
83
+ }
84
+ }
85
+ // 3. Network check
86
+ if (mapping.urlField && toolInput && typeof toolInput[mapping.urlField] === 'string') {
87
+ const url = toolInput[mapping.urlField];
88
+ const method = toolInput.method || 'GET';
89
+ const net = checkNetwork(policy, url, method);
90
+ if (net.decision === 'deny') {
91
+ return { decision: 'deny', reasons: [net.reason] };
92
+ }
93
+ if (net.decision === 'require_approval' && decision !== 'require_approval') {
94
+ decision = 'require_approval';
95
+ reasons.push(net.reason);
96
+ }
97
+ }
98
+ // 4. Bash command heuristics — scan the command string for path patterns
99
+ if (mapping.commandField && toolInput && typeof toolInput[mapping.commandField] === 'string') {
100
+ const command = toolInput[mapping.commandField];
101
+ const bashCheck = scanBashCommand(policy, command);
102
+ if (bashCheck.decision === 'deny') {
103
+ return { decision: 'deny', reasons: [bashCheck.reason] };
104
+ }
105
+ if (bashCheck.decision === 'require_approval' && decision !== 'require_approval') {
106
+ decision = 'require_approval';
107
+ reasons.push(bashCheck.reason);
108
+ }
109
+ }
110
+ return { decision, reasons };
111
+ }
112
+ /**
113
+ * Distinguish "explicit rule match" (user listed this tool in allow/deny/
114
+ * requireApproval) from "default decision" (policy default kicked in
115
+ * because nothing matched). Explicit rules win across both name variants.
116
+ */
117
+ function isExplicit(reason) {
118
+ return (reason.includes('is in the allow list') ||
119
+ reason.includes('is in the deny list') ||
120
+ reason.includes('requires human approval'));
121
+ }
122
+ function mergeCapability(a, b) {
123
+ const aExp = isExplicit(a.reason);
124
+ const bExp = isExplicit(b.reason);
125
+ // If exactly one is explicit, that one wins regardless of decision.
126
+ if (aExp && !bExp)
127
+ return a;
128
+ if (bExp && !aExp)
129
+ return b;
130
+ // Both explicit OR both default — take the strictest:
131
+ // deny > require_approval > allow
132
+ if (a.decision === 'deny' || b.decision === 'deny') {
133
+ return a.decision === 'deny' ? a : b;
134
+ }
135
+ if (a.decision === 'require_approval' || b.decision === 'require_approval') {
136
+ return a.decision === 'require_approval' ? a : b;
137
+ }
138
+ return a;
139
+ }
140
+ function mergeStricter(a, b) {
141
+ if (a.decision === 'deny' || b.decision === 'deny') {
142
+ return a.decision === 'deny' ? a : b;
143
+ }
144
+ if (a.decision === 'require_approval' || b.decision === 'require_approval') {
145
+ return a.decision === 'require_approval' ? a : b;
146
+ }
147
+ return a;
148
+ }
149
+ /**
150
+ * Lightweight scan of a bash command for paths/URLs that might violate the
151
+ * filesystem/network policy. This is best-effort — full bash parsing isn't
152
+ * practical at this layer. We catch the common cases: explicit paths to
153
+ * sensitive files, curl/wget to disallowed URLs.
154
+ */
155
+ function scanBashCommand(policy, command) {
156
+ // Look for URLs
157
+ const urlMatch = command.match(/https?:\/\/[^\s'"`)]+/);
158
+ if (urlMatch) {
159
+ const net = checkNetwork(policy, urlMatch[0], 'GET');
160
+ if (net.decision === 'deny')
161
+ return { decision: 'deny', reason: `bash command targets ${urlMatch[0]}: ${net.reason}` };
162
+ if (net.decision === 'require_approval')
163
+ return { decision: 'require_approval', reason: `bash command targets ${urlMatch[0]}: ${net.reason}` };
164
+ }
165
+ // Look for obvious destructive operations to common sensitive paths
166
+ const dangerousPaths = ['~/.ssh', '~/.aws', '/etc/', '/usr/', '/.env'];
167
+ for (const danger of dangerousPaths) {
168
+ if (command.includes(danger)) {
169
+ // Infer op from command verb
170
+ let op = 'read';
171
+ if (/^|[\s;|]rm\s|>\s*['"]?\Q+danger/.test(command))
172
+ op = 'delete';
173
+ else if (/>|>>|tee|sed -i/.test(command))
174
+ op = 'write';
175
+ const fs = checkFilesystem(policy, op, danger + (danger.endsWith('/') ? '**' : ''));
176
+ if (fs.decision === 'deny')
177
+ return { decision: 'deny', reason: `bash touches ${danger}: ${fs.reason}` };
178
+ if (fs.decision === 'require_approval')
179
+ return { decision: 'require_approval', reason: `bash touches ${danger}: ${fs.reason}` };
180
+ }
181
+ }
182
+ return { decision: 'allow', reason: '' };
183
+ }
184
+ // ============================================================================
185
+ // Hook output helpers
186
+ // ============================================================================
187
+ function emit(output) {
188
+ process.stdout.write(JSON.stringify(output));
189
+ process.exit(0);
190
+ }
191
+ // ============================================================================
192
+ // Main entry
193
+ // ============================================================================
194
+ export async function runPreToolUseHook(failClosed) {
195
+ const raw = await readStdin();
196
+ // No payload → can't do anything useful, pass through silently
197
+ if (!raw.trim())
198
+ emit({});
199
+ let payload;
200
+ try {
201
+ payload = JSON.parse(raw);
202
+ }
203
+ catch {
204
+ // Malformed payload — fail open (default) or closed
205
+ if (failClosed)
206
+ emit({ decision: 'block', reason: 'WARD hook: malformed payload from Claude Code' });
207
+ process.stderr.write('weave-claude-code: malformed hook payload, allowing\n');
208
+ emit({});
209
+ }
210
+ if (!payload.tool_name)
211
+ emit({});
212
+ const cwd = payload.cwd || process.cwd();
213
+ // Resolve WARD policy
214
+ let resolved = null;
215
+ try {
216
+ resolved = resolveWardForCwd(cwd);
217
+ }
218
+ catch (err) {
219
+ const msg = err instanceof Error ? err.message : String(err);
220
+ if (failClosed)
221
+ emit({ decision: 'block', reason: `WARD policy could not be loaded: ${msg}` });
222
+ process.stderr.write(`weave-claude-code: WARD load failed (${msg}), allowing\n`);
223
+ emit({});
224
+ }
225
+ if (!resolved) {
226
+ // No WARD.md found — nothing to enforce
227
+ emit({});
228
+ }
229
+ // Evaluate
230
+ let result;
231
+ try {
232
+ result = evaluateCall(resolved.policy, payload.tool_name, payload.tool_input);
233
+ }
234
+ catch (err) {
235
+ const msg = err instanceof Error ? err.message : String(err);
236
+ if (failClosed)
237
+ emit({ decision: 'block', reason: `WARD evaluation failed: ${msg}` });
238
+ process.stderr.write(`weave-claude-code: WARD eval failed (${msg}), allowing\n`);
239
+ emit({});
240
+ }
241
+ if (result.decision === 'deny') {
242
+ emit({
243
+ decision: 'block',
244
+ reason: `🛡️ WARD: ${result.reasons.join(' | ')}\n Policy: ${resolved.source}`,
245
+ });
246
+ }
247
+ if (result.decision === 'require_approval') {
248
+ // Claude Code's hook protocol doesn't have a "needs approval" decision
249
+ // distinct from "block", so we block with a clear reason. The user can
250
+ // explicitly retry / override after reviewing.
251
+ emit({
252
+ decision: 'block',
253
+ reason: `🛡️ WARD requires approval before this call:\n ${result.reasons.join('\n ')}\n Policy: ${resolved.source}\n To proceed, explicitly confirm or update WARD.md.`,
254
+ });
255
+ }
256
+ // Allow — silent
257
+ emit({});
258
+ }
259
+ //# sourceMappingURL=hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.js","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @weave_protocol/adapter-claudecode - public API
3
+ */
4
+ export * from './types.js';
5
+ export { installHook, removeHook, readSettings, writeSettings, isHookInstalled, claudeSettingsPath, claudeConfigDir, userWardPath, WARD_HOOK_MARKER, } from './config.js';
6
+ export type { ClaudeSettings, InstallOptions } from './config.js';
7
+ export { resolveWardForCwd, evaluateCall, runPreToolUseHook, } from './hook.js';
8
+ export type { ResolvedWard, HookDecision } from './hook.js';
9
+ //# 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,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,GAClB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @weave_protocol/adapter-claudecode - public API
3
+ */
4
+ export * from './types.js';
5
+ export { installHook, removeHook, readSettings, writeSettings, isHookInstalled, claudeSettingsPath, claudeConfigDir, userWardPath, WARD_HOOK_MARKER, } from './config.js';
6
+ export { resolveWardForCwd, evaluateCall, runPreToolUseHook, } from './hook.js';
7
+ //# 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,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,GAClB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Types for the Claude Code adapter.
3
+ */
4
+ /**
5
+ * Shape of the JSON sent to a Claude Code hook on stdin.
6
+ * Based on Claude Code's documented hook input format.
7
+ */
8
+ export interface ClaudeCodeHookInput {
9
+ session_id?: string;
10
+ transcript_path?: string;
11
+ cwd?: string;
12
+ hook_event_name?: string;
13
+ tool_name?: string;
14
+ tool_input?: Record<string, unknown>;
15
+ tool_response?: unknown;
16
+ }
17
+ /**
18
+ * Shape of the JSON returned on stdout to control Claude Code's behavior.
19
+ *
20
+ * For PreToolUse:
21
+ * - { "decision": "approve" } → auto-approve (skip user confirm)
22
+ * - { "decision": "block", "reason": …} → block the call with reason
23
+ * - {} (or no output) → let Claude Code decide normally
24
+ *
25
+ * Optional "systemMessage" appears in the conversation; "continue" controls
26
+ * whether the overall turn proceeds.
27
+ */
28
+ export interface ClaudeCodeHookOutput {
29
+ decision?: 'approve' | 'block';
30
+ reason?: string;
31
+ continue?: boolean;
32
+ stopReason?: string;
33
+ systemMessage?: string;
34
+ suppressOutput?: boolean;
35
+ }
36
+ /**
37
+ * The hook type. v0.1 only ships PreToolUse; PostToolUse and Stop come later.
38
+ */
39
+ export type HookType = 'pre-tool-use' | 'post-tool-use' | 'stop' | 'session-start';
40
+ /**
41
+ * Mapping from Claude Code tool names to their nature.
42
+ * Used to extract the right args and apply the right WARD checks.
43
+ */
44
+ export interface ToolMapping {
45
+ /** Generic capability name for WARD `## Capabilities`. */
46
+ capability: string;
47
+ /** Args field that contains a filesystem path, if any. */
48
+ pathField?: string;
49
+ /** Implied filesystem operation for that path. */
50
+ fsOp?: 'read' | 'write' | 'execute' | 'delete' | 'list';
51
+ /** Args field that contains a URL, if any. */
52
+ urlField?: string;
53
+ /** Args field that contains a shell command, if any. */
54
+ commandField?: string;
55
+ }
56
+ /**
57
+ * Built-in mappings for Claude Code's standard tools.
58
+ * Unknown tools fall through with the tool name as the capability.
59
+ */
60
+ export declare const TOOL_MAPPINGS: Record<string, ToolMapping>;
61
+ /**
62
+ * Settings written into ~/.claude/settings.json for the WARD hook.
63
+ */
64
+ export interface ClaudeSettingsHooksEntry {
65
+ matcher?: string;
66
+ hooks: Array<{
67
+ type: 'command';
68
+ command: string;
69
+ timeout?: number;
70
+ }>;
71
+ }
72
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,eAAe,GAAG,MAAM,GAAG,eAAe,CAAC;AAEnF;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;IACxD,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAcrD,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,SAAS,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ"}
package/dist/types.js ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Types for the Claude Code adapter.
3
+ */
4
+ /**
5
+ * Built-in mappings for Claude Code's standard tools.
6
+ * Unknown tools fall through with the tool name as the capability.
7
+ */
8
+ export const TOOL_MAPPINGS = {
9
+ Bash: { capability: 'shell_exec', commandField: 'command' },
10
+ Edit: { capability: 'file_write', pathField: 'file_path', fsOp: 'write' },
11
+ MultiEdit: { capability: 'file_write', pathField: 'file_path', fsOp: 'write' },
12
+ Write: { capability: 'file_write', pathField: 'file_path', fsOp: 'write' },
13
+ Read: { capability: 'file_read', pathField: 'file_path', fsOp: 'read' },
14
+ Glob: { capability: 'file_list', pathField: 'path', fsOp: 'list' },
15
+ Grep: { capability: 'file_read', pathField: 'path', fsOp: 'read' },
16
+ LS: { capability: 'file_list', pathField: 'path', fsOp: 'list' },
17
+ WebFetch: { capability: 'http_request', urlField: 'url' },
18
+ WebSearch: { capability: 'web_search' },
19
+ Task: { capability: 'subagent' },
20
+ TodoWrite: { capability: 'todo_write' },
21
+ NotebookEdit: { capability: 'notebook_edit', pathField: 'notebook_path', fsOp: 'write' },
22
+ };
23
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AA0DH;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAgC;IACxD,IAAI,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE;IAC3D,IAAI,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE;IACzE,SAAS,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE;IAC9E,KAAK,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE;IAC1E,IAAI,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;IACvE,IAAI,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;IAClE,IAAI,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;IAClE,EAAE,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;IAChE,QAAQ,EAAE,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAE;IACzD,SAAS,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE;IACvC,IAAI,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE;IAChC,SAAS,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE;IACvC,YAAY,EAAE,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,EAAE;CACzF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@weave_protocol/adapter-claudecode",
3
+ "version": "0.1.0",
4
+ "description": "Weave Protocol adapter for Claude Code - enforces WARD.md policies via Claude Code's hook system",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "weave-claude-code": "dist/cli.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "dev": "tsc --watch",
14
+ "test": "node --test tests/",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "weave-protocol",
19
+ "ward",
20
+ "claude-code",
21
+ "anthropic",
22
+ "agent-security",
23
+ "ai-security",
24
+ "hooks",
25
+ "harness-adapter",
26
+ "policy-enforcement",
27
+ "agents-md",
28
+ "skill-md",
29
+ "ward-md"
30
+ ],
31
+ "author": "Trent Yoxall",
32
+ "license": "Apache-2.0",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/Tyox-all/Weave_Protocol.git",
36
+ "directory": "adapter-claudecode"
37
+ },
38
+ "homepage": "https://github.com/Tyox-all/Weave_Protocol/tree/main/adapter-claudecode#readme",
39
+ "bugs": {
40
+ "url": "https://github.com/Tyox-all/Weave_Protocol/issues"
41
+ },
42
+ "dependencies": {
43
+ "@weave_protocol/ward": "^0.1.0"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^20.0.0",
47
+ "typescript": "^5.3.0"
48
+ },
49
+ "engines": {
50
+ "node": ">=18.0.0"
51
+ },
52
+ "files": [
53
+ "dist/",
54
+ "README.md",
55
+ "SKILL.md",
56
+ "LICENSE"
57
+ ]
58
+ }