source dump of claude code
at main 161 lines 4.7 kB view raw
1import axios from 'axios' 2import { z } from 'zod/v4' 3import { getOauthConfig } from '../../constants/oauth.js' 4import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' 5import { getOrganizationUUID } from '../../services/oauth/client.js' 6import { isPolicyAllowed } from '../../services/policyLimits/index.js' 7import type { ToolUseContext } from '../../Tool.js' 8import { buildTool, type ToolDef } from '../../Tool.js' 9import { 10 checkAndRefreshOAuthTokenIfNeeded, 11 getClaudeAIOAuthTokens, 12} from '../../utils/auth.js' 13import { lazySchema } from '../../utils/lazySchema.js' 14import { jsonStringify } from '../../utils/slowOperations.js' 15import { DESCRIPTION, PROMPT, REMOTE_TRIGGER_TOOL_NAME } from './prompt.js' 16import { renderToolResultMessage, renderToolUseMessage } from './UI.js' 17 18const inputSchema = lazySchema(() => 19 z.strictObject({ 20 action: z.enum(['list', 'get', 'create', 'update', 'run']), 21 trigger_id: z 22 .string() 23 .regex(/^[\w-]+$/) 24 .optional() 25 .describe('Required for get, update, and run'), 26 body: z 27 .record(z.string(), z.unknown()) 28 .optional() 29 .describe('JSON body for create and update'), 30 }), 31) 32type InputSchema = ReturnType<typeof inputSchema> 33export type Input = z.infer<InputSchema> 34 35const outputSchema = lazySchema(() => 36 z.object({ 37 status: z.number(), 38 json: z.string(), 39 }), 40) 41type OutputSchema = ReturnType<typeof outputSchema> 42export type Output = z.infer<OutputSchema> 43 44const TRIGGERS_BETA = 'ccr-triggers-2026-01-30' 45 46export const RemoteTriggerTool = buildTool({ 47 name: REMOTE_TRIGGER_TOOL_NAME, 48 searchHint: 'manage scheduled remote agent triggers', 49 maxResultSizeChars: 100_000, 50 shouldDefer: true, 51 get inputSchema(): InputSchema { 52 return inputSchema() 53 }, 54 get outputSchema(): OutputSchema { 55 return outputSchema() 56 }, 57 isEnabled() { 58 return ( 59 getFeatureValue_CACHED_MAY_BE_STALE('tengu_surreal_dali', false) && 60 isPolicyAllowed('allow_remote_sessions') 61 ) 62 }, 63 isConcurrencySafe() { 64 return true 65 }, 66 isReadOnly(input: Input) { 67 return input.action === 'list' || input.action === 'get' 68 }, 69 toAutoClassifierInput(input: Input) { 70 return `RemoteTrigger ${input.action}${input.trigger_id ? ` ${input.trigger_id}` : ''}` 71 }, 72 async description() { 73 return DESCRIPTION 74 }, 75 async prompt() { 76 return PROMPT 77 }, 78 async call(input: Input, context: ToolUseContext) { 79 await checkAndRefreshOAuthTokenIfNeeded() 80 const accessToken = getClaudeAIOAuthTokens()?.accessToken 81 if (!accessToken) { 82 throw new Error( 83 'Not authenticated with a claude.ai account. Run /login and try again.', 84 ) 85 } 86 const orgUUID = await getOrganizationUUID() 87 if (!orgUUID) { 88 throw new Error('Unable to resolve organization UUID.') 89 } 90 91 const base = `${getOauthConfig().BASE_API_URL}/v1/code/triggers` 92 const headers = { 93 Authorization: `Bearer ${accessToken}`, 94 'Content-Type': 'application/json', 95 'anthropic-version': '2023-06-01', 96 'anthropic-beta': TRIGGERS_BETA, 97 'x-organization-uuid': orgUUID, 98 } 99 100 const { action, trigger_id, body } = input 101 let method: 'GET' | 'POST' 102 let url: string 103 let data: unknown 104 switch (action) { 105 case 'list': 106 method = 'GET' 107 url = base 108 break 109 case 'get': 110 if (!trigger_id) throw new Error('get requires trigger_id') 111 method = 'GET' 112 url = `${base}/${trigger_id}` 113 break 114 case 'create': 115 if (!body) throw new Error('create requires body') 116 method = 'POST' 117 url = base 118 data = body 119 break 120 case 'update': 121 if (!trigger_id) throw new Error('update requires trigger_id') 122 if (!body) throw new Error('update requires body') 123 method = 'POST' 124 url = `${base}/${trigger_id}` 125 data = body 126 break 127 case 'run': 128 if (!trigger_id) throw new Error('run requires trigger_id') 129 method = 'POST' 130 url = `${base}/${trigger_id}/run` 131 data = {} 132 break 133 } 134 135 const res = await axios.request({ 136 method, 137 url, 138 headers, 139 data, 140 timeout: 20_000, 141 signal: context.abortController.signal, 142 validateStatus: () => true, 143 }) 144 145 return { 146 data: { 147 status: res.status, 148 json: jsonStringify(res.data), 149 }, 150 } 151 }, 152 mapToolResultToToolResultBlockParam(output, toolUseID) { 153 return { 154 tool_use_id: toolUseID, 155 type: 'tool_result', 156 content: `HTTP ${output.status}\n${output.json}`, 157 } 158 }, 159 renderToolUseMessage, 160 renderToolResultMessage, 161} satisfies ToolDef<InputSchema, Output>)