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 Caught from './caught' |
| 4 | import HeldVerdict from './held-verdict' |
| 5 | import { managedModsOnlyRefusal } from './managed-mods-only-refusal' |
| 6 | import PastUsers from './past-users' |
| 7 | import Policy from './policy' |
| 8 | import { quietly } from './quietly' |
| 9 | import { toolRegistered } from './tool-registered' |
| 10 | import { toolsListed } from './tools-listed' |
| 11 | |
| 12 | /** |
| 13 | * The built-in's hooks, seated outermost: each keeps one control an |
| 14 | * organization has today out of reach of the plugins a person installs. |
| 15 | * |
| 16 | * Three moves: continue past the user tier (`next.to(e, "append")`), refuse |
| 17 | * a user-tier caller or module by name, or pass. Provenance is the event's |
| 18 | * pinned `provider` or `tier`; policy is `$.settings.read`; fail closed. |
| 19 | * |
| 20 | * @param on the engine's registrar |
| 21 | */ |
| 22 | export function register(on: On) { |
| 23 | const readPolicy = Policy.createPolicyMemo(Policy.POLICY_MEMO_MS) |
| 24 | const told = new Set<string>() |
| 25 | const toldOfCeiling = new Set<string>() |
| 26 | |
| 27 | on('classic.*', ($, e, next) => next.to(e, 'append')).catch(($, e, next) => |
| 28 | Caught.pastUsersCaught(e, next), |
| 29 | ) |
| 30 | |
| 31 | on('prompt.section', ($, e, next) => next.to(e, 'append')) |
| 32 | on('prompt.context', ($, e, next) => next.to(e, 'append')) |
| 33 | on('prompt.compose', ($, e, next) => next.to(e, 'append')) |
| 34 | on('skill.prompt', ($, e, next) => next.to(e, 'append')) |
| 35 | on('attribution.text', ($, e, next) => next.to(e, 'append')) |
| 36 | |
| 37 | on('settings.read', ($, e, next) => next.to(e, 'append')).catch( |
| 38 | ($, e, next) => Caught.pastUsersCaught(e, next), |
| 39 | ) |
| 40 | |
| 41 | on('tool.describe', ($, e, next) => PastUsers.pastUsers(e, next)).catch( |
| 42 | ($, e, next) => Caught.providedCaught(e, next), |
| 43 | ) |
| 44 | |
| 45 | on('command.describe', ($, e, next) => PastUsers.pastUsers(e, next)).catch( |
| 46 | ($, e, next) => Caught.providedCaught(e, next), |
| 47 | ) |
| 48 | |
| 49 | on('agent.offer', ($, e, next) => PastUsers.pastUsers(e, next)).catch( |
| 50 | ($, e, next) => Caught.providedCaught(e, next), |
| 51 | ) |
| 52 | |
| 53 | on('agent.spawn', ($, e, next) => PastUsers.pastUsers(e, next)).catch( |
| 54 | ($, e, next) => Caught.providedCaught(e, next), |
| 55 | ) |
| 56 | |
| 57 | on('tool.register', ($, e, next) => |
| 58 | toolRegistered(e, next, () => |
| 59 | Policy.decidedByPolicy( |
| 60 | readPolicy(() => $.settings.read(Policy.SOURCE)), |
| 61 | Policy.hasMcpAllowlist, |
| 62 | ), |
| 63 | ), |
| 64 | ).catch(($, e, next) => |
| 65 | Caught.registerCaught(e, next, () => $.settings.read(Policy.SOURCE)), |
| 66 | ) |
| 67 | |
| 68 | on('tool.list', async ($, e, next) => |
| 69 | toolsListed( |
| 70 | await readPolicy(() => $.settings.read(Policy.SOURCE)).catch( |
| 71 | () => undefined, |
| 72 | ), |
| 73 | e, |
| 74 | next, |
| 75 | ), |
| 76 | ).catch(($, e, next) => Caught.pastUsersCaught(e, next)) |
| 77 | |
| 78 | on('tool.check', async ($, e, next) => { |
| 79 | const answer = await next(e) |
| 80 | const mods = HeldVerdict.loosenedByUsers(next.trace) |
| 81 | const lifters = HeldVerdict.liftedByUsers(next.trace, e.ceiling) |
| 82 | |
| 83 | const doRulesHold = |
| 84 | answer.decision !== 'deny' && |
| 85 | mods.length > 0 && |
| 86 | (await Policy.decidedByPolicy( |
| 87 | readPolicy(() => $.settings.read(Policy.SOURCE)), |
| 88 | Policy.denyRulesHold, |
| 89 | )) |
| 90 | |
| 91 | if (!doRulesHold && !HeldVerdict.isOverCeiling(answer, e.ceiling)) { |
| 92 | return answer |
| 93 | } |
| 94 | |
| 95 | const held = await next.to(e, 'append') |
| 96 | |
| 97 | if (doRulesHold && HeldVerdict.isRuleDeny(held)) { |
| 98 | for (const mod of HeldVerdict.untold(told, mods)) { |
| 99 | told.add(mod) |
| 100 | quietly(() => $.ui.log(HeldVerdict.heldNotice(mod, e.tool, held.rule))) |
| 101 | } |
| 102 | |
| 103 | return held |
| 104 | } |
| 105 | |
| 106 | if (!HeldVerdict.isCeilingHeld(answer, held, e.ceiling)) { |
| 107 | return answer |
| 108 | } |
| 109 | |
| 110 | for (const mod of HeldVerdict.untold(toldOfCeiling, lifters)) { |
| 111 | toldOfCeiling.add(mod) |
| 112 | quietly(() => $.ui.log(HeldVerdict.ceilingNotice(mod, e))) |
| 113 | } |
| 114 | |
| 115 | return held |
| 116 | }).catch(($, e, next) => |
| 117 | Caught.checkCaught(e, next, () => $.settings.read(Policy.SOURCE)), |
| 118 | ) |
| 119 | |
| 120 | on('ui.log', ($, e, next) => |
| 121 | PastUsers.USER_REACHABLE_TIERS.includes(next.origin.tier) |
| 122 | ? next(e) |
| 123 | : next.to(e, 'append'), |
| 124 | ).catch(($, e, next) => Caught.pastUsersCaught(e, next)) |
| 125 | |
| 126 | on('plugin.register', { tier: 'user' }, async ($, e, next) => |
| 127 | Policy.isManagedModsOnly(await $.settings.read(Policy.SOURCE)) |
| 128 | ? { refuse: managedModsOnlyRefusal(e.name) } |
| 129 | : next(e), |
| 130 | ).catch(($, e, next) => |
| 131 | Caught.admissionCaught(e, next, line => $.ui.log(line, { to: 'debug' })), |
| 132 | ) |
| 133 | } |