@scopebond/hook 0.6.0 → 0.7.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 +87 -6
- package/dist/cli.d.ts +2 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +612 -70
- package/dist/cli.js.map +1 -1
- package/dist/cloud.d.ts +2 -0
- package/dist/cloud.d.ts.map +1 -1
- package/dist/cloud.js +1 -1
- package/dist/cloud.js.map +1 -1
- package/dist/explain.d.ts +44 -0
- package/dist/explain.d.ts.map +1 -0
- package/dist/explain.js +75 -0
- package/dist/explain.js.map +1 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +9 -3
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +35 -20
- package/dist/init.js.map +1 -1
- package/dist/install.d.ts +45 -2
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +158 -9
- package/dist/install.js.map +1 -1
- package/dist/map.d.ts +6 -0
- package/dist/map.d.ts.map +1 -1
- package/dist/map.js +4 -1
- package/dist/map.js.map +1 -1
- package/dist/rules.d.ts +51 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +216 -0
- package/dist/rules.js.map +1 -0
- package/dist/runtime-install.d.ts +25 -0
- package/dist/runtime-install.d.ts.map +1 -0
- package/dist/runtime-install.js +106 -0
- package/dist/runtime-install.js.map +1 -0
- package/dist/runtime.d.ts +13 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +52 -7
- package/dist/runtime.js.map +1 -1
- package/dist/version.d.ts +5 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +6 -2
- package/dist/version.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -60,6 +60,60 @@ countersigning key, a starter policy — "protect main and production paths" —
|
|
|
60
60
|
`.scopebond/receipts.db`. `init`, `trust` and `uninstall` are meant for a person at a
|
|
61
61
|
terminal: in a script or CI, pass `--yes`.
|
|
62
62
|
|
|
63
|
+
Check what it did with `npx @scopebond/hook status` (which agents are configured, in
|
|
64
|
+
which scope) and `npx @scopebond/hook doctor` (whether each configured command can
|
|
65
|
+
actually start).
|
|
66
|
+
|
|
67
|
+
### Changing the rules
|
|
68
|
+
|
|
69
|
+
`.scopebond/policy.json` is **generated**. The thing you edit is `.scopebond/rules.json`,
|
|
70
|
+
a short readable list, and `policy.json` is compiled from it — so a limit is a line in a
|
|
71
|
+
list, not a 700-character lookahead:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
npx @scopebond/hook rules # what is blocked, in plain English
|
|
75
|
+
npx @scopebond/hook rules allow dd # stop blocking a program
|
|
76
|
+
npx @scopebond/hook rules protect infra/ # never write there
|
|
77
|
+
npx @scopebond/hook rules protect-branch production
|
|
78
|
+
npx @scopebond/hook rules apply # recompile after editing rules.json by hand
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The compiled patterns are identical to the ones this package has always shipped — there
|
|
82
|
+
is a test that pins them against the starter policy — so the readable front end cannot
|
|
83
|
+
change what is enforced. Each clause description is generated from the list too, so it
|
|
84
|
+
stays true after an edit, and a block message quotes it.
|
|
85
|
+
|
|
86
|
+
### The hook command `init` installs
|
|
87
|
+
|
|
88
|
+
The hook runs once per tool call, so the command has to start fast. `init` copies this
|
|
89
|
+
package into `~/.scopebond/runtime/<version>/` once per machine and points your agent
|
|
90
|
+
at that absolute path. Measured on one Windows machine, through a shell, warm cache:
|
|
91
|
+
|
|
92
|
+
| Command in the agent config | Median per tool call |
|
|
93
|
+
|---|---|
|
|
94
|
+
| pinned absolute path (the default) | **151 ms** |
|
|
95
|
+
| `npx -y @scopebond/hook@<version>` | 1053 ms |
|
|
96
|
+
|
|
97
|
+
That ~900 ms is npm re-resolving a package already on disk, on every action. Pass
|
|
98
|
+
`--npx` to `init` if you would rather have the portable command, and `init` falls back
|
|
99
|
+
to it automatically when it cannot make a durable copy — slow beats broken. `doctor`
|
|
100
|
+
re-checks that the pinned paths still resolve, so a cleared home or a switched Node
|
|
101
|
+
version shows up as a problem rather than as a hook that silently cannot start.
|
|
102
|
+
|
|
103
|
+
### What each agent can actually stop
|
|
104
|
+
|
|
105
|
+
| | Claude Code | Cursor | Codex |
|
|
106
|
+
|---|---|---|---|
|
|
107
|
+
| Shell commands | prevented | prevented | prevented |
|
|
108
|
+
| File reads | prevented | prevented | prevented |
|
|
109
|
+
| MCP tool calls | prevented | prevented | prevented |
|
|
110
|
+
| File writes / edits | prevented | **recorded, not prevented** | prevented |
|
|
111
|
+
|
|
112
|
+
Cursor reports a file edit only *after* it is written (`afterFileEdit`; it has no
|
|
113
|
+
before-edit hook), so an out-of-policy edit there is signed and flagged, not blocked —
|
|
114
|
+
and the message says so rather than claiming otherwise. For edits that must be stopped
|
|
115
|
+
before they land, make `@scopebond/github-action` a required check on pull requests.
|
|
116
|
+
|
|
63
117
|
## Connect it to your workspace (optional)
|
|
64
118
|
|
|
65
119
|
To see the receipts in your hosted Scopebond workspace, create a connection from
|
|
@@ -82,8 +136,8 @@ can hand you a single copy-paste command with nothing to save.
|
|
|
82
136
|
|
|
83
137
|
From then on every receipt is mirrored to the workspace through a **durable outbox**:
|
|
84
138
|
delivery is best-effort and never blocks a tool call, and receipts are retained
|
|
85
|
-
locally and retried if the workspace is unreachable. `scopebond
|
|
86
|
-
anything still queued — run it on a session-end hook (and set
|
|
139
|
+
locally and retried if the workspace is unreachable. `npx @scopebond/hook flush`
|
|
140
|
+
delivers anything still queued — run it on a session-end hook (and set
|
|
87
141
|
`SCOPEBOND_HOOK_FLUSH_MS=0`) if you want zero per-call latency.
|
|
88
142
|
|
|
89
143
|
## How it works
|
|
@@ -91,14 +145,41 @@ anything still queued — run it on a session-end hook (and set
|
|
|
91
145
|
Each tool call is mapped to a normalized [Action Taxonomy](https://github.com/avouro-com/scopebond)
|
|
92
146
|
action (`shell.exec`, `git.push`, `file.write`, `mcp.tool.call`, …), signed by the
|
|
93
147
|
machine key and decided against your policy by an in-process check-only gateway.
|
|
94
|
-
An allowed action is recorded and
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
(deny) with a repair message.
|
|
148
|
+
An allowed action is recorded and the agent proceeds. A denied action is blocked.
|
|
149
|
+
Unknown tools are recorded as *not evaluated* and grant nothing — they fall through to
|
|
150
|
+
the coding agent's own permission prompt, so the hook never turns an unrecognised
|
|
151
|
+
action into an approval. Anything unexpected fails closed (deny) with a repair message.
|
|
152
|
+
|
|
153
|
+
**What a block says.** A denial names the action, the rule that decided, why that rule
|
|
154
|
+
exists (the clause's own description), the engine's technical detail and where to change
|
|
155
|
+
it. The same text goes to the agent, so it can choose another approach instead of
|
|
156
|
+
retrying a blocked call:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
Scopebond blocked git.push origin main — rule "protect-branches" (enforce).
|
|
160
|
+
Why: Deny pushes to main, master and release/* (any case, any refspec spelling), …
|
|
161
|
+
Detail: param ref fails pattern
|
|
162
|
+
Change the rule: edit clause "protect-branches" in /repo/.scopebond/policy.json
|
|
163
|
+
```
|
|
98
164
|
|
|
99
165
|
Commands are stored as a scrubbed head plus a digest; file contents are never
|
|
100
166
|
stored; common secret shapes are removed before signing.
|
|
101
167
|
|
|
168
|
+
**Where receipts live, and how much room they take.** `.scopebond/receipts.db` in the
|
|
169
|
+
project, roughly 25 KiB per tool call. Nothing is ever deleted automatically — these are
|
|
170
|
+
your evidence — so `status` reports the count and size, and `prune` bounds it when you
|
|
171
|
+
choose to:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
npx @scopebond/hook prune # report the footprint
|
|
175
|
+
npx @scopebond/hook prune --before 90d --yes # archive, then remove, anything older
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`prune` writes the receipts it will remove to a JSONL file beside the database first, so
|
|
179
|
+
they stay verifiable, and it refuses outright once the log has been anchored — a receipt's
|
|
180
|
+
position is its anchor leaf index, so removing one would make an existing anchor
|
|
181
|
+
unverifiable.
|
|
182
|
+
|
|
102
183
|
**What a shell command is checked for.** A command line is split into every command it
|
|
103
184
|
runs (`&&`, `;`, pipes, `$( )` and backticks — also inside double quotes — `bash -c`,
|
|
104
185
|
`eval`, `trap`, `su -c`, `script -c`, `watch`, `parallel`, `cmd /c`, `pwsh -Command`
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA8fA,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,GAAG,IAAI,CAS7F"}
|