Prerequisiti

  • Node.js 18+

Installazione

Installa @anthropic-ai/claude-code da NPM:

npm install -g @anthropic-ai/claude-code

Per visualizzare il codice sorgente dell’SDK TypeScript, visita la pagina @anthropic-ai/claude-code su NPM.

Utilizzo di base

L’interfaccia principale tramite l’SDK TypeScript è la funzione query, che restituisce un iteratore asincrono che trasmette i messaggi man mano che arrivano:

import { query } from "@anthropic-ai/claude-code";

for await (const message of query({
  prompt: "Analizza le prestazioni del sistema",
  options: {
    maxTurns: 5,
    appendSystemPrompt: "Sei un ingegnere delle prestazioni",
    allowedTools: ["Bash", "Read", "WebSearch"],
    abortController: new AbortController(),
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}

Opzioni di configurazione

ArgomentoTipoDescrizionePredefinito
abortControllerAbortControllerController di interruzione per annullare le operazioninew AbortController()
additionalDirectoriesstring[]Directory aggiuntive da includere nella sessioneundefined
allowedToolsstring[]Elenco di strumenti che Claude può utilizzareTutti gli strumenti abilitati per impostazione predefinita
appendSystemPromptstringTesto da aggiungere al prompt di sistema predefinitoundefined
canUseTool(toolName: string, input: any) => Promise<ToolPermissionResult>Funzione di autorizzazione personalizzata per l’uso degli strumentiundefined
continuebooleanContinua la sessione più recentefalse
customSystemPromptstringSostituisce completamente il prompt di sistema predefinitoundefined
cwdstringDirectory di lavoro correnteprocess.cwd()
disallowedToolsstring[]Elenco di strumenti che Claude non può utilizzareundefined
envDict<string>Variabili d’ambiente da impostareundefined
executable'bun' | 'deno' | 'node'Quale runtime JavaScript utilizzarenode quando si esegue con Node.js, bun quando si esegue con Bun
executableArgsstring[]Argomenti da passare all’eseguibile[]
fallbackModelstringModello da utilizzare se il modello primario fallisceundefined
hooksPartial<Record<HookEvent, HookCallbackMatcher[]>>Hook del ciclo di vita per la personalizzazioneundefined
includePartialMessagesbooleanIncludi eventi di streaming parziali nel flusso dei messaggifalse
maxThinkingTokensnumberToken massimi per il processo di pensiero di Claudeundefined
maxTurnsnumberNumero massimo di turni di conversazioneundefined
mcpServersRecord<string, McpServerConfig>Configurazioni del server MCPundefined
modelstringModello Claude da utilizzareUtilizza il predefinito dalla configurazione CLI
pathToClaudeCodeExecutablestringPercorso dell’eseguibile Claude CodeEseguibile fornito con @anthropic-ai/claude-code
permissionModePermissionModeModalità di autorizzazione per la sessione"default" (opzioni: "default", "acceptEdits", "bypassPermissions", "plan")
resumestringID sessione da riprendereundefined
stderr(data: string) => voidCallback per l’output stderrundefined
strictMcpConfigbooleanApplica la validazione rigorosa della configurazione MCPundefined

Streaming di messaggi parziali

Quando includePartialMessages è abilitato, l’SDK emetterà messaggi stream_event che contengono eventi di streaming grezzi dall’API Claude. Questo ti consente di accedere al contenuto parziale mentre viene generato, utile per implementare aggiornamenti dell’interfaccia utente in tempo reale o indicatori di progresso.

import { query } from "@anthropic-ai/claude-code";

for await (const message of query({
  prompt: "Scrivi un lungo saggio sull'intelligenza artificiale",
  options: {
    includePartialMessages: true,
    maxTurns: 1
  }
})) {
  // Gestisci eventi di streaming parziali
  if (message.type === "stream_event") {
    const event = message.event;
    
    // Accedi al testo parziale mentre viene trasmesso
    if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
      process.stdout.write(event.delta.text);
    }
    
    // Traccia il progresso del pensiero
    if (event.type === "content_block_start" && event.content_block.type === "thinking") {
      console.log("\n[Claude sta pensando...]");
    }
  }
  
  // Ottieni comunque il risultato finale
  if (message.type === "result" && message.subtype === "success") {
    console.log("\nRisultato finale:", message.result);
  }
}

Ogni messaggio stream_event include:

  • event: L’evento di streaming grezzo dall’API
  • session_id: L’identificatore della sessione corrente
  • parent_tool_use_id: L’ID dello strumento in esecuzione (se applicabile)
  • uuid: Un identificatore univoco per questo evento

Lo streaming di messaggi parziali è principalmente utile per casi d’uso avanzati dove hai bisogno di controllo granulare sulla risposta in streaming. Per la maggior parte delle applicazioni, il comportamento predefinito (aspettare messaggi completi) è sufficiente.

Conversazioni multi-turno

Per conversazioni multi-turno, hai due opzioni.

Puoi generare risposte e riprenderle, oppure puoi utilizzare la modalità di input in streaming che accetta un async/generator per un array di messaggi. Per ora, la modalità di input in streaming è l’unico modo per allegare immagini tramite messaggi.

Riprendi con gestione della sessione

import { query } from "@anthropic-ai/claude-code";

// Continua la conversazione più recente
for await (const message of query({
  prompt: "Ora refactorizza questo per migliori prestazioni",
  options: { continue: true }
})) { 
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

// Riprendi sessione specifica
for await (const message of query({
  prompt: "Aggiorna i test",
  options: {
    resume: "550e8400-e29b-41d4-a716-446655440000",
    maxTurns: 3
  }
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Modalità di input in streaming

La modalità di input in streaming ti consente di fornire messaggi come un iterabile asincrono invece di una singola stringa. Questo abilita conversazioni multi-turno, allegati di immagini e generazione dinamica di messaggi:

import { query } from "@anthropic-ai/claude-code";

// Crea un generatore asincrono per lo streaming dei messaggi
async function* generateMessages() {
  yield {
    type: "user" as const,
    message: {
      role: "user" as const,
      content: "Inizia ad analizzare questa codebase"
    }
  };
  
  // Aspetta qualche condizione o input dell'utente
  await new Promise(resolve => setTimeout(resolve, 1000));
  
  yield {
    type: "user" as const,
    message: {
      role: "user" as const,
      content: "Ora concentrati sul modulo di autenticazione"
    }
  };
}

// Utilizza input in streaming
for await (const message of query({
  prompt: generateMessages(),
  options: {
    maxTurns: 5,
    allowedTools: ["Read", "Grep", "Bash"]
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}

Input in streaming con immagini

La modalità di input in streaming è l’unico modo per allegare immagini tramite messaggi:

import { query } from "@anthropic-ai/claude-code";
import { readFileSync } from "fs";

async function* messagesWithImage() {
  // Invia un'immagine con testo
  yield {
    type: "user" as const,
    message: {
      role: "user" as const,
      content: [
        {
          type: "text",
          text: "Analizza questo screenshot e suggerisci miglioramenti"
        },
        {
          type: "image",
          source: {
            type: "base64",
            media_type: "image/png",
            data: readFileSync("screenshot.png", "base64")
          }
        }
      ]
    }
  };
}

for await (const message of query({
  prompt: messagesWithImage()
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Prompt di sistema personalizzati

I prompt di sistema definiscono il ruolo, l’expertise e il comportamento del tuo agente:

import { query } from "@anthropic-ai/claude-code";

// Agente di risposta agli incidenti SRE
for await (const message of query({
  prompt: "L'API è down, investiga",
  options: {
    customSystemPrompt: "Sei un esperto SRE. Diagnostica i problemi sistematicamente e fornisci soluzioni attuabili.",
    maxTurns: 3
  }
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

// Aggiungi al prompt di sistema predefinito
for await (const message of query({
  prompt: "Refactorizza questa funzione",
  options: {
    appendSystemPrompt: "Includi sempre gestione completa degli errori e test unitari.",
    maxTurns: 2
  }
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Integrazione del server MCP

Il Model Context Protocol (MCP) ti consente di dare ai tuoi agenti strumenti e capacità personalizzati:

import { query } from "@anthropic-ai/claude-code";

// Agente SRE con strumenti di monitoraggio
for await (const message of query({
  prompt: "Investiga l'interruzione del servizio di pagamento",
  options: {
    mcpConfig: "sre-tools.json",
    allowedTools: ["mcp__datadog", "mcp__pagerduty", "mcp__kubernetes"],
    appendSystemPrompt: "Sei un SRE. Utilizza i dati di monitoraggio per diagnosticare i problemi.",
    maxTurns: 4
  }
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Strumenti personalizzati con server MCP in-process

I server SDK MCP ti consentono di creare strumenti personalizzati che vengono eseguiti direttamente nel processo della tua applicazione, fornendo esecuzione di strumenti type-safe senza l’overhead di processi separati o comunicazione di rete.

Creazione di strumenti personalizzati

Utilizza le funzioni helper createSdkMcpServer e tool per definire strumenti personalizzati type-safe:

import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-code";
import { z } from "zod";

// Crea un server SDK MCP con strumenti personalizzati
const customServer = createSdkMcpServer({
  name: "my-custom-tools",
  version: "1.0.0",
  tools: [
    tool(
      "calculate_compound_interest",
      "Calcola l'interesse composto per un investimento",
      {
        principal: z.number().describe("Importo dell'investimento iniziale"),
        rate: z.number().describe("Tasso di interesse annuale (come decimale, es. 0.05 per 5%)"),
        time: z.number().describe("Periodo di investimento in anni"),
        n: z.number().default(12).describe("Frequenza di capitalizzazione per anno")
      },
      async (args) => {
        const amount = args.principal * Math.pow(1 + args.rate / args.n, args.n * args.time);
        const interest = amount - args.principal;
        
        return {
          content: [{
            type: "text",
            text: `Importo finale: $${amount.toFixed(2)}\nInteressi guadagnati: $${interest.toFixed(2)}`
          }]
        };
      }
    ),
    tool(
      "fetch_user_data",
      "Recupera i dati utente dal database della tua applicazione",
      {
        userId: z.string().describe("L'ID utente da recuperare"),
        fields: z.array(z.string()).optional().describe("Campi specifici da restituire")
      },
      async (args) => {
        // Accesso diretto al livello dati della tua applicazione
        const userData = await myDatabase.getUser(args.userId, args.fields);
        
        return {
          content: [{
            type: "text",
            text: JSON.stringify(userData, null, 2)
          }]
        };
      }
    )
  ]
});

// Utilizza gli strumenti personalizzati nella tua query
for await (const message of query({
  prompt: "Calcola l'interesse composto per $10.000 al 5% per 10 anni",
  options: {
    mcpServers: {
      "my-custom-tools": customServer
    },
    maxTurns: 3
  }
})) {
  if (message.type === "result") {
    console.log(message.result);
  }
}

Type safety con Zod

L’helper tool fornisce inferenza completa dei tipi TypeScript dai tuoi schemi Zod:

tool(
  "process_data",
  "Elabora dati strutturati con type safety",
  {
    // Lo schema Zod definisce sia la validazione runtime che i tipi TypeScript
    data: z.object({
      name: z.string(),
      age: z.number().min(0).max(150),
      email: z.string().email(),
      preferences: z.array(z.string()).optional()
    }),
    format: z.enum(["json", "csv", "xml"]).default("json")
  },
  async (args) => {
    // args è completamente tipizzato basato sullo schema
    // TypeScript sa: args.data.name è string, args.data.age è number, ecc.
    console.log(`Elaborando i dati di ${args.data.name} come ${args.format}`);
    
    // La tua logica di elaborazione qui
    return {
      content: [{
        type: "text",
        text: `Dati elaborati per ${args.data.name}`
      }]
    };
  }
)

Hook

Gli hook ti consentono di personalizzare ed estendere il comportamento di Claude Code eseguendo callback personalizzati in vari punti del ciclo di vita dell’agente. A differenza degli hook CLI che eseguono comandi bash, gli hook SDK sono funzioni JavaScript/TypeScript che vengono eseguite in-process.

Definizione degli hook

Gli hook sono organizzati per tipo di evento, con matcher opzionali per filtrare quando vengono eseguiti:

import { query } from "@anthropic-ai/claude-code";

for await (const message of query({
  prompt: "Analizza la codebase",
  options: {
    hooks: {
      PreToolUse: [
        {
          matcher: "Write",
          hooks: [
            async (input, toolUseId, { signal }) => {
              console.log(`Sto per scrivere il file: ${input.tool_input.file_path}`);
              
              // Valida l'operazione
              if (input.tool_input.file_path.includes('.env')) {
                return {
                  decision: 'block',
                  stopReason: 'Non posso scrivere nei file di ambiente'
                };
              }
              
              // Consenti l'operazione
              return { continue: true };
            }
          ]
        }
      ],
      PostToolUse: [
        {
          matcher: "Write|Edit",
          hooks: [
            async (input, toolUseId, { signal }) => {
              console.log(`File modificato: ${input.tool_response.filePath}`);
              // Esegui la tua formattazione o validazione personalizzata
              return { continue: true };
            }
          ]
        }
      ]
    }
  }
})) {
  if (message.type === "result") console.log(message.result);
}

Eventi hook disponibili

  • PreToolUse: Viene eseguito prima dell’esecuzione dello strumento. Può bloccare strumenti o fornire feedback.
  • PostToolUse: Viene eseguito dopo l’esecuzione riuscita dello strumento.
  • UserPromptSubmit: Viene eseguito quando l’utente invia un prompt.
  • SessionStart: Viene eseguito quando inizia una sessione.
  • SessionEnd: Viene eseguito quando termina una sessione.
  • Stop: Viene eseguito quando Claude sta per smettere di rispondere.
  • SubagentStop: Viene eseguito quando un subagente sta per fermarsi.
  • PreCompact: Viene eseguito prima della compattazione della conversazione.
  • Notification: Viene eseguito quando vengono inviate notifiche.

Tipi di input degli hook

Ogni hook riceve input tipizzato basato sull’evento:

// Input PreToolUse
type PreToolUseHookInput = {
  hook_event_name: 'PreToolUse';
  session_id: string;
  transcript_path: string;
  cwd: string;
  permission_mode?: string;
  tool_name: string;
  tool_input: unknown;
}

// Input PostToolUse
type PostToolUseHookInput = {
  hook_event_name: 'PostToolUse';
  session_id: string;
  transcript_path: string;
  cwd: string;
  permission_mode?: string;
  tool_name: string;
  tool_input: unknown;
  tool_response: unknown;
}

Output degli hook

Gli hook restituiscono output che controlla il flusso di esecuzione:

interface HookJSONOutput {
  // Continua l'esecuzione (predefinito: true)
  continue?: boolean;
  
  // Sopprimi output all'utente
  suppressOutput?: boolean;
  
  // Motivo di arresto (mostrato al modello)
  stopReason?: string;
  
  // Decisione per hook PreToolUse
  decision?: 'approve' | 'block';
  
  // Messaggio di sistema da mostrare
  systemMessage?: string;
  
  // Output specifico dell'hook
  hookSpecificOutput?: {
    // Per PreToolUse
    permissionDecision?: 'allow' | 'deny' | 'ask';
    permissionDecisionReason?: string;
    
    // Per UserPromptSubmit o PostToolUse
    additionalContext?: string;
  };
}

Esempi pratici

Logging e monitoraggio

const hooks = {
  PreToolUse: [
    {
      hooks: [
        async (input) => {
          // Registra tutto l'uso degli strumenti
          await logToMonitoring({
            event: 'tool_use',
            tool: input.tool_name,
            input: input.tool_input,
            session: input.session_id
          });
          
          return { continue: true };
        }
      ]
    }
  ]
};

Validazione delle operazioni sui file

const hooks = {
  PreToolUse: [
    {
      matcher: "Write|Edit",
      hooks: [
        async (input) => {
          const filePath = input.tool_input.file_path;
          
          // Blocca file sensibili
          const sensitivePatterns = ['.env', '.git/', 'secrets/', '*.key'];
          
          for (const pattern of sensitivePatterns) {
            if (filePath.includes(pattern)) {
              return {
                decision: 'block',
                stopReason: `Non posso modificare file sensibili che corrispondono a ${pattern}`
              };
            }
          }
          
          return { continue: true };
        }
      ]
    }
  ]
};

Formattazione automatica del codice

import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

const hooks =  {
  PostToolUse: [
    {
      matcher: "Write|Edit|MultiEdit",
      hooks: [
        async (input) => {
          const filePath = input.tool_response.filePath;
          
          // Formattazione automatica basata sul tipo di file
          if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
            await execAsync(`prettier --write "${filePath}"`);
          } else if (filePath.endsWith('.py')) {
            await execAsync(`black "${filePath}"`);
          }
          
          return { continue: true };
        }
      ]
    }
  ]
};

Miglioramento dei prompt

const hooks = {
  UserPromptSubmit: [
    {
      hooks: [
        async (input) => {
          // Aggiungi contesto ai prompt
          const projectContext = await loadProjectContext();
          
          return {
            continue: true,
            hookSpecificOutput: {
              hookEventName: 'UserPromptSubmit',
              additionalContext: `Contesto del progetto: ${projectContext}`
            }
          };
        }
      ]
    }
  ]
};

Istruzioni di compattazione personalizzate

const hooks = {
  PreCompact: [
    {
      hooks: [
        async (input) => {
          const trigger = input.trigger; // 'manual' o 'auto'
          
          return {
            continue: true,
            systemMessage: 'Concentrati sulla conservazione dei dettagli di implementazione e delle risoluzioni degli errori'
          };
        }
      ]
    }
  ]
};

Comportamento di esecuzione degli hook

  • Parallelizzazione: Tutti gli hook corrispondenti vengono eseguiti in parallelo
  • Timeout: Gli hook rispettano il segnale di interruzione dalle opzioni
  • Gestione degli errori: Gli errori degli hook vengono registrati ma non fermano l’esecuzione
  • Matcher: Supportano pattern regex (es. "Write|Edit")

Combinazione di hook con canUseTool

Mentre canUseTool fornisce controllo delle autorizzazioni, gli hook offrono un’integrazione più ampia del ciclo di vita:

for await (const message of query({
  prompt: "Costruisci la funzionalità",
  options: {
    // Controllo granulare delle autorizzazioni
    canUseTool: async (toolName, input) => {
      // Modifica input o nega basato su condizioni runtime
      return { behavior: "allow", updatedInput: input };
    },
    
    // Hook del ciclo di vita per monitoraggio e automazione
    hooks: {
      PreToolUse: [
        {
          hooks: [
            async (input) => {
              // Registra, valida o prepara
              return { continue: true };
            }
          ]
        }
      ]
    }
  }
})) {
  // Elabora messaggi
}

Controllo delle autorizzazioni con canUseTool

Il callback canUseTool fornisce controllo granulare sull’esecuzione degli strumenti. Viene chiamato prima di ogni uso di strumento e può consentire, negare o modificare gli input degli strumenti:

type ToolPermissionResult = 
  | { behavior: "allow"; updatedInput?: any }
  | { behavior: "deny"; message?: string };

for await (const message of query({
  prompt: "Analizza il comportamento degli utenti e calcola le metriche",
  options: {
    mcpServers: {
      "analytics": analyticsServer
    },
    canUseTool: async (toolName: string, input: any) => {
      // Controlla quali strumenti possono essere utilizzati
      if (toolName.startsWith("mcp__analytics__")) {
        // Controlla le autorizzazioni per gli strumenti di analisi
        const hasPermission = await checkUserPermissions(toolName);
        
        return hasPermission
          ? { behavior: "allow", updatedInput: input }
          : { behavior: "deny", message: "Autorizzazioni insufficienti" };
      }
      
      // Modifica input per certi strumenti
      if (toolName === "Bash") {
        // Aggiungi controlli di sicurezza o modifica comandi
        const safeInput = sanitizeBashCommand(input);
        return { behavior: "allow", updatedInput: safeInput };
      }
      
      // Consenti altri strumenti per impostazione predefinita
      return { behavior: "allow", updatedInput: input };
    }
  }
})) {
  if (message.type === "result") console.log(message.result);
}

Casi d’uso per canUseTool

  • Gestione delle autorizzazioni: Controlla le autorizzazioni utente prima di consentire l’esecuzione dello strumento
  • Validazione degli input: Valida o sanifica gli input degli strumenti prima dell’esecuzione
  • Limitazione della frequenza: Implementa limiti di frequenza per operazioni costose
  • Logging di audit: Registra l’uso degli strumenti per conformità o debug
  • Autorizzazioni dinamiche: Abilita/disabilita strumenti basato su condizioni runtime
// Esempio: Limitatore di frequenza per web scraping
const rateLimits = new Map<string, { count: number; resetTime: number }>();

const canUseTool = async (toolName: string, input: any) => {
  // Limita la frequenza del web scraping per prevenire ban IP e problemi di quota API
  if (toolName === "WebFetch" || toolName === "WebSearch") {
    const now = Date.now();
    const limit = rateLimits.get(toolName) || { count: 0, resetTime: now + 60000 };
    
    // Resetta il contatore ogni minuto
    if (now > limit.resetTime) {
      limit.count = 0;
      limit.resetTime = now + 60000;
    }
    
    // Consenti massimo 10 richieste per minuto
    if (limit.count >= 10) {
      return { 
        behavior: "deny", 
        message: `Limite di frequenza superato: massimo 10 richieste ${toolName} per minuto. Si resetta in ${Math.ceil((limit.resetTime - now) / 1000)}s` 
      };
    }
    
    limit.count++;
    rateLimits.set(toolName, limit);
    
    // Registra l'attività di scraping per monitoraggio
    console.log(`Richiesta ${toolName} ${limit.count}/10 a: ${input.url || input.query}`);
  }
  
  // Previeni loop infiniti accidentali negli script bash
  if (toolName === "Bash" && input.command?.includes("while true")) {
    return { 
      behavior: "deny", 
      message: "I loop infiniti non sono consentiti" 
    };
  }
  
  return { behavior: "allow", updatedInput: input };
};

Formati di output

Output di testo (predefinito)

// Output di testo predefinito
for await (const message of query({
  prompt: "Spiega il file src/components/Header.tsx"
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
    // Output: Questo è un componente React che mostra...
  }
}

Output JSON

// Raccogli tutti i messaggi per accesso simile a JSON
const messages = [];
for await (const message of query({
  prompt: "Come funziona il livello dati?"
})) {
  messages.push(message);
}

// Accedi al messaggio risultato con metadati
const result = messages.find(m => m.type === "result" && message.subtype === "success");
console.log({
  result: result.result,
  cost: result.total_cost_usd,
  duration: result.duration_ms
});

Formati di input

// Prompt diretto
for await (const message of query({
  prompt: "Spiega questo codice"
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

// Da variabile
const userInput = "Spiega questo codice";
for await (const message of query({ prompt: userInput })) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Esempi di integrazione di agenti

Agente di risposta agli incidenti SRE

import { query } from "@anthropic-ai/claude-code";

// Agente automatizzato di risposta agli incidenti
async function investigateIncident(
  incidentDescription: string,
  severity = "medium"
) {
  const messages = [];

  for await (const message of query({
    prompt: `Incidente: ${incidentDescription} (Gravità: ${severity})`,
    options: {
      appendSystemPrompt: "Sei un esperto SRE. Diagnostica il problema, valuta l'impatto e fornisci elementi di azione immediati.",
      maxTurns: 6,
      allowedTools: ["Bash", "Read", "WebSearch", "mcp__datadog"],
      mcpConfig: "monitoring-tools.json"
    }
  })) {
    messages.push(message);
  }

  return messages.find(m => m.type === "result" && message.subtype === "success");
}

// Utilizzo
const result = await investigateIncident("API di pagamento che restituisce errori 500", "high");
console.log(result.result);

Revisione di sicurezza automatizzata

import { query } from "@anthropic-ai/claude-code";
import { execSync } from "child_process";

async function auditPR(prNumber: number) {
  // Ottieni diff PR
  const prDiff = execSync(`gh pr diff ${prNumber}`, { encoding: 'utf8' });

  const messages = [];
  for await (const message of query({
    prompt: prDiff,
    options: {
      appendSystemPrompt: "Sei un ingegnere della sicurezza. Rivedi questa PR per vulnerabilità, pattern insicuri e problemi di conformità.",
      maxTurns: 3,
      allowedTools: ["Read", "Grep", "WebSearch"]
    }
  })) {
    messages.push(message);
  }

  return messages.find(m => m.type === "result" && message.subtype === "success");
}

// Utilizzo
const report = await auditPR(123);
console.log(JSON.stringify(report, null, 2));

Assistente legale multi-turno

import { query } from "@anthropic-ai/claude-code";

async function legalReview() {
  // Inizia sessione di revisione legale
  let sessionId: string;

  for await (const message of query({
    prompt: "Inizia sessione di revisione legale",
    options: { maxTurns: 1 }
  })) {
    if (message.type === "system" && message.subtype === "init") {
      sessionId = message.session_id;
    }
  }

  // Revisione multi-step utilizzando la stessa sessione
  const steps = [
    "Rivedi contract.pdf per clausole di responsabilità",
    "Controlla conformità con requisiti GDPR",
    "Genera riassunto esecutivo dei rischi"
  ];

  for (const step of steps) {
    for await (const message of query({
      prompt: step,
      options: { resume: sessionId, maxTurns: 2 }
    })) {
      if (message.type === "result" && message.subtype === "success") {
        console.log(`Passo: ${step}`);
        console.log(message.result);
      }
    }
  }
}

Schema dei messaggi

I messaggi restituiti dall’API JSON sono rigorosamente tipizzati secondo il seguente schema:

type SDKMessage =
  // Un messaggio dell'assistente
  | {
      type: "assistant";
      uuid: string;
      session_id: string;
      message: Message; // dall'SDK Anthropic
      parent_tool_use_id: string | null;
    }

  // Un messaggio utente (input)
  | {
      type: "user";
      uuid?: string;
      session_id: string;
      message: MessageParam; // dall'SDK Anthropic
      parent_tool_use_id: string | null;
    }

  // Un messaggio utente (output/replay con UUID richiesto)
  | {
      type: "user";
      uuid: string;
      session_id: string;
      message: MessageParam; // dall'SDK Anthropic
      parent_tool_use_id: string | null;
    }

  // Emesso come ultimo messaggio in caso di successo
  | {
      type: "result";
      subtype: "success";
      uuid: UUID;
      session_id: string;
      duration_ms: number;
      duration_api_ms: number;
      is_error: boolean;
      num_turns: number;
      result: string;
      total_cost_usd: number;
      usage: Usage;
      permission_denials: SDKPermissionDenial[];
    }

  // Emesso come ultimo messaggio in caso di errore o turni massimi
  | {
      type: "result";
      subtype: "error_max_turns" | "error_during_execution";
      uuid: UUID;
      session_id: string;
      duration_ms: number;
      duration_api_ms: number;
      is_error: boolean;
      num_turns: number;
      total_cost_usd: number;
      usage: Usage;
      permission_denials: SDKPermissionDenial[];
    }

  // Emesso come primo messaggio all'inizio di una conversazione
  | {
      type: "system";
      subtype: "init";
      uuid: UUID;
      session_id: string;
      apiKeySource: "user" | "project" | "org" | "temporary";
      cwd: string;
      tools: string[];
      mcp_servers: {
        name: string;
        status: string;
      }[];
      model: string;
      permissionMode: "default" | "acceptEdits" | "bypassPermissions" | "plan";
      slash_commands: string[];
      output_style: string;
    };

  type SDKPermissionDenial = {
    tool_name: string;
    tool_use_id: string;
    tool_input: Record<string, unknown>;
  }

Tipi di supporto aggiuntivi:

I tipi Message, MessageParam e Usage sono disponibili nell’SDK TypeScript di Anthropic.

Risorse correlate