@weave_protocol/adapter-cursor 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 CHANGED
@@ -1,3 +1,68 @@
1
- # Temporary Holding Version
1
+ # 🛡️ @weave_protocol/adapter-cursor
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ > Enforce [WARD.md](https://github.com/Tyox-all/Weave_Protocol/tree/main/ward) in **Cursor** with its agent hooks. Shell commands, file reads and writes, and MCP calls are checked against your policy before they run.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@weave_protocol/adapter-cursor?color=000&style=flat-square)](https://www.npmjs.com/package/@weave_protocol/adapter-cursor)
6
+
7
+ The same WARD.md you use with Claude Code, Antigravity, Microsoft Agent Framework, Gemini CLI, Codex CLI and OpenCode.
8
+
9
+ ## Quick start
10
+
11
+ ```bash
12
+ npm i -g @weave_protocol/adapter-cursor
13
+ weave-ward-cursor init # adds the hook to ~/.cursor/hooks.json
14
+ weave-ward-cursor status
15
+ ```
16
+
17
+ Cursor reloads `hooks.json` when it changes. Add a `WARD.md` to your project (`npx @weave_protocol/ward init`), or a user-wide one at `~/.cursor/WARD.md`.
18
+
19
+ ## How it hooks in
20
+
21
+ One command, `weave-ward-cursor hook`, is registered on four of Cursor's [agent hook events](https://cursor.com/docs/agent/hooks). It decides each call with Ward's shared evaluator (`evaluateToolCall`), so the rules match the other adapters exactly:
22
+
23
+ | Event | Checked |
24
+ |---|---|
25
+ | `beforeShellExecution` | `shell_exec`, the command's `cwd` (as a read), and every URL and absolute or `~` path in the command |
26
+ | `beforeReadFile` | the `file_path` (as a read) |
27
+ | `beforeMCPExecution` | `mcp__<server>__<tool>`, plus every path and URL argument in its `tool_input` |
28
+ | `preToolUse` | every other tool (`Write`, `Delete`, `Grep`, `Task`, …), by capability and every path-named argument. Shell, Read and MCP are left to the events above, which carry richer fields. |
29
+
30
+ ## Decisions
31
+
32
+ | WARD decision | What Cursor sees |
33
+ |---|---|
34
+ | allow | nothing: the call continues, and Cursor's own approval settings still apply |
35
+ | deny | `permission: "deny"`, with the reason in `user_message` and `agent_message` |
36
+ | require_approval | `permission: "ask"` for shell and MCP calls, where Cursor enforces it. Elsewhere it's a deny whose reason says approval is needed, because `preToolUse` doesn't enforce "ask" and `beforeReadFile` has none. |
37
+
38
+ **Failure modes:**
39
+ - **An invalid WARD.md always denies**, so a typo can't silently switch enforcement off.
40
+ - **No WARD.md anywhere means no enforcement.**
41
+ - **Malformed payloads and evaluator errors** allow by default. `init --fail-closed` makes them deny.
42
+
43
+ WARD.md is looked up in this order:
44
+ 1. `$WEAVE_WARD_PATH`
45
+ 2. `<workspace>/WARD.md`
46
+ 3. `<workspace>/.cursor/WARD.md`
47
+ 4. `<workspace>/.weave/WARD.md`
48
+ 5. `~/.cursor/WARD.md`
49
+
50
+ ## Commands
51
+
52
+ ```bash
53
+ weave-ward-cursor init [--timeout=SECONDS] [--fail-closed]
54
+ weave-ward-cursor disable
55
+ weave-ward-cursor status
56
+ weave-ward-cursor test Read --input='{"file_path":"secrets/key"}' # dry run
57
+ weave-ward-cursor hook # what Cursor runs
58
+ ```
59
+
60
+ `init` backs up `hooks.json` and edits it atomically. It adds one entry per event and leaves your other hooks alone. The command is `weave-ward-cursor`, matching `weave-ward-codex` and `weave-ward-opencode`.
61
+
62
+ ## Verified
63
+
64
+ Built against Cursor's [agent hooks documentation](https://cursor.com/docs/agent/hooks), with 11 fixture tests. It hasn't been live-checked in Cursor yet. Cursor's docs don't say whether the `cursor-agent` CLI runs agent hooks, so for now treat this as an IDE adapter.
65
+
66
+ ## License
67
+
68
+ Apache-2.0
package/dist/cli.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * weave-ward-cursor CLI
4
+ *
5
+ * weave-ward-cursor init [--timeout=SECONDS] [--fail-closed] Install the WARD hook on four events
6
+ * weave-ward-cursor disable Remove it
7
+ * weave-ward-cursor status Hook + active WARD.md
8
+ * weave-ward-cursor test <tool> [--input=JSON] Dry-run a tool call (Shell, Read, Write, ...)
9
+ * weave-ward-cursor hook [--fail-closed] Hook handler (run by Cursor)
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG"}
package/dist/cli.js ADDED
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * weave-ward-cursor CLI
4
+ *
5
+ * weave-ward-cursor init [--timeout=SECONDS] [--fail-closed] Install the WARD hook on four events
6
+ * weave-ward-cursor disable Remove it
7
+ * weave-ward-cursor status Hook + active WARD.md
8
+ * weave-ward-cursor test <tool> [--input=JSON] Dry-run a tool call (Shell, Read, Write, ...)
9
+ * weave-ward-cursor hook [--fail-closed] Hook handler (run by Cursor)
10
+ */
11
+ import { installHook, removeHook, isHookInstalled, readHooks, hooksJsonPath, userWardPath } from './config.js';
12
+ import { resolveWardForRoot, evaluateCall, runHook } from './hook.js';
13
+ const tty = process.stderr.isTTY && !process.env.NO_COLOR;
14
+ const c = {
15
+ reset: tty ? '\x1b[0m' : '', bold: tty ? '\x1b[1m' : '', red: tty ? '\x1b[31m' : '',
16
+ green: tty ? '\x1b[32m' : '', yellow: tty ? '\x1b[33m' : '', cyan: tty ? '\x1b[36m' : '', gray: tty ? '\x1b[90m' : '',
17
+ };
18
+ const say = (s = '') => console.error(s);
19
+ const flag = (args, name) => args.includes(`--${name}`);
20
+ const option = (args, name) => args.find((a) => a.startsWith(`--${name}=`))?.slice(name.length + 3);
21
+ function help() {
22
+ say(`\n${c.cyan}${c.bold}🛡️ weave-ward-cursor${c.reset} ${c.gray}WARD.md enforcement for Cursor${c.reset}\n`);
23
+ say(`${c.bold}Commands:${c.reset}`);
24
+ say(` ${c.cyan}init${c.reset} ${c.gray}[--timeout=SECONDS] [--fail-closed]${c.reset} Install the hook in ~/.cursor/hooks.json`);
25
+ say(` ${c.cyan}disable${c.reset} Remove the hook`);
26
+ say(` ${c.cyan}status${c.reset} Show the hook and the active WARD.md`);
27
+ say(` ${c.cyan}test${c.reset} ${c.gray}<tool> [--input=JSON]${c.reset} Dry-run a tool call against WARD.md`);
28
+ say(` ${c.cyan}hook${c.reset} ${c.gray}[--fail-closed]${c.reset} Hook handler (Cursor runs this)\n`);
29
+ return 0;
30
+ }
31
+ function init(args) {
32
+ const timeout = option(args, 'timeout');
33
+ installHook({
34
+ timeoutSeconds: timeout ? Number(timeout) : undefined,
35
+ failClosed: flag(args, 'fail-closed'),
36
+ });
37
+ say(`${c.green}✓${c.reset} WARD hook installed in ${hooksJsonPath()} (beforeShellExecution, beforeMCPExecution, beforeReadFile, preToolUse)`);
38
+ say(`${c.gray}Cursor reloads hooks.json on save.${c.reset}`);
39
+ const ward = safeResolve(process.cwd());
40
+ if (!ward) {
41
+ say(`${c.yellow}!${c.reset} No WARD.md found here or at ${userWardPath()}; calls are allowed until you add one.`);
42
+ }
43
+ return 0;
44
+ }
45
+ function disable() {
46
+ const { removed } = removeHook();
47
+ say(removed ? `${c.green}✓${c.reset} Removed the WARD hook from ${hooksJsonPath()}` : 'No WARD hook was installed.');
48
+ return 0;
49
+ }
50
+ function safeResolve(cwd) {
51
+ try {
52
+ return resolveWardForRoot(cwd);
53
+ }
54
+ catch (err) {
55
+ say(`${c.red}✗${c.reset} ${err instanceof Error ? err.message : String(err)}`);
56
+ return null;
57
+ }
58
+ }
59
+ function status() {
60
+ const installed = isHookInstalled(readHooks());
61
+ say(`Hook: ${installed ? `${c.green}installed${c.reset}` : `${c.yellow}not installed${c.reset}`} (${hooksJsonPath()})`);
62
+ const ward = safeResolve(process.cwd());
63
+ say(`WARD.md: ${ward ? ward.source : `${c.yellow}none found${c.reset}`}`);
64
+ return installed && ward ? 0 : 1;
65
+ }
66
+ function test(args) {
67
+ const tool = args.find((a) => !a.startsWith('--'));
68
+ if (!tool) {
69
+ say('Usage: weave-ward-cursor test <tool> [--input=JSON]');
70
+ return 2;
71
+ }
72
+ const ward = safeResolve(process.cwd());
73
+ if (!ward) {
74
+ say('No WARD.md found; nothing to test against.');
75
+ return 2;
76
+ }
77
+ const input = JSON.parse(option(args, 'input') ?? '{}');
78
+ const result = evaluateCall(ward.policy, { tool, args: input, cwd: process.cwd(), canAsk: false });
79
+ const color = result.decision === 'allow' ? c.green : result.decision === 'deny' ? c.red : c.yellow;
80
+ say(`${color}${result.decision}${c.reset} ${tool}`);
81
+ for (const r of result.reasons)
82
+ say(` ${c.gray}${r}${c.reset}`);
83
+ return result.decision === 'allow' ? 0 : 1;
84
+ }
85
+ async function main() {
86
+ const [cmd, ...rest] = process.argv.slice(2);
87
+ switch (cmd) {
88
+ case 'init': return init(rest);
89
+ case 'disable':
90
+ case 'uninstall': return disable();
91
+ case 'status': return status();
92
+ case 'test': return test(rest);
93
+ case 'hook':
94
+ return runHook(flag(rest, 'fail-closed'));
95
+ default: return help();
96
+ }
97
+ }
98
+ main().then((code) => process.exit(code), (err) => {
99
+ say(`weave-ward-cursor: ${err instanceof Error ? err.message : String(err)}`);
100
+ process.exit(1);
101
+ });
102
+ //# 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,36 @@
1
+ /**
2
+ * Manage ~/.cursor/hooks.json — install, remove, inspect the WARD hook on
3
+ * the four events it handles. Cursor reloads hooks.json on save.
4
+ *
5
+ * Safety rules:
6
+ * - Back up hooks.json before changing it, and write atomically
7
+ * - Idempotent: init twice leaves one entry per event
8
+ * - Our entries are found by their command; other hooks are untouched
9
+ */
10
+ import { type CursorHookEntry } from './types.js';
11
+ export declare function cursorDir(): string;
12
+ export declare function hooksJsonPath(): string;
13
+ /** User-global WARD.md, used when a project has none. */
14
+ export declare function userWardPath(): string;
15
+ export interface HooksFile {
16
+ version?: number;
17
+ hooks?: Record<string, CursorHookEntry[] | undefined>;
18
+ [other: string]: unknown;
19
+ }
20
+ export declare function readHooks(path?: string): HooksFile;
21
+ export declare function writeHooks(file: HooksFile, path?: string): void;
22
+ export interface InstallOptions {
23
+ /** Command that runs this CLI. Default: "weave-ward-cursor" */
24
+ binary?: string;
25
+ /** Hook timeout in seconds. Default 10 */
26
+ timeoutSeconds?: number;
27
+ /** Deny on malformed payloads and evaluator errors. Default: allow */
28
+ failClosed?: boolean;
29
+ }
30
+ export declare function isHookInstalled(file?: HooksFile): boolean;
31
+ export declare function installHook(opts?: InstallOptions): HooksFile;
32
+ export declare function removeHook(): {
33
+ removed: number;
34
+ file: HooksFile;
35
+ };
36
+ //# 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,EAAU,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAE1D,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,yDAAyD;AACzD,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,SAAS,CAAC,CAAC;IACtD,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;AAKD,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAMD,wBAAgB,eAAe,CAAC,IAAI,GAAE,SAAuB,GAAG,OAAO,CAEtE;AAED,wBAAgB,WAAW,CAAC,IAAI,GAAE,cAAmB,GAAG,SAAS,CAYhE;AAED,wBAAgB,UAAU,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,CAajE"}
package/dist/config.js ADDED
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Manage ~/.cursor/hooks.json — install, remove, inspect the WARD hook on
3
+ * the four events it handles. Cursor reloads hooks.json on save.
4
+ *
5
+ * Safety rules:
6
+ * - Back up hooks.json before changing it, and write atomically
7
+ * - Idempotent: init twice leaves one entry per event
8
+ * - Our entries are found by their command; other hooks are untouched
9
+ */
10
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, renameSync, copyFileSync } from 'node:fs';
11
+ import { dirname, join } from 'node:path';
12
+ import { homedir } from 'node:os';
13
+ import { EVENTS } from './types.js';
14
+ export function cursorDir() {
15
+ return join(homedir(), '.cursor');
16
+ }
17
+ export function hooksJsonPath() {
18
+ return join(cursorDir(), 'hooks.json');
19
+ }
20
+ /** User-global WARD.md, used when a project has none. */
21
+ export function userWardPath() {
22
+ return join(cursorDir(), 'WARD.md');
23
+ }
24
+ export function readHooks(path = hooksJsonPath()) {
25
+ if (!existsSync(path))
26
+ return {};
27
+ try {
28
+ return JSON.parse(readFileSync(path, 'utf8'));
29
+ }
30
+ catch (err) {
31
+ throw new Error(`Failed to parse ${path}; fix the JSON or move it aside and re-run. ${err instanceof Error ? err.message : String(err)}`);
32
+ }
33
+ }
34
+ export function writeHooks(file, path = hooksJsonPath()) {
35
+ mkdirSync(dirname(path), { recursive: true });
36
+ if (existsSync(path))
37
+ copyFileSync(path, `${path}.weave-backup`);
38
+ const tmp = `${path}.tmp`;
39
+ writeFileSync(tmp, JSON.stringify(file, null, 2) + '\n', 'utf8');
40
+ renameSync(tmp, path);
41
+ }
42
+ /** The command marker: our entries run "<binary> hook". */
43
+ const HOOK_ARGS = ' hook';
44
+ /** Our entries: the published bin, or this package's built CLI run by path. */
45
+ const anyOurs = (e) => typeof e.command === 'string' && /(^|[\s/])weave-ward-cursor hook\b|adapter-cursor\/dist\/cli\.js hook\b/.test(e.command);
46
+ export function isHookInstalled(file = readHooks()) {
47
+ return EVENTS.every((ev) => (file.hooks?.[ev] ?? []).some(anyOurs));
48
+ }
49
+ export function installHook(opts = {}) {
50
+ const binary = opts.binary ?? 'weave-ward-cursor';
51
+ const file = readHooks();
52
+ file.version ??= 1;
53
+ const hooks = (file.hooks ??= {});
54
+ const command = `${binary}${HOOK_ARGS}${opts.failClosed ? ' --fail-closed' : ''}`;
55
+ for (const ev of EVENTS) {
56
+ const keep = (hooks[ev] ?? []).filter((e) => !anyOurs(e));
57
+ hooks[ev] = [...keep, { command, timeout: opts.timeoutSeconds ?? 10 }];
58
+ }
59
+ writeHooks(file);
60
+ return file;
61
+ }
62
+ export function removeHook() {
63
+ const file = readHooks();
64
+ let removed = 0;
65
+ for (const ev of EVENTS) {
66
+ const before = file.hooks?.[ev];
67
+ if (!before)
68
+ continue;
69
+ const after = before.filter((e) => !anyOurs(e));
70
+ removed += before.length - after.length;
71
+ if (after.length)
72
+ file.hooks[ev] = after;
73
+ else
74
+ delete file.hooks[ev];
75
+ }
76
+ if (removed > 0)
77
+ writeHooks(file);
78
+ return { removed, file };
79
+ }
80
+ //# 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,50 @@
1
+ /**
2
+ * Hook handler for Cursor's agent hooks. Reads the payload from stdin, finds
3
+ * the active WARD.md, decides with Ward's shared evaluator, and prints
4
+ * Cursor's permission output.
5
+ *
6
+ * WARD.md resolution (root = the first workspace root, else cwd):
7
+ * 1. $WEAVE_WARD_PATH
8
+ * 2. <root>/WARD.md
9
+ * 3. <root>/.cursor/WARD.md
10
+ * 4. <root>/.weave/WARD.md
11
+ * 5. ~/.cursor/WARD.md (user-global)
12
+ *
13
+ * Output: an allowed call prints nothing, so Cursor's own approval settings
14
+ * still apply. A deny prints permission "deny" with the reason. A WARD
15
+ * require_approval prints "ask" on shell and MCP calls, where Cursor
16
+ * enforces it, and "deny" elsewhere (preToolUse doesn't enforce "ask", and
17
+ * beforeReadFile has none).
18
+ *
19
+ * Failure modes:
20
+ * - A WARD.md that exists but is invalid always denies.
21
+ * - Malformed payloads and evaluator errors allow by default (with a note
22
+ * on stderr); --fail-closed denies instead.
23
+ */
24
+ import { type WardPolicy } from '@weave_protocol/ward';
25
+ import { type CursorHookInput, type CursorHookOutput } from './types.js';
26
+ export interface ResolvedWard {
27
+ policy: WardPolicy;
28
+ source: string;
29
+ }
30
+ export interface HookDecision {
31
+ decision: 'allow' | 'deny' | 'require_approval';
32
+ reasons: string[];
33
+ }
34
+ /** A tool call extracted from one of the four events, or null to skip it. */
35
+ export interface ToolCall {
36
+ tool: string;
37
+ args: Record<string, unknown>;
38
+ cwd: string;
39
+ /** Whether Cursor enforces "ask" for this event */
40
+ canAsk: boolean;
41
+ }
42
+ export declare function resolveWardForRoot(root: string): ResolvedWard | null;
43
+ /** Turn a Cursor hook payload into the tool call Ward should decide. */
44
+ export declare function toToolCall(payload: CursorHookInput, fallbackCwd?: string): ToolCall | null;
45
+ /** Decide a Cursor tool call against a WARD policy. */
46
+ export declare function evaluateCall(policy: WardPolicy, call: ToolCall): HookDecision;
47
+ /** WARD decision → Cursor output; undefined means print nothing. */
48
+ export declare function toHookOutput(result: HookDecision, source: string, canAsk: boolean): CursorHookOutput | undefined;
49
+ export declare function runHook(failClosed: boolean): Promise<never>;
50
+ //# sourceMappingURL=hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,EAAsC,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAiB,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGxF,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,6EAA6E;AAC7E,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAmBpE;AAaD,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,OAAO,EAAE,eAAe,EAAE,WAAW,SAAgB,GAAG,QAAQ,GAAG,IAAI,CAqBjG;AAED,uDAAuD;AACvD,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,YAAY,CAG7E;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAUhH;AAiBD,wBAAsB,OAAO,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAoCjE"}
package/dist/hook.js ADDED
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Hook handler for Cursor's agent hooks. Reads the payload from stdin, finds
3
+ * the active WARD.md, decides with Ward's shared evaluator, and prints
4
+ * Cursor's permission output.
5
+ *
6
+ * WARD.md resolution (root = the first workspace root, else cwd):
7
+ * 1. $WEAVE_WARD_PATH
8
+ * 2. <root>/WARD.md
9
+ * 3. <root>/.cursor/WARD.md
10
+ * 4. <root>/.weave/WARD.md
11
+ * 5. ~/.cursor/WARD.md (user-global)
12
+ *
13
+ * Output: an allowed call prints nothing, so Cursor's own approval settings
14
+ * still apply. A deny prints permission "deny" with the reason. A WARD
15
+ * require_approval prints "ask" on shell and MCP calls, where Cursor
16
+ * enforces it, and "deny" elsewhere (preToolUse doesn't enforce "ask", and
17
+ * beforeReadFile has none).
18
+ *
19
+ * Failure modes:
20
+ * - A WARD.md that exists but is invalid always denies.
21
+ * - Malformed payloads and evaluator errors allow by default (with a note
22
+ * on stderr); --fail-closed denies instead.
23
+ */
24
+ import { readFileSync, existsSync } from 'node:fs';
25
+ import { join, resolve } from 'node:path';
26
+ import { parseAndValidate, evaluateToolCall } from '@weave_protocol/ward';
27
+ import { TOOL_MAPPINGS } from './types.js';
28
+ import { userWardPath } from './config.js';
29
+ export function resolveWardForRoot(root) {
30
+ const candidates = [
31
+ process.env.WEAVE_WARD_PATH,
32
+ root && join(root, 'WARD.md'),
33
+ root && join(root, '.cursor', 'WARD.md'),
34
+ root && join(root, '.weave', 'WARD.md'),
35
+ userWardPath(),
36
+ ].filter((p) => !!p);
37
+ for (const path of candidates) {
38
+ const full = resolve(path);
39
+ if (!existsSync(full))
40
+ continue;
41
+ const result = parseAndValidate(readFileSync(full, 'utf8'));
42
+ if (!result.valid || !result.policy) {
43
+ throw new Error(`Invalid WARD.md at ${full}: ${result.errors.map((e) => e.message).join('; ')}`);
44
+ }
45
+ return { policy: result.policy, source: full };
46
+ }
47
+ return null;
48
+ }
49
+ const asObject = (v) => {
50
+ if (typeof v === 'string') {
51
+ try {
52
+ v = JSON.parse(v);
53
+ }
54
+ catch {
55
+ return {};
56
+ }
57
+ }
58
+ return v && typeof v === 'object' && !Array.isArray(v) ? v : {};
59
+ };
60
+ /** Turn a Cursor hook payload into the tool call Ward should decide. */
61
+ export function toToolCall(payload, fallbackCwd = process.cwd()) {
62
+ const root = payload.workspace_roots?.[0] || fallbackCwd;
63
+ const cwd = payload.cwd || root;
64
+ switch (payload.hook_event_name) {
65
+ case 'beforeShellExecution':
66
+ return { tool: 'Shell', args: { command: payload.command ?? '', cwd }, cwd, canAsk: true };
67
+ case 'beforeMCPExecution': {
68
+ const server = (payload.mcp_server_name ?? 'unknown').replace(/[^A-Za-z0-9_-]/g, '_');
69
+ return { tool: `mcp__${server}__${payload.tool_name ?? ''}`, args: asObject(payload.tool_input), cwd, canAsk: true };
70
+ }
71
+ case 'beforeReadFile':
72
+ return { tool: 'Read', args: { file_path: payload.file_path ?? '' }, cwd, canAsk: false };
73
+ case 'preToolUse': {
74
+ const tool = payload.tool_name ?? '';
75
+ // Shell, Read and MCP calls are decided by the dedicated events above
76
+ if (tool === 'Shell' || tool === 'Read' || tool.startsWith('MCP:'))
77
+ return null;
78
+ return { tool, args: asObject(payload.tool_input), cwd, canAsk: false };
79
+ }
80
+ default:
81
+ return null;
82
+ }
83
+ }
84
+ /** Decide a Cursor tool call against a WARD policy. */
85
+ export function evaluateCall(policy, call) {
86
+ const { decision, reasons } = evaluateToolCall(policy, call.tool, call.args, { mappings: TOOL_MAPPINGS, cwd: call.cwd });
87
+ return { decision, reasons };
88
+ }
89
+ /** WARD decision → Cursor output; undefined means print nothing. */
90
+ export function toHookOutput(result, source, canAsk) {
91
+ if (result.decision === 'allow')
92
+ return undefined;
93
+ if (result.decision === 'require_approval' && canAsk) {
94
+ const msg = `WARD requires approval: ${result.reasons.join(' | ')} (policy: ${source})`;
95
+ return { permission: 'ask', user_message: msg, agent_message: msg };
96
+ }
97
+ const msg = result.decision === 'deny'
98
+ ? `WARD: ${result.reasons.join(' | ')} (policy: ${source})`
99
+ : `WARD requires approval before this call: ${result.reasons.join(' | ')} (policy: ${source}). Ask the user to approve it or update WARD.md.`;
100
+ return { permission: 'deny', user_message: msg, agent_message: msg };
101
+ }
102
+ async function readStdin() {
103
+ if (process.stdin.isTTY)
104
+ return '';
105
+ let data = '';
106
+ process.stdin.setEncoding('utf8');
107
+ for await (const chunk of process.stdin)
108
+ data += chunk;
109
+ return data;
110
+ }
111
+ function emit(output) {
112
+ if (output)
113
+ process.stdout.write(JSON.stringify(output));
114
+ process.exit(0);
115
+ }
116
+ const denyWith = (msg) => ({ permission: 'deny', user_message: msg, agent_message: msg });
117
+ export async function runHook(failClosed) {
118
+ const raw = await readStdin();
119
+ if (!raw.trim())
120
+ emit();
121
+ let payload;
122
+ try {
123
+ payload = JSON.parse(raw);
124
+ }
125
+ catch {
126
+ if (failClosed)
127
+ emit(denyWith('WARD hook: malformed payload from Cursor'));
128
+ process.stderr.write('weave-ward-cursor: malformed hook payload, allowing\n');
129
+ emit();
130
+ }
131
+ const call = toToolCall(payload);
132
+ if (!call)
133
+ emit();
134
+ let resolved;
135
+ try {
136
+ resolved = resolveWardForRoot(payload.workspace_roots?.[0] || call.cwd);
137
+ }
138
+ catch (err) {
139
+ // A policy exists but can't be used: deny rather than run unprotected.
140
+ emit(denyWith(`WARD policy could not be loaded: ${err instanceof Error ? err.message : String(err)}. Fix WARD.md to continue.`));
141
+ }
142
+ if (!resolved)
143
+ emit();
144
+ let result;
145
+ try {
146
+ result = evaluateCall(resolved.policy, call);
147
+ }
148
+ catch (err) {
149
+ const msg = err instanceof Error ? err.message : String(err);
150
+ if (failClosed)
151
+ emit(denyWith(`WARD evaluation failed: ${msg}`));
152
+ process.stderr.write(`weave-ward-cursor: WARD evaluation failed (${msg}), allowing\n`);
153
+ emit();
154
+ }
155
+ emit(toHookOutput(result, resolved.source, call.canAsk));
156
+ }
157
+ //# 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-cursor — WARD.md enforcement for Cursor's agent hooks.
3
+ */
4
+ export * from './types.js';
5
+ export { cursorDir, hooksJsonPath, userWardPath, readHooks, writeHooks, installHook, removeHook, isHookInstalled, } from './config.js';
6
+ export type { HooksFile, InstallOptions } from './config.js';
7
+ export { resolveWardForRoot, toToolCall, evaluateCall, toHookOutput } from './hook.js';
8
+ export type { ResolvedWard, HookDecision, ToolCall } 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,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,kBAAkB,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACvF,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @weave_protocol/adapter-cursor — WARD.md enforcement for Cursor's agent hooks.
3
+ */
4
+ export * from './types.js';
5
+ export { cursorDir, hooksJsonPath, userWardPath, readHooks, writeHooks, installHook, removeHook, isHookInstalled, } from './config.js';
6
+ export { resolveWardForRoot, toToolCall, evaluateCall, toHookOutput } 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,SAAS,EACT,aAAa,EACb,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,EACX,UAAU,EACV,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Cursor agent hooks (https://cursor.com/docs/agent/hooks).
3
+ *
4
+ * One command is registered on four events and tells them apart by
5
+ * hook_event_name:
6
+ *
7
+ * beforeShellExecution { command, cwd } → Shell
8
+ * beforeMCPExecution { tool_name, tool_input (JSON string),
9
+ * mcp_server_name } → mcp__<server>__<tool>
10
+ * beforeReadFile { file_path } → Read
11
+ * preToolUse { tool_name, tool_input, cwd } → every other tool
12
+ * (Shell, Read and MCP:* are left to the events above,
13
+ * which carry richer fields)
14
+ *
15
+ * Output: { permission: "allow" | "deny" | "ask", user_message, agent_message }.
16
+ * Common fields: workspace_roots, conversation_id, hook_event_name, ...
17
+ */
18
+ import type { ToolMapping } from '@weave_protocol/ward';
19
+ export type CursorEvent = 'beforeShellExecution' | 'beforeMCPExecution' | 'beforeReadFile' | 'preToolUse';
20
+ export declare const EVENTS: CursorEvent[];
21
+ export interface CursorHookInput {
22
+ hook_event_name?: string;
23
+ conversation_id?: string;
24
+ workspace_roots?: string[];
25
+ cwd?: string;
26
+ command?: string;
27
+ tool_name?: string;
28
+ tool_input?: unknown;
29
+ mcp_server_name?: string;
30
+ file_path?: string;
31
+ }
32
+ export interface CursorHookOutput {
33
+ permission?: 'allow' | 'deny' | 'ask';
34
+ user_message?: string;
35
+ agent_message?: string;
36
+ }
37
+ /**
38
+ * Cursor's tool names (preToolUse matcher values: Shell, Read, Write, Grep,
39
+ * Delete, Task). Write and Delete arguments aren't documented, so Ward checks
40
+ * every path-named argument they carry (file_path, path, target_file, ...).
41
+ */
42
+ export declare const TOOL_MAPPINGS: Record<string, ToolMapping>;
43
+ /** One hooks.json entry. */
44
+ export interface CursorHookEntry {
45
+ command: string;
46
+ type?: 'command' | 'prompt';
47
+ timeout?: number;
48
+ matcher?: string;
49
+ failClosed?: boolean;
50
+ }
51
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,MAAM,WAAW,GAAG,sBAAsB,GAAG,oBAAoB,GAAG,gBAAgB,GAAG,YAAY,CAAC;AAE1G,eAAO,MAAM,MAAM,EAAE,WAAW,EAAmF,CAAC;AAEpH,MAAM,WAAW,eAAe;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CASrD,CAAC;AAEF,4BAA4B;AAC5B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
package/dist/types.js ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Cursor agent hooks (https://cursor.com/docs/agent/hooks).
3
+ *
4
+ * One command is registered on four events and tells them apart by
5
+ * hook_event_name:
6
+ *
7
+ * beforeShellExecution { command, cwd } → Shell
8
+ * beforeMCPExecution { tool_name, tool_input (JSON string),
9
+ * mcp_server_name } → mcp__<server>__<tool>
10
+ * beforeReadFile { file_path } → Read
11
+ * preToolUse { tool_name, tool_input, cwd } → every other tool
12
+ * (Shell, Read and MCP:* are left to the events above,
13
+ * which carry richer fields)
14
+ *
15
+ * Output: { permission: "allow" | "deny" | "ask", user_message, agent_message }.
16
+ * Common fields: workspace_roots, conversation_id, hook_event_name, ...
17
+ */
18
+ export const EVENTS = ['beforeShellExecution', 'beforeMCPExecution', 'beforeReadFile', 'preToolUse'];
19
+ /**
20
+ * Cursor's tool names (preToolUse matcher values: Shell, Read, Write, Grep,
21
+ * Delete, Task). Write and Delete arguments aren't documented, so Ward checks
22
+ * every path-named argument they carry (file_path, path, target_file, ...).
23
+ */
24
+ export const TOOL_MAPPINGS = {
25
+ // cwd is where the command runs: checked as a read, like the other adapters' workdir
26
+ Shell: { capability: 'shell_exec', commandField: 'command', pathField: 'cwd', fsOp: 'read' },
27
+ Read: { capability: 'file_read', pathField: 'file_path', fsOp: 'read' },
28
+ Write: { capability: 'file_write', fsOp: 'write' },
29
+ Delete: { capability: 'file_delete', fsOp: 'delete' },
30
+ Grep: { capability: 'file_read', fsOp: 'read' },
31
+ Glob: { capability: 'file_list', fsOp: 'list' },
32
+ Task: { capability: 'subagent' },
33
+ };
34
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,MAAM,CAAC,MAAM,MAAM,GAAkB,CAAC,sBAAsB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,YAAY,CAAC,CAAC;AAuBpH;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAgC;IACxD,qFAAqF;IACrF,KAAK,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE;IAC5F,IAAI,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;IACvE,KAAK,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE;IAClD,MAAM,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE;IACrD,IAAI,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;IAC/C,IAAI,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;IAC/C,IAAI,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE;CACjC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,54 @@
1
1
  {
2
2
  "name": "@weave_protocol/adapter-cursor",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Weave Protocol adapter for Cursor - enforces WARD.md policies via Cursor's agent hooks",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "weave-ward-cursor": "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
+ "cursor",
21
+ "cursor-agent",
22
+ "agent-security",
23
+ "ai-security",
24
+ "hooks",
25
+ "harness-adapter",
26
+ "policy-enforcement",
27
+ "ward-md"
28
+ ],
29
+ "author": "Trent Yoxall",
30
+ "license": "Apache-2.0",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/Tyox-all/Weave_Protocol.git",
34
+ "directory": "adapter-cursor"
35
+ },
36
+ "homepage": "https://github.com/Tyox-all/Weave_Protocol/tree/main/adapter-cursor#readme",
37
+ "bugs": {
38
+ "url": "https://github.com/Tyox-all/Weave_Protocol/issues"
39
+ },
40
+ "dependencies": {
41
+ "@weave_protocol/ward": "^0.3.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^26.6.6",
45
+ "typescript": "^7.0.2"
46
+ },
47
+ "engines": {
48
+ "node": ">=18.0.0"
49
+ },
50
+ "files": [
51
+ "dist/",
52
+ "README.md"
53
+ ]
54
+ }