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 { |
| 2 | CommandRunInput, |
| 3 | On, |
| 4 | PromptSectionInput, |
| 5 | SessionStartInput, |
| 6 | Settings, |
| 7 | ToolInfo, |
| 8 | } from 'claude-code' |
| 9 | import type { Plugin } from 'claude-code/testing' |
| 10 | import { expect, test, tier } from 'claude-code/testing' |
| 11 | |
| 12 | tier('prepend') |
| 13 | |
| 14 | const SESSION: SessionStartInput = { |
| 15 | surface: 'terminal', |
| 16 | isInteractive: true, |
| 17 | cwd: '/work', |
| 18 | } |
| 19 | const TOOLS_COMMAND: CommandRunInput = { |
| 20 | command: 'tools', |
| 21 | args: '', |
| 22 | origin: { kind: 'composer' }, |
| 23 | } |
| 24 | const ALLOWLIST: Settings = { allowedMcpServers: [{ serverName: 'corp' }] } |
| 25 | const NO_ALLOWLIST: Settings = { permissions: { allow: [] } } |
| 26 | const MEMORY: PromptSectionInput = { name: 'memory', text: 'the org says hi' } |
| 27 | const TOOLS: ToolInfo[] = [ |
| 28 | { |
| 29 | name: 'mcp__corp__search', |
| 30 | description: 'Searches the corp wiki.', |
| 31 | mcp: true, |
| 32 | }, |
| 33 | { name: 'Bash', description: 'Runs a command.', mcp: false }, |
| 34 | ] |
| 35 | |
| 36 | /** |
| 37 | * A plugin that registers a tool when the session starts, in the tier |
| 38 | * given: the person's own by default. |
| 39 | */ |
| 40 | const registering = (name: string, tier?: Plugin['tier']): Plugin => ({ |
| 41 | name, |
| 42 | tier, |
| 43 | register(on) { |
| 44 | on('session.start', async ($, e, next) => { |
| 45 | await $.tool.register({ |
| 46 | name: 'greet', |
| 47 | description: 'Says hello.', |
| 48 | inputSchema: { type: 'object' }, |
| 49 | }) |
| 50 | |
| 51 | return next(e) |
| 52 | }) |
| 53 | }, |
| 54 | }) |
| 55 | |
| 56 | /** |
| 57 | * A session starting, where each tool a plugin asks for is registered and |
| 58 | * kept by the name of the plugin that asked. |
| 59 | */ |
| 60 | function toolsRegistered(on: On) { |
| 61 | const registered: string[] = [] |
| 62 | on('session.start', ($, e) => ({ cwd: e.cwd })) |
| 63 | on('tool.register', ($, e, next) => { |
| 64 | registered.push(next.origin.plugin) |
| 65 | |
| 66 | return { value: { tool: `mcp__plugin_${next.origin.plugin}__${e.name}` } } |
| 67 | }) |
| 68 | |
| 69 | return registered |
| 70 | } |
| 71 | |
| 72 | /** |
| 73 | * A plugin the person installed that hides the organization's tools from |
| 74 | * the listing and relabels every other one. |
| 75 | */ |
| 76 | const relabeling: Plugin = { |
| 77 | name: 'relabeling', |
| 78 | register(on) { |
| 79 | on('tool.list', async ($, e, next) => { |
| 80 | const listed = await next(e) |
| 81 | |
| 82 | return listed.value === undefined |
| 83 | ? listed |
| 84 | : { |
| 85 | value: listed.value |
| 86 | .filter(tool => !tool.name.startsWith('mcp__corp__')) |
| 87 | .map(tool => ({ ...tool, description: 'relabeled' })), |
| 88 | } |
| 89 | }) |
| 90 | }, |
| 91 | } |
| 92 | |
| 93 | /** |
| 94 | * A plugin whose `/tools` answers the tool listing it reads, one |
| 95 | * `name: description` line per tool. |
| 96 | */ |
| 97 | const listing: Plugin = { |
| 98 | name: 'listing', |
| 99 | register(on) { |
| 100 | on('command.run', { command: 'tools' }, async $ => ({ |
| 101 | text: (await $.tool.list()) |
| 102 | .map(tool => `${tool.name}: ${tool.description}`) |
| 103 | .join('\n'), |
| 104 | })) |
| 105 | }, |
| 106 | } |
| 107 | |
| 108 | /** |
| 109 | * A plugin the person installed that drops the memory section. |
| 110 | */ |
| 111 | const dropping: Plugin = { |
| 112 | name: 'dropping', |
| 113 | register(on) { |
| 114 | on('prompt.section', () => ({ text: null })) |
| 115 | }, |
| 116 | } |
| 117 | |
| 118 | /** |
| 119 | * The organization's own plugin, in its last tier, which signs the section. |
| 120 | */ |
| 121 | const signing: Plugin = { |
| 122 | name: 'signing', |
| 123 | tier: 'append', |
| 124 | register(on) { |
| 125 | on('prompt.section', ($, e, next) => |
| 126 | next({ ...e, text: `${e.text} (signed)` }), |
| 127 | ) |
| 128 | }, |
| 129 | } |
| 130 | |
| 131 | test( |
| 132 | 'under an MCP allowlist a plugin the person installed may not add a tool', |
| 133 | { plugins: [registering('mine'), registering('bundled', 'builtin')] }, |
| 134 | async ($, on) => { |
| 135 | on('settings.read', () => ({ value: ALLOWLIST })) |
| 136 | const registered = toolsRegistered(on) |
| 137 | |
| 138 | await $.session.start(SESSION) |
| 139 | |
| 140 | expect(registered).toEqual(['bundled']) |
| 141 | }, |
| 142 | ) |
| 143 | |
| 144 | test( |
| 145 | 'with no allowlist, a plugin the person installed adds its tool', |
| 146 | { plugins: [registering('mine')] }, |
| 147 | async ($, on) => { |
| 148 | on('settings.read', () => ({ value: NO_ALLOWLIST })) |
| 149 | const registered = toolsRegistered(on) |
| 150 | |
| 151 | await $.session.start(SESSION) |
| 152 | |
| 153 | expect(registered).toEqual(['mine']) |
| 154 | }, |
| 155 | ) |
| 156 | |
| 157 | test( |
| 158 | 'a policy that cannot be read counts as one in force', |
| 159 | { plugins: [registering('mine')] }, |
| 160 | async ($, on) => { |
| 161 | on('settings.read', () => ({ deny: 'managed settings unreadable' })) |
| 162 | const registered = toolsRegistered(on) |
| 163 | |
| 164 | await $.session.start(SESSION) |
| 165 | |
| 166 | expect(registered).toEqual([]) |
| 167 | }, |
| 168 | ) |
| 169 | |
| 170 | test( |
| 171 | 'the organization tools are listed as its tiers listed them', |
| 172 | { plugins: [relabeling, listing] }, |
| 173 | async ($, on) => { |
| 174 | on('settings.read', () => ({ value: ALLOWLIST })) |
| 175 | on('tool.list', () => ({ value: TOOLS })) |
| 176 | |
| 177 | const { text } = await $.command.run(TOOLS_COMMAND) |
| 178 | |
| 179 | expect(text?.split('\n')).toEqual([ |
| 180 | 'mcp__corp__search: Searches the corp wiki.', |
| 181 | 'Bash: relabeled', |
| 182 | ]) |
| 183 | }, |
| 184 | ) |
| 185 | |
| 186 | test( |
| 187 | 'a prompt section skips the plugins the person installed, never the organization ones', |
| 188 | { plugins: [dropping, signing] }, |
| 189 | async ($, on) => { |
| 190 | on('prompt.section', ($, e) => ({ text: e.text })) |
| 191 | |
| 192 | expect(await $.prompt.section(MEMORY)).toEqual({ |
| 193 | text: 'the org says hi (signed)', |
| 194 | }) |
| 195 | }, |
| 196 | ) |