surshar / claude-code
Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.
Built by Anthropic · github.com/anthropics
| 1 | import type { On } from 'claude-code' |
| 2 | |
| 3 | import { admissionFailure } from './admission-failure' |
| 4 | import HeldVerdict from './held-verdict' |
| 5 | import { managedModsOnlyRefusal } from './managed-mods-only-refusal' |
| 6 | import { pastUsers } from './past-users' |
| 7 | import { pinnedVariableRefusal } from './pinned-variable-refusal' |
| 8 | import Policy from './policy' |
| 9 | import { isSkillRow } from './skill-row' |
| 10 | import { |
| 11 | registerRefusalOf, |
| 12 | TOOL_REGISTER_REFUSAL, |
| 13 | } from './tool-register-refusal' |
| 14 | |
| 15 | /** |
| 16 | * The built-in's hooks, seated outermost: each keeps one control an |
| 17 | * organization has today out of reach of the plugins a person installs. |
| 18 | * |
| 19 | * Three moves: continue past the user tier (`next.to(e, "append")`), refuse |
| 20 | * a user-tier caller or module by name, or pass. Provenance is the event's |
| 21 | * pinned `provider` or `tier`; policy is `$.settings.read`; fail closed. |
| 22 | * |
| 23 | * @param on the engine's registrar |
| 24 | */ |
| 25 | export function register(on: On) { |
| 26 | const readPolicy = Policy.createPolicyMemo(Policy.POLICY_MEMO_MS) |
| 27 | const told = new Set<string>() |
| 28 | const admittedAs = new Map<string, string>() |
| 29 | |
| 30 | on('classic.*', ($, e, next) => next.to(e, 'append')) |
| 31 | |
| 32 | on('prompt.section', ($, e, next) => next.to(e, 'append')) |
| 33 | on('prompt.context', ($, e, next) => next.to(e, 'append')) |
| 34 | on('prompt.attachment', ($, e, next) => next.to(e, 'append')) |
| 35 | on('prompt.compose', ($, e, next) => next.to(e, 'append')) |
| 36 | on('skill.prompt', ($, e, next) => next.to(e, 'append')) |
| 37 | on('attribution.text', ($, e, next) => next.to(e, 'append')) |
| 38 | |
| 39 | on('session.append', { door: 'attachment' }, ($, e, next) => |
| 40 | next.to(e, 'append'), |
| 41 | ) |
| 42 | on('session.append', { door: 'hook-context' }, ($, e, next) => |
| 43 | next.to(e, 'append'), |
| 44 | ) |
| 45 | on('session.append', { door: 'compaction' }, ($, e, next) => |
| 46 | next.to(e, 'append'), |
| 47 | ) |
| 48 | on('session.append', { door: 'tool-message' }, ($, e, next) => |
| 49 | isSkillRow(e) ? next.to(e, 'append') : next(e), |
| 50 | ) |
| 51 | on('session.append', { door: 'note' }, ($, e, next) => { |
| 52 | const isOrgs = |
| 53 | next.origin.tier === 'prepend' || next.origin.tier === 'append' |
| 54 | |
| 55 | return isOrgs ? next.to(e, 'append') : next(e) |
| 56 | }) |
| 57 | |
| 58 | on('session.compact', ($, e, next) => next.to(e, 'append')) |
| 59 | |
| 60 | on('settings.read', ($, e, next) => next.to(e, 'append')) |
| 61 | |
| 62 | on('tool.describe', ($, e, next) => pastUsers(e, next)) |
| 63 | on('command.describe', ($, e, next) => pastUsers(e, next)) |
| 64 | on('agent.offer', ($, e, next) => pastUsers(e, next)) |
| 65 | on('agent.spawn', ($, e, next) => pastUsers(e, next)) |
| 66 | |
| 67 | on('tool.register', async ($, e, next) => { |
| 68 | const isOrgs = |
| 69 | next.origin.tier === 'prepend' || next.origin.tier === 'append' |
| 70 | |
| 71 | if (isOrgs) { |
| 72 | return next.to(e, 'append') |
| 73 | } |
| 74 | |
| 75 | const refusal = |
| 76 | next.origin.tier === 'user' |
| 77 | ? await readPolicy(() => $.settings.read(Policy.SOURCE)) |
| 78 | .then(policy => |
| 79 | registerRefusalOf( |
| 80 | policy, |
| 81 | next.origin.plugin, |
| 82 | e.name, |
| 83 | admittedAs.get(next.origin.plugin), |
| 84 | ), |
| 85 | ) |
| 86 | .catch(() => TOOL_REGISTER_REFUSAL) |
| 87 | : undefined |
| 88 | |
| 89 | return refusal === undefined ? next(e) : { deny: refusal } |
| 90 | }) |
| 91 | |
| 92 | on('tool.list', async ($, e, next) => |
| 93 | Policy.managedToolsRestored( |
| 94 | await readPolicy(() => $.settings.read(Policy.SOURCE)).catch( |
| 95 | () => undefined, |
| 96 | ), |
| 97 | await next.to(e, 'append'), |
| 98 | await next(e), |
| 99 | ), |
| 100 | ) |
| 101 | |
| 102 | on('tool.check', async ($, e, next) => { |
| 103 | const answer = await next(e) |
| 104 | const mods = HeldVerdict.rewrittenByUsers(next.trace) |
| 105 | |
| 106 | const shouldRecheck = |
| 107 | mods.length > 0 && |
| 108 | (await Policy.decidedByPolicy( |
| 109 | readPolicy(() => $.settings.read(Policy.SOURCE)), |
| 110 | Policy.denyRulesHold, |
| 111 | )) |
| 112 | |
| 113 | if (!shouldRecheck) { |
| 114 | return answer |
| 115 | } |
| 116 | |
| 117 | const held = await next.to(e, 'append') |
| 118 | |
| 119 | const { approver }: { tool: string; approver?: string } = e |
| 120 | |
| 121 | if (!HeldVerdict.holdsOver(held, answer, approver)) { |
| 122 | return answer |
| 123 | } |
| 124 | |
| 125 | const kind = HeldVerdict.heldKind(held) |
| 126 | |
| 127 | for (const mod of mods.filter(name => !told.has(`${name} ${kind}`))) { |
| 128 | told.add(`${mod} ${kind}`) |
| 129 | $.ui.log( |
| 130 | HeldVerdict.heldNotice( |
| 131 | mod, |
| 132 | e.tool, |
| 133 | held, |
| 134 | HeldVerdict.isLooser(answer, held) ? 'lift' : 'reword', |
| 135 | ), |
| 136 | ) |
| 137 | } |
| 138 | |
| 139 | return held |
| 140 | }).catch(async ($, e, next) => { |
| 141 | const last = await next(e).catch(() => undefined) |
| 142 | |
| 143 | const shouldVouch = await Policy.decidedByPolicy( |
| 144 | readPolicy(() => $.settings.read(Policy.SOURCE)), |
| 145 | Policy.denyRulesHold, |
| 146 | ) |
| 147 | |
| 148 | return shouldVouch ? HeldVerdict.caughtAnswer(last, next.trace) : last |
| 149 | }) |
| 150 | |
| 151 | on('ui.log', ($, e, next) => { |
| 152 | const isOrgs = |
| 153 | next.origin.tier === 'prepend' || next.origin.tier === 'append' |
| 154 | |
| 155 | return isOrgs ? next.to(e, 'append') : next(e) |
| 156 | }) |
| 157 | |
| 158 | on('env.get', ($, e, next) => { |
| 159 | const isOrgs = |
| 160 | next.origin.tier === 'prepend' || next.origin.tier === 'append' |
| 161 | |
| 162 | return isOrgs ? next.to(e, 'append') : next(e) |
| 163 | }) |
| 164 | |
| 165 | on('env.set', async ($, e, next) => { |
| 166 | const isOrgs = |
| 167 | next.origin.tier === 'prepend' || next.origin.tier === 'append' |
| 168 | |
| 169 | if (isOrgs) { |
| 170 | return next.to(e, 'append') |
| 171 | } |
| 172 | |
| 173 | const isPinned = await Policy.decidedByPolicy( |
| 174 | readPolicy(() => $.settings.read(Policy.SOURCE)), |
| 175 | policy => Policy.isPinnedVariable(policy, e.name), |
| 176 | ) |
| 177 | |
| 178 | if (!isPinned) { |
| 179 | return next(e) |
| 180 | } |
| 181 | |
| 182 | const isTheirs = next.origin.tier === 'user' |
| 183 | |
| 184 | return isTheirs |
| 185 | ? { deny: pinnedVariableRefusal(e.name) } |
| 186 | : next.to(e, 'append') |
| 187 | }).catch(($, e, next) => { |
| 188 | if (next.called) { |
| 189 | return next(e) |
| 190 | } |
| 191 | |
| 192 | const isTheirs = next.origin.tier === 'user' |
| 193 | |
| 194 | return isTheirs |
| 195 | ? { deny: pinnedVariableRefusal(e.name) } |
| 196 | : next.to(e, 'append') |
| 197 | }) |
| 198 | |
| 199 | on('plugin.register', { tier: 'user' }, async ($, e, next) => { |
| 200 | admittedAs.set(e.name, e.provenance) |
| 201 | |
| 202 | return Policy.isManagedModsOnly(await $.settings.read(Policy.SOURCE)) |
| 203 | ? { refuse: managedModsOnlyRefusal(e.name) } |
| 204 | : next(e) |
| 205 | }).catch(($, e, next) => { |
| 206 | $.ui.log(admissionFailure(e.name, next.error), { to: 'debug' }) |
| 207 | |
| 208 | return next.called ? next(e) : { refuse: managedModsOnlyRefusal(e.name) } |
| 209 | }) |
| 210 | } |