fix(gateway): run Claude Code's /usage without CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC (#438)
With CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC set, Claude Code refuses its own /api/oauth/usage request, so /usage only prints a snapshot another Claude Code process left in ~/.claude.json within the last hour, and the usage card shows "Usage unavailable" otherwise. The /usage run now drops that flag unless the user set it, and sets DISABLE_TELEMETRY, DISABLE_ERROR_REPORTING and DISABLE_AUTOUPDATER. cleanClaudeEnv is unchanged, so the bridge and the model probe still run with the flag. Without the flag, the /usage run also sends Claude Code's startup config fetch, the org fast-mode check and the Grove notice config request. TestClaudeUsageSendsItsRequest checks the environment of the /usage run, of the warm-up, and of a /usage run where the user set the flag. Fixes #437
This commit is contained in:
1 parent
4696d14726
commit
fc036d1db4
2 files changed
+47
-2
No files matched your search
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/yetone/magpie/internal/netproxy"
|
||||
@@ -90,7 +91,17 @@ func claudeUsage(ctx context.Context) (string, error) {
|
||||
cmd := proc.CommandContext(ctx, binary, claudeUsageArgs()...)
|
||||
cmd.Dir = tmp
|
||||
cmd.Stdin = strings.NewReader("")
|
||||
cmd.Env = netproxy.EnvWith(claudeProxy(ctx), cleanClaudeEnv(os.Environ()))
|
||||
// CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC makes /usage skip its request
|
||||
// and print only a reading another run left in the last hour, so it stays
|
||||
// only when the user set it.
|
||||
env := cleanClaudeEnv(os.Environ())
|
||||
if os.Getenv("CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC") == "" {
|
||||
env = slices.DeleteFunc(env, func(e string) bool {
|
||||
return strings.HasPrefix(e, "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=")
|
||||
})
|
||||
}
|
||||
env = append(env, "DISABLE_TELEMETRY=1", "DISABLE_ERROR_REPORTING=1", "DISABLE_AUTOUPDATER=1")
|
||||
cmd.Env = netproxy.EnvWith(claudeProxy(ctx), env)
|
||||
var out, stderr bytes.Buffer
|
||||
cmd.Stdout, cmd.Stderr = &out, &stderr
|
||||
runErr := cmd.Run()
|
||||
|
||||
@@ -23,7 +23,9 @@ func fakeWarmClaude(t *testing.T, out string, code int) string {
|
||||
log := filepath.Join(dir, "log")
|
||||
script := "#!/bin/sh\n" +
|
||||
"{ printf 'args:'; for a in \"$@\"; do printf '[%s]' \"$a\"; done; echo; " +
|
||||
"echo \"dir:$CLAUDE_CONFIG_DIR\"; echo \"base:$ANTHROPIC_BASE_URL\"; echo \"pwd:$(pwd)\"; printf 'stdin:'; cat; echo; } > " + log + "\n" +
|
||||
"echo \"dir:$CLAUDE_CONFIG_DIR\"; echo \"base:$ANTHROPIC_BASE_URL\"; echo \"pwd:$(pwd)\"; printf 'stdin:'; cat; echo; " +
|
||||
"echo \"traffic:$CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC\"; echo \"telemetry:$DISABLE_TELEMETRY\"; " +
|
||||
"echo \"errors:$DISABLE_ERROR_REPORTING\"; echo \"updater:$DISABLE_AUTOUPDATER\"; } > " + log + "\n" +
|
||||
"echo '" + out + "'\nexit " + string(rune('0'+code)) + "\n"
|
||||
if err := os.WriteFile(filepath.Join(dir, "claude"), []byte(script), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -123,6 +125,38 @@ func TestClaudeUsageRunsClaudeCode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// /usage runs without CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC, which keeps
|
||||
// Claude Code from asking for the usage, unless the user set it; telemetry,
|
||||
// error reporting and autoupdate stay off. The warm-up keeps it.
|
||||
func TestClaudeUsageSendsItsRequest(t *testing.T) {
|
||||
log := fakeWarmClaude(t, `{"type":"result","is_error":false,"result":"Current session: 13% used"}`, 0)
|
||||
for _, k := range []string{"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC", "DISABLE_TELEMETRY", "DISABLE_ERROR_REPORTING", "DISABLE_AUTOUPDATER"} {
|
||||
t.Setenv(k, "")
|
||||
}
|
||||
if _, err := claudeUsage(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b, _ := os.ReadFile(log)
|
||||
for _, want := range []string{"traffic:\n", "telemetry:1\n", "errors:1\n", "updater:1\n"} {
|
||||
if !strings.Contains(string(b), want) {
|
||||
t.Errorf("/usage run lacks %q:\n%s", want, b)
|
||||
}
|
||||
}
|
||||
if err := warmClaude(context.Background(), ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b, _ := os.ReadFile(log); !strings.Contains(string(b), "traffic:1\n") {
|
||||
t.Errorf("warm-up lacks CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:\n%s", b)
|
||||
}
|
||||
t.Setenv("CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC", "1")
|
||||
if _, err := claudeUsage(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b, _ := os.ReadFile(log); !strings.Contains(string(b), "traffic:1\n") {
|
||||
t.Errorf("/usage run dropped the user's CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:\n%s", b)
|
||||
}
|
||||
}
|
||||
|
||||
// With Claude Code's verbose output on (its /config, kept in .claude.json),
|
||||
// claude -p --output-format json prints every message as an array, the
|
||||
// system init first and the result last (KevinXC on Discord: usage
|
||||
|
||||
Reference in new issue
Block a user