{"name":"claude_chat.nu","source":"// claude_chat.nu — minimal Claude (Anthropic Messages API) CLI client.\n//\n// Reads ANTHROPIC_API_KEY from the environment, takes the prompt either\n// from argv or stdin, sends a single-turn message to claude-opus-4-7\n// and prints the assistant's reply plus token usage.\n//\n// Build + run (Linux/macOS):\n//\n//     ./build.sh\n//     export ANTHROPIC_API_KEY=sk-ant-...\n//\n//     # prompt as a single argv:\n//     ./nurl.sh examples/claude_chat.nu \"Explain NURL in one sentence\"\n//\n//     # prompt as multiple argv tokens (auto-joined with spaces):\n//     ./examples/claude_chat hello there\n//\n//     # prompt piped on stdin (no argv):\n//     echo \"Explain NURL\" | ./examples/claude_chat\n//     ./examples/claude_chat < prompt.txt\n//\n// Errors are reported by name (ClaudeAuth, ClaudeHttpDns, …); see\n// stdlib/ext/anthropic.nu for the full error contract.\n\n$ `stdlib/ext/anthropic.nu`\n$ `stdlib/ext/env.nu`\n$ `stdlib/core/io.nu`\n\n@ main → i {\n    : i argc ( env_args_count )\n\n    // Build prompt: either join argv past the program name, or — when\n    // there are no extra args — slurp stdin to EOF. This makes the tool\n    // usable both as `claude_chat \"what is NURL\"` and\n    // `cat question.txt | claude_chat`.\n    : String prompt ( string_with_cap 64 )\n    ? > argc 1 {\n        : ~ i i 1\n        ~ < i argc {\n            ? > i 1 { ( string_push_str prompt ` ` ) } {}\n            ( string_push_str prompt ( nurl_argv_get i ) )\n            = i + i 1\n        }\n    } {\n        : String stdin_text ( read_all_stdin )\n        ( string_push_str prompt ( string_data stdin_text ) )\n        ( string_free stdin_text )\n    }\n\n    // Reject empty prompts so we don't silently spend a token call on a\n    // blank message.\n    ? == ( string_len prompt ) 0 {\n        ( nurl_print `usage: claude_chat <prompt>\\n` )\n        ( nurl_print `       echo \"<prompt>\" | claude_chat\\n` )\n        ( nurl_print `       set ANTHROPIC_API_KEY in the environment first\\n` )\n        ( string_free prompt )\n        ^ 1\n    } {}\n\n    // Pull the API key out of the environment. We don't print it — even\n    // a partial leak in logs is a risk worth refusing.\n    : ?String key ( env_get `ANTHROPIC_API_KEY` )\n    : s api_key ?? key {\n        T s → ( string_data s )\n        F → ``\n    }\n    ? == ( nurl_str_len api_key ) 0 {\n        ( nurl_print `error: ANTHROPIC_API_KEY not set\\n` )\n        ?? key { T s → ( string_free s ) F → {} }\n        ^ 1\n    } {}\n\n    : !Json ClaudeErr r\n    ( claude_messages api_key\n    `claude-opus-4-7`\n    `You are a helpful, concise assistant.`\n    ( string_data prompt )\n    1024 )\n    ( string_free prompt )\n    ?? key { T s → ( string_free s ) F → {} }\n\n    ?? r {\n        T resp → {\n            ( nurl_print ( claude_text resp ) )\n            ( nurl_print `\\n` )\n            ( nurl_print `\\n[model=` )\n            ( nurl_print ( claude_model resp ) )\n            ( nurl_print ` stop=` )\n            ( nurl_print ( claude_stop_reason resp ) )\n            ( nurl_print ` in=` )\n            ( nurl_print ( nurl_str_int ( claude_input_tokens resp ) ) )\n            ( nurl_print ` out=` )\n            ( nurl_print ( nurl_str_int ( claude_output_tokens resp ) ) )\n            ( nurl_print `]\\n` )\n            ( claude_response_free resp )\n            ^ 0\n        }\n        F e → {\n            : ClaudeErr ce # ClaudeErr e\n            ( nurl_print `error: ` )\n            ( nurl_print_str ( claude_err_name ce ) )\n            ^ 1\n        }\n    }\n    ^ 1\n}\n","bytes":3489}