source dump of claude code
23
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 112 lines 3.3 kB view raw
1import axios from 'axios' 2import { readFile, stat } from 'fs/promises' 3import type { Message } from '../../types/message.js' 4import { checkAndRefreshOAuthTokenIfNeeded } from '../../utils/auth.js' 5import { logForDebugging } from '../../utils/debug.js' 6import { errorMessage } from '../../utils/errors.js' 7import { getAuthHeaders, getUserAgent } from '../../utils/http.js' 8import { normalizeMessagesForAPI } from '../../utils/messages.js' 9import { 10 extractAgentIdsFromMessages, 11 getTranscriptPath, 12 loadSubagentTranscripts, 13 MAX_TRANSCRIPT_READ_BYTES, 14} from '../../utils/sessionStorage.js' 15import { jsonStringify } from '../../utils/slowOperations.js' 16import { redactSensitiveInfo } from '../Feedback.js' 17 18type TranscriptShareResult = { 19 success: boolean 20 transcriptId?: string 21} 22 23export type TranscriptShareTrigger = 24 | 'bad_feedback_survey' 25 | 'good_feedback_survey' 26 | 'frustration' 27 | 'memory_survey' 28 29export async function submitTranscriptShare( 30 messages: Message[], 31 trigger: TranscriptShareTrigger, 32 appearanceId: string, 33): Promise<TranscriptShareResult> { 34 try { 35 logForDebugging('Collecting transcript for sharing', { level: 'info' }) 36 37 const transcript = normalizeMessagesForAPI(messages) 38 39 // Collect subagent transcripts 40 const agentIds = extractAgentIdsFromMessages(messages) 41 const subagentTranscripts = await loadSubagentTranscripts(agentIds) 42 43 // Read raw JSONL transcript (with size guard to prevent OOM) 44 let rawTranscriptJsonl: string | undefined 45 try { 46 const transcriptPath = getTranscriptPath() 47 const { size } = await stat(transcriptPath) 48 if (size <= MAX_TRANSCRIPT_READ_BYTES) { 49 rawTranscriptJsonl = await readFile(transcriptPath, 'utf-8') 50 } else { 51 logForDebugging( 52 `Skipping raw transcript read: file too large (${size} bytes)`, 53 { level: 'warn' }, 54 ) 55 } 56 } catch { 57 // File may not exist 58 } 59 60 const data = { 61 trigger, 62 version: MACRO.VERSION, 63 platform: process.platform, 64 transcript, 65 subagentTranscripts: 66 Object.keys(subagentTranscripts).length > 0 67 ? subagentTranscripts 68 : undefined, 69 rawTranscriptJsonl, 70 } 71 72 const content = redactSensitiveInfo(jsonStringify(data)) 73 74 await checkAndRefreshOAuthTokenIfNeeded() 75 76 const authResult = getAuthHeaders() 77 if (authResult.error) { 78 return { success: false } 79 } 80 81 const headers: Record<string, string> = { 82 'Content-Type': 'application/json', 83 'User-Agent': getUserAgent(), 84 ...authResult.headers, 85 } 86 87 const response = await axios.post( 88 'https://api.anthropic.com/api/claude_code_shared_session_transcripts', 89 { content, appearance_id: appearanceId }, 90 { 91 headers, 92 timeout: 30000, 93 }, 94 ) 95 96 if (response.status === 200 || response.status === 201) { 97 const result = response.data 98 logForDebugging('Transcript shared successfully', { level: 'info' }) 99 return { 100 success: true, 101 transcriptId: result?.transcript_id, 102 } 103 } 104 105 return { success: false } 106 } catch (err) { 107 logForDebugging(errorMessage(err), { 108 level: 'error', 109 }) 110 return { success: false } 111 } 112}