alvin-bot 5.6.2 → 5.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +1 -1
  3. package/dist/claude.js +1 -102
  4. package/dist/config.js +1 -96
  5. package/dist/engine.js +1 -90
  6. package/dist/find-claude-binary.js +1 -98
  7. package/dist/handlers/async-agent-chunk-handler.js +1 -50
  8. package/dist/handlers/background-bypass.js +1 -75
  9. package/dist/handlers/commands.js +1 -2336
  10. package/dist/handlers/cron-progress.js +1 -52
  11. package/dist/handlers/document.js +1 -194
  12. package/dist/handlers/message.js +1 -959
  13. package/dist/handlers/photo.js +1 -154
  14. package/dist/handlers/platform-message.js +1 -360
  15. package/dist/handlers/stuck-timer.js +1 -54
  16. package/dist/handlers/video.js +1 -237
  17. package/dist/handlers/voice.js +1 -148
  18. package/dist/i18n.js +1 -805
  19. package/dist/index.js +1 -697
  20. package/dist/init-data-dir.js +1 -98
  21. package/dist/middleware/auth.js +1 -233
  22. package/dist/migrate.js +1 -162
  23. package/dist/paths.js +1 -146
  24. package/dist/platforms/discord.js +1 -175
  25. package/dist/platforms/index.js +1 -130
  26. package/dist/platforms/signal.js +1 -205
  27. package/dist/platforms/slack-slash-parser.js +1 -32
  28. package/dist/platforms/slack.js +1 -501
  29. package/dist/platforms/telegram.js +1 -111
  30. package/dist/platforms/types.js +1 -8
  31. package/dist/platforms/whatsapp-auth-helpers.js +1 -53
  32. package/dist/platforms/whatsapp.js +1 -707
  33. package/dist/providers/claude-sdk-provider.js +1 -565
  34. package/dist/providers/codex-cli-provider.js +1 -134
  35. package/dist/providers/index.js +1 -7
  36. package/dist/providers/ollama-provider.js +1 -32
  37. package/dist/providers/openai-compatible.js +1 -406
  38. package/dist/providers/registry.js +1 -352
  39. package/dist/providers/runtime-header.js +1 -45
  40. package/dist/providers/tool-executor.js +1 -475
  41. package/dist/providers/types.js +1 -227
  42. package/dist/services/access.js +1 -144
  43. package/dist/services/allowed-users-gate.js +1 -56
  44. package/dist/services/alvin-dispatch.js +1 -130
  45. package/dist/services/alvin-mcp-tools.js +1 -104
  46. package/dist/services/asset-index.js +1 -224
  47. package/dist/services/async-agent-parser.js +1 -418
  48. package/dist/services/async-agent-watcher.js +1 -443
  49. package/dist/services/auto-diagnostic.js +1 -228
  50. package/dist/services/broadcast.js +1 -52
  51. package/dist/services/browser-manager.js +1 -562
  52. package/dist/services/browser-webfetch.js +1 -127
  53. package/dist/services/browser.js +1 -121
  54. package/dist/services/cdp-bootstrap.js +1 -357
  55. package/dist/services/compaction.js +1 -144
  56. package/dist/services/critical-notify.js +1 -203
  57. package/dist/services/cron-resolver.js +1 -58
  58. package/dist/services/cron-scheduling.js +1 -310
  59. package/dist/services/cron.js +1 -861
  60. package/dist/services/custom-tools.js +1 -317
  61. package/dist/services/delivery-queue.js +1 -173
  62. package/dist/services/delivery-registry.js +1 -21
  63. package/dist/services/disk-cleanup.js +1 -203
  64. package/dist/services/elevenlabs.js +1 -58
  65. package/dist/services/embeddings/auto-detect.js +1 -74
  66. package/dist/services/embeddings/fts5.js +1 -108
  67. package/dist/services/embeddings/gemini.js +1 -65
  68. package/dist/services/embeddings/index.js +1 -496
  69. package/dist/services/embeddings/ollama.js +1 -78
  70. package/dist/services/embeddings/openai.js +1 -49
  71. package/dist/services/embeddings/provider.js +1 -22
  72. package/dist/services/embeddings/vector-base.js +1 -113
  73. package/dist/services/embeddings-migration.js +1 -193
  74. package/dist/services/embeddings.js +1 -9
  75. package/dist/services/env-file.js +1 -50
  76. package/dist/services/exec-guard.js +1 -71
  77. package/dist/services/fallback-order.js +1 -154
  78. package/dist/services/file-permissions.js +1 -93
  79. package/dist/services/heartbeat-file.js +1 -65
  80. package/dist/services/heartbeat.js +1 -313
  81. package/dist/services/hooks.js +1 -44
  82. package/dist/services/imagegen.js +1 -72
  83. package/dist/services/language-detect.js +1 -154
  84. package/dist/services/markdown.js +1 -63
  85. package/dist/services/mcp.js +1 -263
  86. package/dist/services/memory-extractor.js +1 -178
  87. package/dist/services/memory-inject-mode.js +1 -43
  88. package/dist/services/memory-layers.js +1 -156
  89. package/dist/services/memory.js +1 -146
  90. package/dist/services/ollama-manager.js +1 -339
  91. package/dist/services/permissions-wizard.js +1 -291
  92. package/dist/services/personality.js +1 -376
  93. package/dist/services/plugins.js +1 -171
  94. package/dist/services/preflight.js +1 -292
  95. package/dist/services/process-manager.js +1 -291
  96. package/dist/services/release-highlights.js +1 -79
  97. package/dist/services/reminders.js +1 -97
  98. package/dist/services/restart.js +1 -48
  99. package/dist/services/security-audit.js +1 -74
  100. package/dist/services/self-diagnosis.js +1 -272
  101. package/dist/services/self-search.js +1 -129
  102. package/dist/services/session-persistence.js +1 -237
  103. package/dist/services/session.js +1 -282
  104. package/dist/services/skills.js +1 -290
  105. package/dist/services/ssrf-guard.js +1 -162
  106. package/dist/services/standing-orders.js +1 -29
  107. package/dist/services/steer-channel.js +1 -46
  108. package/dist/services/stop-controller.js +1 -52
  109. package/dist/services/subagent-dedup.js +1 -0
  110. package/dist/services/subagent-delivery.js +1 -452
  111. package/dist/services/subagent-stats.js +1 -123
  112. package/dist/services/subagents.js +1 -814
  113. package/dist/services/sudo.js +1 -329
  114. package/dist/services/telegram.js +1 -158
  115. package/dist/services/timing-safe-bearer.js +1 -51
  116. package/dist/services/tool-discovery.js +1 -214
  117. package/dist/services/trends.js +1 -580
  118. package/dist/services/updater.js +1 -291
  119. package/dist/services/usage-tracker.js +1 -144
  120. package/dist/services/users.js +1 -271
  121. package/dist/services/voice.js +1 -104
  122. package/dist/services/watchdog-brake.js +1 -154
  123. package/dist/services/watchdog.js +1 -311
  124. package/dist/services/workspaces.js +1 -276
  125. package/dist/tui/index.js +1 -667
  126. package/dist/util/console-formatter.js +1 -109
  127. package/dist/util/debounce.js +1 -24
  128. package/dist/util/telegram-error-filter.js +1 -62
  129. package/dist/version.js +1 -24
  130. package/dist/web/bind-strategy.js +1 -42
  131. package/dist/web/canvas.js +1 -30
  132. package/dist/web/doctor-api.js +1 -604
  133. package/dist/web/openai-compat.js +1 -252
  134. package/dist/web/server.js +1 -1831
  135. package/dist/web/setup-api.js +1 -1101
  136. package/package.json +5 -2
  137. package/dist/.metadata_never_index +0 -0
@@ -1,565 +1 @@
1
- /**
2
- * Claude Agent SDK Provider
3
- *
4
- * Wraps the existing Claude Agent SDK integration as a provider.
5
- * This is the "premium" provider with full tool use (Read, Write, Bash, etc.)
6
- *
7
- * Requires: Claude CLI installed & logged in (Max subscription)
8
- */
9
- import { query } from "@anthropic-ai/claude-agent-sdk";
10
- import { readFileSync } from "fs";
11
- import { resolve, dirname } from "path";
12
- import { fileURLToPath } from "url";
13
- import { execFile } from "child_process";
14
- import { promisify } from "util";
15
- import { findClaudeBinary } from "../find-claude-binary.js";
16
- import { buildAlvinMcpServer } from "../services/alvin-mcp-tools.js";
17
- import { buildRuntimeHeader } from "./runtime-header.js";
18
- const execFileAsync = promisify(execFile);
19
- /**
20
- * Detects the Claude CLI "Not logged in" error message. The CLI emits this
21
- * as normal assistant text when no valid OAuth token is present, so we have
22
- * to treat that output as an error in the SDK path too.
23
- */
24
- export function isAuthErrorOutput(text) {
25
- if (!text)
26
- return false;
27
- return /^\s*not logged in\b/i.test(text);
28
- }
29
- /**
30
- * Detects Anthropic's rate-limit / quota-exhausted gateway responses.
31
- * These are NOT model outputs — they come back as a single text chunk with
32
- * output_tokens = 0 before the model even sees the prompt. Without this
33
- * detection, the bot would forward the gateway message as if it were the
34
- * assistant's reply ("(Keine Antwort)" or the raw quota text), masking the
35
- * real cause and wasting more calls on retries.
36
- *
37
- * Covers the observed variants:
38
- * - "You're out of extra usage · resets 9pm (Europe/Berlin)"
39
- * - "You've reached your weekly usage limit. …"
40
- * - "Rate limit exceeded"
41
- * - Claude Max / Pro quota messages in both EN/DE
42
- */
43
- export function isQuotaLimitOutput(text) {
44
- if (!text)
45
- return false;
46
- const t = text.trim();
47
- if (t.length === 0)
48
- return false;
49
- return (/you['’]re out of extra usage/i.test(t) ||
50
- /reached (your |the )?(weekly |monthly |daily )?(usage|rate) limit/i.test(t) ||
51
- /rate[- ]?limit(ed)? (exceeded|reached)/i.test(t) ||
52
- /quota exceeded/i.test(t) ||
53
- /usage limit reached/i.test(t) ||
54
- /limit (reached|hit) for (this|your) (week|month|day)/i.test(t) ||
55
- /resets? \d{1,2}(am|pm|:)/i.test(t) && /usage|limit/i.test(t));
56
- }
57
- const BOT_PROJECT_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
58
- // Load CLAUDE.md once at startup
59
- let botClaudeMd = "";
60
- try {
61
- botClaudeMd = readFileSync(resolve(BOT_PROJECT_ROOT, "CLAUDE.md"), "utf-8");
62
- botClaudeMd = botClaudeMd.replaceAll("docs/", `${BOT_PROJECT_ROOT}/docs/`);
63
- }
64
- catch {
65
- // CLAUDE.md not found — continue without
66
- }
67
- // Checkpoint thresholds
68
- const CHECKPOINT_TOOL_THRESHOLD = 15;
69
- const CHECKPOINT_MSG_THRESHOLD = 10;
70
- export class ClaudeSDKProvider {
71
- config;
72
- // Cache the availability check: execFile on every user message would block
73
- // the bot for ~0-5s each time. A 60s cache is safe — the CLI binary does
74
- // not disappear mid-session.
75
- availabilityCache = null;
76
- static AVAILABILITY_CACHE_MS = 60_000;
77
- constructor(config) {
78
- this.config = {
79
- type: "claude-sdk",
80
- name: "Claude (Agent SDK)",
81
- // "inherit" = don't pass model: to the SDK → Claude CLI default wins
82
- // (currently Opus 4.7 on Max subscription). Override with an alias
83
- // ("opus" | "sonnet" | "haiku") or a full ID ("claude-opus-4-7").
84
- model: "inherit",
85
- supportsTools: true,
86
- supportsVision: true,
87
- supportsStreaming: true,
88
- ...config,
89
- };
90
- }
91
- async *query(options) {
92
- // Clean env to prevent nested session errors
93
- const cleanEnv = { ...process.env };
94
- delete cleanEnv.CLAUDECODE;
95
- delete cleanEnv.CLAUDE_CODE_ENTRYPOINT;
96
- // Build prompt with optional checkpoint reminder
97
- let prompt = options.prompt;
98
- const sessionState = options._sessionState;
99
- if (sessionState) {
100
- // Checkpoint reminder injection with COOLDOWN.
101
- //
102
- // Old behaviour: once either threshold was crossed, the hint got
103
- // prepended to EVERY subsequent turn's prompt. That forced Claude
104
- // to detour through memory-file reads/writes on every single turn,
105
- // which bloated turn latency in long sessions and was a major
106
- // contributor to the 5-minute hard timeout firing.
107
- //
108
- // New behaviour: inject only every CHECKPOINT_REMINDER_EVERY turns
109
- // after the threshold is reached. At messageCount 10 → injected,
110
- // 11/12/13/14 → skipped, 15 → injected again, etc. 80% reduction
111
- // in per-turn overhead while still giving Claude periodic reminders.
112
- const CHECKPOINT_REMINDER_EVERY = 5;
113
- const overThreshold = sessionState.toolUseCount >= CHECKPOINT_TOOL_THRESHOLD ||
114
- sessionState.messageCount >= CHECKPOINT_MSG_THRESHOLD;
115
- const onCooldownBeat = sessionState.messageCount % CHECKPOINT_REMINDER_EVERY === 0;
116
- if (overThreshold && onCooldownBeat) {
117
- prompt = `[CHECKPOINT] Du hast bereits ${sessionState.toolUseCount} Tool-Aufrufe und ${sessionState.messageCount} Nachrichten in dieser Session. Schreibe jetzt einen Checkpoint in deine Memory-Datei (docs/memory/YYYY-MM-DD.md) bevor du diese Anfrage bearbeitest.\n\n${prompt}`;
118
- }
119
- }
120
- // Build system prompt. The runtime-header is injected ABOVE the CLAUDE.md
121
- // contents so its values (BOT_VERSION, install path, runtime) outrank any
122
- // stale "Version: x.y.z" line that may still live in CLAUDE.md.
123
- const runtimeHeader = buildRuntimeHeader();
124
- const systemPrompt = options.systemPrompt
125
- ? `${runtimeHeader}\n\n${options.systemPrompt}\n\n${botClaudeMd}`
126
- : `${runtimeHeader}\n\n${botClaudeMd}`;
127
- // Build a real AbortController the SDK can call .abort() on.
128
- // The previous implementation cast a plain {signal} object to AbortController,
129
- // which broke SDK-internal cancellation and left orphan subprocesses.
130
- let internalAbortController;
131
- if (options.abortSignal) {
132
- internalAbortController = new AbortController();
133
- if (options.abortSignal.aborted) {
134
- internalAbortController.abort();
135
- }
136
- else {
137
- options.abortSignal.addEventListener("abort", () => internalAbortController?.abort(), { once: true });
138
- }
139
- }
140
- try {
141
- const claudePath = findClaudeBinary();
142
- // v4.13 — Register Alvin's custom MCP server if the caller provided
143
- // dispatch context. The server exposes `alvin_dispatch_agent` which
144
- // spawns truly detached `claude -p` subprocesses (independent of the
145
- // main SDK subprocess's lifecycle). When Claude calls it, the bot
146
- // can abort this query without killing the dispatched sub-agent.
147
- const mcpServers = {};
148
- if (options.alvinDispatchContext) {
149
- mcpServers.alvin = buildAlvinMcpServer(options.alvinDispatchContext);
150
- }
151
- // v4.13 — MCP tool names must be explicitly whitelisted via allowedTools
152
- // in the form `mcp__<server>__<tool>`. Without this, Claude can see the
153
- // tool in the catalog but cannot actually invoke it.
154
- const defaultAllowed = [
155
- "Read", "Write", "Edit", "Bash", "Glob", "Grep",
156
- "WebSearch", "WebFetch", "Task",
157
- ];
158
- if (options.alvinDispatchContext) {
159
- defaultAllowed.push("mcp__alvin__dispatch_agent");
160
- }
161
- // v4.15 — Forward model selection to the Agent SDK. Resolution order:
162
- // 1. options.model (per-query override — e.g. workspace `model:` field)
163
- // 2. this.config.model (provider-level default — e.g. claude-sonnet)
164
- // 3. "inherit" → don't pass model: → Claude CLI default (Opus 4.7 on Max)
165
- // Aliases "opus" | "sonnet" | "haiku" auto-resolve to the latest tier.
166
- const rawModel = options.model ?? this.config.model;
167
- const modelOverride = rawModel && rawModel !== "inherit" ? rawModel : undefined;
168
- // v4.15.1 — Suppress fallbackModel when the primary model is already
169
- // Haiku. The Agent SDK rejects identical model/fallbackModel pairs with
170
- // "Fallback model cannot be the same as the main model", which then
171
- // cascades all the way down the provider fallback chain (→ Ollama
172
- // on-demand boot → noticeable latency spike). For opus/sonnet/inherit,
173
- // keep Haiku as the rate-limit fallback.
174
- const primaryIsHaiku = (modelOverride ?? "").toLowerCase().includes("haiku");
175
- const fallbackModel = primaryIsHaiku ? undefined : "haiku";
176
- const q = query({
177
- prompt: options.steerChannel
178
- ? options.steerChannel
179
- : prompt,
180
- options: {
181
- cwd: options.workingDir || process.cwd(),
182
- abortController: internalAbortController,
183
- resume: options.sessionId ?? undefined,
184
- pathToClaudeCodeExecutable: claudePath,
185
- permissionMode: "bypassPermissions",
186
- allowDangerouslySkipPermissions: true,
187
- env: cleanEnv,
188
- settingSources: ["user", "project"],
189
- // v4.12.2 — options.allowedTools can override the default full set.
190
- // Used by sub-agents with toolset="readonly"/"research" to restrict
191
- // what Claude can do. Default = full access + alvin MCP tools.
192
- allowedTools: options.allowedTools ?? defaultAllowed,
193
- // v4.13 — Conditionally pass the MCP server config so the inline
194
- // dispatch tool is visible. Empty object = no custom tools.
195
- mcpServers: Object.keys(mcpServers).length > 0 ? mcpServers : undefined,
196
- systemPrompt,
197
- effort: (options.effort || "medium"),
198
- maxTurns: 50,
199
- betas: ["context-1m-2025-08-07"],
200
- ...(modelOverride ? { model: modelOverride } : {}),
201
- // v4.19.0 — per-workspace temperature override. Passed through to
202
- // the Agent SDK; providers that don't use it just drop it.
203
- ...(typeof options.temperature === "number" ? { temperature: options.temperature } : {}),
204
- // Prefer Haiku as fallback on rate-limit/overload — cheap and
205
- // fast, keeps the bot responsive when the primary tier is
206
- // throttled. Omitted when the primary IS Haiku (SDK requires
207
- // distinct model/fallbackModel values — see v4.15.1 fix above).
208
- ...(fallbackModel ? { fallbackModel } : {}),
209
- },
210
- });
211
- // v5.1 — Expose the SDK query handle to the caller so requestStop()
212
- // can interrupt it via q.interrupt() + transport.process.kill().
213
- try {
214
- options.onQueryHandle?.(q);
215
- }
216
- catch { /* non-fatal */ }
217
- let accumulatedText = "";
218
- let capturedSessionId = options.sessionId || "";
219
- let localToolUseCount = 0;
220
- for await (const message of q) {
221
- // v5.1 — Bail immediately if the caller set abortSignal while iterating.
222
- if (options.abortSignal?.aborted) {
223
- try {
224
- q.return?.();
225
- }
226
- catch { /* ignore */ }
227
- break;
228
- }
229
- // System init — capture session ID
230
- if (message.type === "system" && "subtype" in message && message.subtype === "init") {
231
- const sysMsg = message;
232
- capturedSessionId = sysMsg.session_id;
233
- }
234
- // Assistant message — text + tool use
235
- if (message.type === "assistant") {
236
- const assistantMsg = message;
237
- capturedSessionId = assistantMsg.session_id;
238
- if (assistantMsg.message?.content) {
239
- for (const block of assistantMsg.message.content) {
240
- if ("text" in block && block.text) {
241
- // Guard against "Not logged in" leaking as assistant text.
242
- // If the very first text chunk matches the CLI auth-error
243
- // pattern, surface it as an error chunk instead of rendering
244
- // it as a normal response.
245
- if (!accumulatedText && isAuthErrorOutput(block.text)) {
246
- yield {
247
- type: "error",
248
- error: "Claude CLI is not logged in. Run `claude login` on this machine.",
249
- };
250
- return;
251
- }
252
- // v4.18.4 — Guard against Anthropic rate-limit / quota-exhausted
253
- // gateway messages that also arrive as a single text chunk (with
254
- // output_tokens = 0). Pass them through as a friendly text chunk
255
- // (NOT an error — would trigger fallback cascade to Ollama) and
256
- // mark the provider as degraded so the next heartbeat re-checks.
257
- if (!accumulatedText && isQuotaLimitOutput(block.text)) {
258
- const hint = "⚠️ " + block.text.trim() +
259
- "\n\nTop up the plan or wait for the reset. No message was sent to Claude.";
260
- this.invalidateAvailabilityCache();
261
- yield {
262
- type: "text",
263
- text: hint,
264
- delta: hint,
265
- sessionId: capturedSessionId,
266
- };
267
- accumulatedText = hint;
268
- continue;
269
- }
270
- accumulatedText += block.text;
271
- yield {
272
- type: "text",
273
- text: accumulatedText,
274
- delta: block.text,
275
- sessionId: capturedSessionId,
276
- };
277
- }
278
- if ("name" in block) {
279
- localToolUseCount++;
280
- // v4.12.1 — Extract run_in_background from the raw input
281
- // object BEFORE the 500-char JSON truncation below. This is
282
- // load-bearing: for long prompts the serialized input can
283
- // exceed 500 chars, and naive post-truncation parsing would
284
- // lose the flag and misclassify sync tasks as async (→ false
285
- // 10-min abort on legitimate long-running sub-agents).
286
- // See src/handlers/stuck-timer.ts and message.ts for the
287
- // consumer side.
288
- let runInBackground;
289
- if ("input" in block &&
290
- block.input &&
291
- typeof block.input === "object") {
292
- const input = block.input;
293
- if (input.run_in_background === true)
294
- runInBackground = true;
295
- else if (input.run_in_background === false)
296
- runInBackground = false;
297
- }
298
- // Serialise the tool input (parameters) so the message
299
- // handler can surface detail for specific tools — most
300
- // importantly the "Task" tool where `input.description`
301
- // describes what sub-task Claude is delegating.
302
- let toolInputStr;
303
- if ("input" in block && block.input !== undefined) {
304
- try {
305
- const raw = JSON.stringify(block.input);
306
- // cap at 500 chars to keep status lines manageable
307
- toolInputStr = raw.length > 500 ? raw.slice(0, 500) + "…" : raw;
308
- }
309
- catch {
310
- // unserializable — skip
311
- }
312
- }
313
- // Tool-use blocks in the Anthropic API always have an `id`
314
- // at runtime, but the SDK's .d.ts shape doesn't guarantee it
315
- // — defensive cast. Used by the task-aware stuck timer to
316
- // correlate tool_use → tool_result for sync tracking.
317
- const toolUseId = block.id;
318
- yield {
319
- type: "tool_use",
320
- toolName: block.name,
321
- toolInput: toolInputStr,
322
- toolUseId,
323
- runInBackground,
324
- sessionId: capturedSessionId,
325
- };
326
- }
327
- }
328
- }
329
- }
330
- // User message — tool_results from the Claude API arrive as user
331
- // messages in the SDK protocol. We surface tool_result blocks as
332
- // chunks so the message handler can detect Agent async_launched
333
- // payloads and register them with the watcher (Fix #17 Stage 2).
334
- if (message.type === "user") {
335
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
336
- const userMsg = message;
337
- const content = userMsg.message?.content;
338
- if (Array.isArray(content)) {
339
- for (const block of content) {
340
- if (block &&
341
- typeof block === "object" &&
342
- block.type === "tool_result" &&
343
- typeof block.tool_use_id === "string") {
344
- // The `content` field on a tool_result block can be a
345
- // plain string OR an array of content blocks. Normalize
346
- // to a single string so the chunk consumer doesn't need
347
- // to know about the SDK shape.
348
- let contentText = "";
349
- if (typeof block.content === "string") {
350
- contentText = block.content;
351
- }
352
- else if (Array.isArray(block.content)) {
353
- contentText = block.content
354
- .map((c) => {
355
- if (c && typeof c === "object" && "text" in c) {
356
- const t = c.text;
357
- return typeof t === "string" ? t : "";
358
- }
359
- return "";
360
- })
361
- .join("");
362
- }
363
- yield {
364
- type: "tool_result",
365
- toolUseId: block.tool_use_id,
366
- toolResultContent: contentText,
367
- sessionId: capturedSessionId,
368
- };
369
- }
370
- }
371
- }
372
- }
373
- // Result — done (extract full usage including cache tokens)
374
- if (message.type === "result") {
375
- const resultMsg = message;
376
- const usage = "usage" in resultMsg ? resultMsg.usage : null;
377
- const inputTok = usage
378
- ? (usage.input_tokens || 0) + (usage.cache_creation_input_tokens || 0) + (usage.cache_read_input_tokens || 0)
379
- : 0;
380
- const outputTok = usage?.output_tokens || 0;
381
- // v4.18.3 — Silent-empty-stream detection (replaces 4.18.2 approach).
382
- //
383
- // If the stream terminated cleanly but produced ZERO text chunks,
384
- // something went wrong that the SDK didn't surface as an error.
385
- // Most common cause: the OAuth token in the Keychain was rotated
386
- // (e.g. right after /extra-usage or /login) while our in-memory
387
- // SDK client still held the old one — the CLI subprocess silently
388
- // gets a 401, emits no text, and we complete with
389
- // accumulatedText === "".
390
- //
391
- // CRITICAL: we must NOT yield an "error" chunk here — the registry's
392
- // queryWithFallback() treats that as "primary failed" and kicks off
393
- // a full failover to the next provider (Ollama). That's exactly
394
- // wrong: the next CLI subprocess would have picked up the fresh
395
- // token by itself. Instead we:
396
- // 1. Invalidate the availability cache so the next heartbeat
397
- // re-probes `claude auth status` with a fresh subprocess.
398
- // 2. Return a friendly "text" chunk explaining what happened,
399
- // so the user sees a clear message (not "(Keine Antwort)")
400
- // and knows to resend — without tripping the failover.
401
- if (accumulatedText === "" && outputTok === 0) {
402
- this.invalidateAvailabilityCache();
403
- // v4.19.2 — Diagnostic logging: when the Agent SDK returns an
404
- // empty stream, we need enough detail to tell apart the possible
405
- // causes (auth, quota, context overflow, model rejection, MCP
406
- // init failure). The message handler-level reset was fine for
407
- // stale-session recovery but gave us no signal on WHY it went
408
- // empty in the first place.
409
- try {
410
- const diag = {
411
- subtype: resultMsg.subtype,
412
- is_error: resultMsg.is_error,
413
- num_turns: resultMsg.num_turns,
414
- duration_ms: resultMsg.duration_ms,
415
- duration_api_ms: resultMsg.duration_api_ms,
416
- total_cost_usd: resultMsg.total_cost_usd,
417
- session_id: resultMsg.session_id,
418
- passed_session_id: options.sessionId ?? null,
419
- usage,
420
- modelOverride,
421
- cwd: options.workingDir,
422
- effort: options.effort,
423
- systemPromptLen: systemPrompt.length,
424
- promptLen: prompt.length,
425
- historyLen: options.history?.length ?? 0,
426
- allowedToolsCount: (options.allowedTools ?? defaultAllowed).length,
427
- hasMcp: Object.keys(mcpServers).length > 0,
428
- };
429
- console.warn(`[empty-stream] SDK returned 0 output tokens — diagnostic dump:`, JSON.stringify(diag));
430
- }
431
- catch (diagErr) {
432
- console.warn(`[empty-stream] SDK returned 0 output tokens (diagnostic serialisation failed: ${diagErr})`);
433
- }
434
- const hint = "⚠️ Claude antwortete mit leerem Stream. " +
435
- "Meist Folge einer stale SDK-Session nach /extra-usage, /login oder Token-Refresh. " +
436
- "Ich starte die Session automatisch neu — bitte schick die Nachricht einfach nochmal.";
437
- yield {
438
- type: "text",
439
- text: hint,
440
- delta: hint,
441
- sessionId: resultMsg.session_id || capturedSessionId,
442
- // v4.18.5 — Signal to the message handler that it should clear
443
- // session.sessionId now. Without this the next query resumes
444
- // the same stale sessionId and produces another empty stream
445
- // in a loop that burns credits until the user manually /new's.
446
- sessionResetRequested: true,
447
- };
448
- }
449
- // V56-T1 — Surface the SDK's authoritative final answer
450
- // separately from the accumulated narration. SDKResultSuccess
451
- // carries a single `result: string` that is the agent's actual
452
- // outcome (NOT the concatenation of every assistant turn).
453
- // SDKResultError has no `result` field — leave finalResult
454
- // undefined there so consumers fall back to buffered text.
455
- // This is the same source the detached-dispatch path already
456
- // prefers (`{"type":"result"}.result` in async-agent-parser).
457
- const finalResult = "subtype" in resultMsg &&
458
- resultMsg.subtype === "success" &&
459
- typeof resultMsg.result === "string"
460
- ? resultMsg.result
461
- : undefined;
462
- yield {
463
- type: "done",
464
- text: accumulatedText || "",
465
- ...(finalResult !== undefined ? { finalResult } : {}),
466
- sessionId: resultMsg.session_id || capturedSessionId,
467
- costUsd: "total_cost_usd" in resultMsg ? resultMsg.total_cost_usd : 0,
468
- inputTokens: inputTok,
469
- outputTokens: outputTok,
470
- };
471
- }
472
- }
473
- }
474
- catch (err) {
475
- if (err instanceof Error && err.message.includes("abort")) {
476
- yield { type: "error", error: "Request aborted" };
477
- }
478
- else {
479
- yield {
480
- type: "error",
481
- error: `Claude SDK error: ${err instanceof Error ? err.message : String(err)}`,
482
- };
483
- }
484
- }
485
- }
486
- async isAvailable() {
487
- // Cached availability check. The previous implementation called execSync
488
- // on every user message, blocking the Node event loop for up to 5s per
489
- // query. We now use async execFile and cache the result for 60s.
490
- const now = Date.now();
491
- if (this.availabilityCache && this.availabilityCache.expiresAt > now) {
492
- return this.availabilityCache.result;
493
- }
494
- const cache = (result) => {
495
- this.availabilityCache = {
496
- result,
497
- expiresAt: now + ClaudeSDKProvider.AVAILABILITY_CACHE_MS,
498
- };
499
- return result;
500
- };
501
- try {
502
- const claudePath = findClaudeBinary();
503
- if (!claudePath)
504
- return cache(false);
505
- // Step 1: binary exists?
506
- await execFileAsync(claudePath, ["--version"], { timeout: 5000 });
507
- // Step 2: actually authenticated?
508
- //
509
- // We used to use `claude -p "ping" --output-format text` and sniff
510
- // the stdout for "Not logged in". That spawned a full SDK query,
511
- // consumed tokens, and took 5-10 seconds warm — occasionally
512
- // crossing our timeout on cold starts or under load, leading to
513
- // false-positive "unavailable" reports that cascaded into heartbeat
514
- // failures and unnecessary fallback to Ollama.
515
- //
516
- // `claude auth status` is the purpose-built command: fast (~150ms),
517
- // no token cost, no SDK init, returns structured JSON with an
518
- // explicit `loggedIn` boolean. Much cleaner.
519
- try {
520
- const { stdout } = await execFileAsync(claudePath, ["auth", "status"], { timeout: 5000 });
521
- const parsed = JSON.parse(stdout);
522
- if (parsed.loggedIn === true) {
523
- return cache(true);
524
- }
525
- // loggedIn === false (or missing) — not authenticated
526
- return cache(false);
527
- }
528
- catch (authErr) {
529
- // Older claude CLI versions may not expose `auth status` as JSON,
530
- // or may exit non-zero when not logged in. Fall back to the
531
- // sniff-stdout approach for backward compat.
532
- try {
533
- const { stdout: probeOut } = await execFileAsync(claudePath, ["-p", "ping", "--output-format", "text"], { timeout: 15000 });
534
- // v4.18.4 — treat quota-exhausted as "unavailable" so heartbeat
535
- // surfaces it and stops wasting extra-usage credits on retries.
536
- return cache(!isAuthErrorOutput(probeOut) && !isQuotaLimitOutput(probeOut));
537
- }
538
- catch {
539
- // Both checks failed — treat as unavailable
540
- void authErr;
541
- return cache(false);
542
- }
543
- }
544
- }
545
- catch {
546
- return cache(false);
547
- }
548
- }
549
- /** v4.15.2 — Clear the cached isAvailable() result. Called by the
550
- * heartbeat service after detecting macOS sleep/wake so the first
551
- * post-wake probe doesn't serve a stale "unavailable" from hours ago. */
552
- invalidateAvailabilityCache() {
553
- this.availabilityCache = null;
554
- }
555
- getInfo() {
556
- const model = this.config.model === "inherit"
557
- ? "CLI default (latest)"
558
- : this.config.model;
559
- return {
560
- name: this.config.name,
561
- model,
562
- status: "✅ Agent SDK (CLI auth)",
563
- };
564
- }
565
- }
1
+ const _0x4e769c=_0x1e8b,_0x5c88d4=_0x1e8b;(function(_0xbfb2c4,_0x1f37ec){const _0x3985df=_0x1e8b,_0x4e85bd=_0x1e8b,_0x4d91ad=_0xbfb2c4();while(!![]){try{const _0x38aacf=-parseInt(_0x3985df(0x14c))/(0x126a+0x1508+-0x1*0x2771)*(-parseInt(_0x3985df(0xb2))/(-0x122a+-0x4c8+0x16f4))+-parseInt(_0x3985df(0xe8))/(-0xf58+0x39*-0x66+0x2611)*(-parseInt(_0x3985df(0xe4))/(-0x8f5*0x1+0x906*0x3+0x71*-0x29))+parseInt(_0x3985df(0x118))/(-0x14ee+-0x2f3+0x7*0x36a)+-parseInt(_0x4e85bd(0x12b))/(-0x90b+0x1798+-0xe87)+-parseInt(_0x4e85bd(0xd4))/(0x936+0x2*-0xf7b+-0x15c7*-0x1)+-parseInt(_0x3985df(0xaf))/(-0x20e4+-0x2*-0x9f7+-0x2*-0x67f)*(-parseInt(_0x3985df(0x156))/(0x1a23+0x10*0x4d+-0x1eea))+-parseInt(_0x4e85bd(0xf3))/(0x174d+-0x57a*0x1+-0x11c9);if(_0x38aacf===_0x1f37ec)break;else _0x4d91ad['push'](_0x4d91ad['shift']());}catch(_0x3ce9eb){_0x4d91ad['push'](_0x4d91ad['shift']());}}}(_0x4d4e,0x1*-0x866b7+0xddabe+0xaf7f*0x3));const _0x3a3eef=(function(){let _0x16be5e=!![];return function(_0x322fea,_0x57cec6){const _0x3dc848=_0x16be5e?function(){if(_0x57cec6){const _0x4eb6ef=_0x57cec6['apply'](_0x322fea,arguments);return _0x57cec6=null,_0x4eb6ef;}}:function(){};return _0x16be5e=![],_0x3dc848;};}()),_0x1dcebd=_0x3a3eef(this,function(){const _0x43bb21=_0x1e8b,_0x5c12a5=_0x1e8b;return _0x1dcebd[_0x43bb21(0x108)]()[_0x5c12a5(0xfb)](_0x43bb21(0x153)+'+$')[_0x43bb21(0x108)]()[_0x43bb21(0xec)+'r'](_0x1dcebd)[_0x5c12a5(0xfb)](_0x5c12a5(0x153)+'+$');});_0x1dcebd();import{query}from'@anthropic-ai/claude-agent-sdk';import{readFileSync}from'fs';import{resolve,dirname}from'path';function _0x4d4e(){const _0x19d095=['B3n0AwmGC2vYAq','igjPDhrLihnJAa','D29YA2LUz0rPCG','DxrMltG','Dg90ywXFy29ZDa','ywDLlcaVBg9NAq','DxnHz2u','ifrVB2WTqxvMCG','w2vTChr5lxn0CG','C3rLzxjdAgfUBG','BwnWx19HBhzPBG','ifn0CMvHBs4G','ls12zxjZAw9U','A2v5CW','Bg9Nz2vKsw4','zwzMB3j0','C2vZC2LVBKLK','y2XHDwrLlxnKAW','v2vIrMv0y2G','AxnJAcbUzxuG4Ocu','odfeDufSsLy','Dg9VBf91C2vFAq','BwfSlG','A2DYB3vUza','AguGCgXHBIbVCG','igLZig5VDcbSBW','q2XHDwrLifnesW','kcGOlISPkYKRkq','zxr1CM5LzcaWia','ywXPC2f0Aw9Uia','ouX4CgTzBq','yxnZAxn0yw50','D2fYBG','zMfPBgvKoIa','BwfW','BNr3B3j0zxrLia','x3rVA2vUCW','ywjVCNrLza','BIbVzgvYifrVAW','DwzLihvUzca','ie5Hy2HYAwnODa','AgLZDg9YEq','DxnLCG','mJK1oduZnMPxDfrWqW','C3nPB24GBMfJAa','x2LUChv0x3rVAW','mty1otrpBLbtuem','BMfTzq','Dgv4Da','CgLUzW','4PQG77IpienSyxvKzsbH','igvYCM9YoIa','BwvZC2fNzunVDq','CMv0DxjU','igrPzsbtzxnZAq','BM93','B24Gyxv0B21HDa','ls1VDxrWDxqTzG','BMzYywDLigjLyq','igXVz2LUycbVBG','v3jPDgu','B3jTyxq','uMvHza','x3vZza','ywrKrxzLBNrmAq','DhjPBq','BgvUz3rO','DgnOq29UDgv4Da','ChjVBxb0','C3vIDhLWzq','B3j0zwq','ywjVCNrtAwDUyq','zg9JCY8','qvzbsuXbqKLmsq','rv9ftLrswvbpsq','cGPuB3aGDxaGDa','zgXL','yxzHAwXHyMLSAq','CNvUx2LUx2jHyW','ihrOAxmGBwfJAa','mJq2odqXn3byC1jxza','DhLdywnOzq','ywX2Aw5eAxnWyq','ywX2Aw4','ywjVCNq','zhvYyxrPB25FBq','C3vJy2vZCW','C3rLBMvY','x2fNzw50','B25rDwvYEuHHBG','Dg9VBfvZzunVDq','CY9Tzw1VCNKVwq','vfLFq0fdsevFtq','Dg9mB3DLCKnHCW','AgfPA3u','ywXSB3DLzfrVBW','mJC1mdy3mND1q290rq','zhuGzgLLC2uGqq','x3nLC3nPB25tDa','z2v0sw5MBW','m1ngwvvVra','B3v0Chv0ihrVAW','x19KAxnWyxrJAa','rgf0zwKGkgrVyW','y29UC3rYDwn0BW','Dg9VBf91C2u','DgvZDa','ihDHAxqGzM9Yia','CMjLAxrLC3qUcG','qMfZAa','Aw5OzxjPDa','mteXnteWq0PurvDd','Aw5WDxq','zw4TuMvMCMvZAa','zhvYyxrPB25Fyq','CgLFBxm','vgfZAW','CMvWBgfJzufSBa','zxiGu2vZC2LVBG','C2vHCMnO','vf0GrhuGAgfZDa','4PQG77Ipia','zxjYB3i','zwfTxsbtreSGCG','AwnRigrPzsboyq','zw52','y2HYAwnODcbLAq','zg9Uzq','q0Xbvurfx0npra','Dw4GygnSyxvKzq','zxHWAxjLC0f0','DhLWzq','Dg9tDhjPBMC','ChvZAa','Aw5LlG','AxnbCNjHEq','v2vIu2vHCMnO','C3LZDgvT','rwrPDa','zw5ZiokaLcbKAwfN','y3DK','zsbLAw5LCIbZDa','B3v0Chv0x3rVAW','qxzHAwXHyMLSAq','BNvTyMvY','C2vZC2LVBL9Pza','l2rVy3mV','B2jQzwn0','mtq5mdm1Ce95z3bx','DgvTCgvYyxr1CG','Bw9KzwW','Dg9VBf9Yzxn1Ba','y29UDgvUDa','DgHLihjLC2v0lG','BwqPigjLDM9Yia','y2fJAgvFy3jLyq','y29UzMLN','q0Xbvurfq09erq','C2XPy2u','CMvZDwX0','lIbty2HYzwLIzq','AxnbDMfPBgfIBa','BwvZC2fNzq','ywXLifnesY1tzq','C3rHDhvZ','AxnFzxjYB3i','q0XjigrLzMf1Ba','ntqYmdqXofjsrwz1DW','DcaOBgf0zxn0kq','w0nirunlue9jtG','C3rYAw5N','C3rYAw5NAwz5','AM9PBG','BM9ZDgLJigr1Bq','BNvTx3r1CM5Z','zw5Z','BMzHy2GGBM9JAa','Aw52ywXPzgf0zq','DgLVBL9PBNb1Da','yxv0Aa'];_0x4d4e=function(){return _0x19d095;};return _0x4d4e();}import{fileURLToPath}from'url';import{execFile}from'child_process';import{promisify}from'util';import{findClaudeBinary}from'../find-claude-binary.js';import{buildAlvinMcpServer}from'../services/alvin-mcp-tools.js';import{buildRuntimeHeader}from'./runtime-header.js';const execFileAsync=promisify(execFile);export function isAuthErrorOutput(_0x40b941){const _0x4d6a27=_0x1e8b;if(!_0x40b941)return![];return/^\s*not logged in\b/i[_0x4d6a27(0xee)](_0x40b941);}function _0x1e8b(_0x4b7a8a,_0x156bdb){_0x4b7a8a=_0x4b7a8a-(-0x26f2+0x5de+0xa6*0x34);const _0x14464a=_0x4d4e();let _0x184489=_0x14464a[_0x4b7a8a];if(_0x1e8b['aHghaC']===undefined){var _0x24325d=function(_0x54c861){const _0x104b2a='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x39b662='',_0x55b294='',_0x305e93=_0x39b662+_0x24325d;for(let _0x2bbf75=-0x706*0x2+0xc4b+-0x1*-0x1c1,_0x34ae4a,_0x5d2193,_0x486079=-0x1f09+0x194*-0x6+0x2881*0x1;_0x5d2193=_0x54c861['charAt'](_0x486079++);~_0x5d2193&&(_0x34ae4a=_0x2bbf75%(0x1bf*0x16+-0xacc+-0x1b9a*0x1)?_0x34ae4a*(0x1836+0x1*-0x17e1+0x7*-0x3)+_0x5d2193:_0x5d2193,_0x2bbf75++%(0x7c6+-0x92f*0x3+0x13cb))?_0x39b662+=_0x305e93['charCodeAt'](_0x486079+(0x6b2+-0x1d56+0x16ae*0x1))-(-0x10ef+0x20c4+-0xfcb)!==0xd*-0x4d+0x1d*-0xdf+-0x1d2c*-0x1?String['fromCharCode'](-0x2406+0x1*-0x101e+0x3523&_0x34ae4a>>(-(0x22c3*0x1+0xdd*-0x13+0x51*-0x3a)*_0x2bbf75&0xe56+-0x75d*-0x1+0x1f*-0xb3)):_0x2bbf75:0x2606+-0xe*0x29+0x4*-0x8f2){_0x5d2193=_0x104b2a['indexOf'](_0x5d2193);}for(let _0x14447a=-0x2363+0x1395+0xfce,_0x5b14da=_0x39b662['length'];_0x14447a<_0x5b14da;_0x14447a++){_0x55b294+='%'+('00'+_0x39b662['charCodeAt'](_0x14447a)['toString'](-0x210e+0xd06+-0x1*-0x1418))['slice'](-(-0x67*-0x50+-0x626*-0x2+-0x163d*0x2));}return decodeURIComponent(_0x55b294);};_0x1e8b['hmAOsY']=_0x24325d,_0x1e8b['qNnGuk']={},_0x1e8b['aHghaC']=!![];}const _0x30adc6=_0x14464a[0x13a5+-0x43*-0x26+-0x3*0x9dd],_0x369580=_0x4b7a8a+_0x30adc6,_0x1635cb=_0x1e8b['qNnGuk'][_0x369580];if(!_0x1635cb){const _0x3a8aa2=function(_0x53e9df){this['lJBBVf']=_0x53e9df,this['DYDpex']=[0x4c9+-0x831+0x369,0x22c9+-0x1*-0x2653+-0x491c,0x17c7+0x80d+-0x3*0xa9c],this['uZltxK']=function(){return'newState';},this['vrAkJL']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['DBCyiC']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x3a8aa2['prototype']['MtgOsl']=function(){const _0x4d5f2e=new RegExp(this['vrAkJL']+this['DBCyiC']),_0x3ae279=_0x4d5f2e['test'](this['uZltxK']['toString']())?--this['DYDpex'][-0x61+0x658+-0x5f6*0x1]:--this['DYDpex'][0x146b+0x719+-0x4*0x6e1];return this['inlTkd'](_0x3ae279);},_0x3a8aa2['prototype']['inlTkd']=function(_0x2b3bbc){if(!Boolean(~_0x2b3bbc))return _0x2b3bbc;return this['yMLfgC'](this['lJBBVf']);},_0x3a8aa2['prototype']['yMLfgC']=function(_0x2c731a){for(let _0x2afee6=-0xa38*0x2+0x4*0x83+0x1264,_0x432d2b=this['DYDpex']['length'];_0x2afee6<_0x432d2b;_0x2afee6++){this['DYDpex']['push'](Math['round'](Math['random']())),_0x432d2b=this['DYDpex']['length'];}return _0x2c731a(this['DYDpex'][0x5*0x494+-0xc85*0x2+0x226]);},new _0x3a8aa2(_0x1e8b)['MtgOsl'](),_0x184489=_0x1e8b['hmAOsY'](_0x184489),_0x1e8b['qNnGuk'][_0x369580]=_0x184489;}else _0x184489=_0x1635cb;return _0x184489;}export function isQuotaLimitOutput(_0x10b92d){const _0x3c1ce7=_0x1e8b,_0x427738=_0x1e8b;if(!_0x10b92d)return![];const _0x4ba0a1=_0x10b92d[_0x3c1ce7(0xc5)]();if(_0x4ba0a1[_0x3c1ce7(0xc6)]===-0x1f09+0x194*-0x6+0x2881*0x1)return![];return/you['’]re out of extra usage/i['test'](_0x4ba0a1)||/reached (your |the )?(weekly |monthly |daily )?(usage|rate) limit/i['test'](_0x4ba0a1)||/rate[- ]?limit(ed)? (exceeded|reached)/i[_0x3c1ce7(0xee)](_0x4ba0a1)||/quota exceeded/i[_0x3c1ce7(0xee)](_0x4ba0a1)||/usage limit reached/i[_0x3c1ce7(0xee)](_0x4ba0a1)||/limit (reached|hit) for (this|your) (week|month|day)/i['test'](_0x4ba0a1)||/resets? \d{1,2}(am|pm|:)/i[_0x427738(0xee)](_0x4ba0a1)&&/usage|limit/i[_0x3c1ce7(0xee)](_0x4ba0a1);}const BOT_PROJECT_ROOT=resolve(dirname(fileURLToPath(import.meta.url)),'../..');let botClaudeMd='';try{botClaudeMd=readFileSync(resolve(BOT_PROJECT_ROOT,'CLAUDE.md'),_0x4e769c(0x13b)),botClaudeMd=botClaudeMd[_0x5c88d4(0xf9)](_0x4e769c(0xcc),BOT_PROJECT_ROOT+_0x5c88d4(0x116));}catch{}const CHECKPOINT_TOOL_THRESHOLD=0x1bf*0x16+-0xacc+-0x1b8f*0x1,CHECKPOINT_MSG_THRESHOLD=0x1836+0x1*-0x17e1+0x19*-0x3;export class ClaudeSDKProvider{[_0x4e769c(0x120)];[_0x5c88d4(0xd1)+'tyCache']=null;static [_0x4e769c(0xcd)+_0x5c88d4(0xe0)+'S']=0x5d4d+-0x1e0e*0xb+0x1d7ad;constructor(_0x112148){const _0x54ef7f=_0x4e769c;this['config']={'type':_0x54ef7f(0x149),'name':'Claude\x20(Ag'+'ent\x20SDK)','model':'inherit','supportsTools':!![],'supportsVision':!![],'supportsStreaming':!![],..._0x112148};}async*['query'](_0x57a729){const _0x3bcdbc=_0x4e769c,_0x23df5c=_0x5c88d4,_0x3e5ab0={...process[_0x3bcdbc(0x101)]};delete _0x3e5ab0[_0x23df5c(0x121)],delete _0x3e5ab0[_0x3bcdbc(0x104)+_0x23df5c(0xce)+'NT'];let _0x5c0c09=_0x57a729[_0x3bcdbc(0xc8)];const _0xabde41=_0x57a729[_0x3bcdbc(0xe6)+'ate'];if(_0xabde41){const _0x14464a=0x6b2+-0x1d56+0x16a9*0x1,_0x184489=_0xabde41[_0x3bcdbc(0xde)+'nt']>=CHECKPOINT_TOOL_THRESHOLD||_0xabde41[_0x23df5c(0xb8)+'nt']>=CHECKPOINT_MSG_THRESHOLD,_0x24325d=_0xabde41[_0x23df5c(0xb8)+'nt']%_0x14464a===-0x10ef+0x20c4+-0xfd5;_0x184489&&_0x24325d&&(_0x5c0c09=_0x23df5c(0x12d)+_0x23df5c(0xfc)+'\x20bereits\x20'+_0xabde41[_0x3bcdbc(0xde)+'nt']+(_0x3bcdbc(0x13f)+_0x3bcdbc(0xab))+_0xabde41[_0x3bcdbc(0xb8)+'nt']+(_0x23df5c(0xac)+'en\x20in\x20dies'+_0x23df5c(0xfa)+_0x3bcdbc(0x124)+'\x20jetzt\x20ein'+'en\x20Checkpo'+'int\x20in\x20dei'+'ne\x20Memory-'+_0x3bcdbc(0xeb)+_0x3bcdbc(0xdf)+'YYY-MM-DD.'+_0x3bcdbc(0x11e)+_0x3bcdbc(0xe5)+_0x3bcdbc(0xbe)+_0x3bcdbc(0xf0)+'\x0a')+_0x5c0c09);}const _0x1f64e5=buildRuntimeHeader(),_0x4b7a8a=_0x57a729['systemProm'+'pt']?_0x1f64e5+'\x0a\x0a'+_0x57a729['systemProm'+'pt']+'\x0a\x0a'+botClaudeMd:_0x1f64e5+'\x0a\x0a'+botClaudeMd;let _0x156bdb;_0x57a729[_0x23df5c(0xcb)+'l']&&(_0x156bdb=new AbortController(),_0x57a729[_0x3bcdbc(0xcb)+'l'][_0x3bcdbc(0xa9)]?_0x156bdb[_0x3bcdbc(0xd8)]():_0x57a729[_0x23df5c(0xcb)+'l'][_0x23df5c(0xc4)+_0x3bcdbc(0xdb)](_0x3bcdbc(0xd8),()=>_0x156bdb?.[_0x23df5c(0xd8)](),{'once':!![]}));try{const _0x30adc6=findClaudeBinary(),_0x369580={};_0x57a729[_0x3bcdbc(0xd6)+_0x3bcdbc(0xc7)]&&(_0x369580[_0x3bcdbc(0xd7)]=buildAlvinMcpServer(_0x57a729['alvinDispa'+'tchContext']));const _0x1635cb=[_0x23df5c(0xc2),_0x23df5c(0xc0),_0x23df5c(0x10e),_0x23df5c(0xf1),'Glob','Grep',_0x23df5c(0x10c),_0x23df5c(0x14a),_0x3bcdbc(0xf8)];_0x57a729[_0x3bcdbc(0xd6)+_0x3bcdbc(0xc7)]&&_0x1635cb[_0x23df5c(0x109)](_0x23df5c(0x142)+_0x3bcdbc(0xea)+_0x3bcdbc(0xdc));const _0x54c861=_0x57a729[_0x3bcdbc(0x11a)]??this['config'][_0x23df5c(0x11a)],_0x104b2a=_0x54c861&&_0x54c861!==_0x3bcdbc(0xf2)?_0x54c861:undefined,_0x39b662=(_0x104b2a??'')[_0x3bcdbc(0xe1)+'e']()['includes'](_0x23df5c(0xe2)),_0x55b294=_0x39b662?undefined:_0x3bcdbc(0xe2),_0x305e93=query({'prompt':_0x57a729[_0x3bcdbc(0x141)+'el']?_0x57a729[_0x3bcdbc(0x141)+'el']:_0x5c0c09,'options':{'cwd':_0x57a729[_0x23df5c(0x13a)]||process[_0x3bcdbc(0x110)](),'abortController':_0x156bdb,'resume':_0x57a729['sessionId']??undefined,'pathToClaudeCodeExecutable':_0x30adc6,'permissionMode':'bypassPerm'+'issions','allowDangerouslySkipPermissions':!![],'env':_0x3e5ab0,'settingSources':[_0x3bcdbc(0xae),'project'],'allowedTools':_0x57a729[_0x3bcdbc(0xe3)+'ls']??_0x1635cb,'mcpServers':Object[_0x23df5c(0x145)](_0x369580)[_0x3bcdbc(0xc6)]>0xd*-0x4d+0x1d*-0xdf+-0x1d2c*-0x1?_0x369580:undefined,'systemPrompt':_0x4b7a8a,'effort':_0x57a729[_0x3bcdbc(0x147)]||'medium','maxTurns':0x32,'betas':['context-1m'+'-2025-08-0'+'7'],..._0x104b2a?{'model':_0x104b2a}:{},...typeof _0x57a729['temperatur'+'e']===_0x23df5c(0x114)?{'temperature':_0x57a729[_0x3bcdbc(0x119)+'e']}:{},..._0x55b294?{'fallbackModel':_0x55b294}:{}}});try{_0x57a729[_0x3bcdbc(0xdd)+_0x3bcdbc(0xd0)]?.(_0x305e93);}catch{}let _0x2bbf75='',_0x34ae4a=_0x57a729[_0x3bcdbc(0x148)]||'',_0x5d2193=-0x2406+0x1*-0x101e+0x3424;for await(const _0x486079 of _0x305e93){if(_0x57a729[_0x23df5c(0xcb)+'l']?.[_0x23df5c(0xa9)]){try{_0x305e93[_0x23df5c(0xb9)]?.();}catch{}break;}if(_0x486079[_0x23df5c(0x107)]===_0x3bcdbc(0x10d)&&_0x3bcdbc(0xc9)in _0x486079&&_0x486079['subtype']==='init'){const _0x14447a=_0x486079;_0x34ae4a=_0x14447a[_0x23df5c(0x115)];}if(_0x486079[_0x3bcdbc(0x107)]===_0x23df5c(0x157)){const _0x5b14da=_0x486079;_0x34ae4a=_0x5b14da['session_id'];if(_0x5b14da['message']?.[_0x3bcdbc(0x11c)])for(const _0x3a8aa2 of _0x5b14da[_0x3bcdbc(0x126)]['content']){if(_0x23df5c(0xb4)in _0x3a8aa2&&_0x3a8aa2[_0x3bcdbc(0xb4)]){if(!_0x2bbf75&&isAuthErrorOutput(_0x3a8aa2[_0x23df5c(0xb4)])){yield{'type':'error','error':'Claude\x20CLI'+_0x3bcdbc(0x151)+'gged\x20in.\x20R'+_0x23df5c(0x105)+_0x23df5c(0xbf)+_0x3bcdbc(0xd3)+_0x3bcdbc(0x10a)};return;}if(!_0x2bbf75&&isQuotaLimitOutput(_0x3a8aa2['text'])){const _0x53e9df=_0x3bcdbc(0xfd)+_0x3a8aa2[_0x23df5c(0xb4)][_0x23df5c(0xc5)]()+(_0x23df5c(0xcf)+_0x23df5c(0x150)+_0x3bcdbc(0xef)+_0x23df5c(0x11d)+'\x20No\x20messag'+'e\x20was\x20sent'+'\x20to\x20Claude'+'.');this['invalidate'+_0x23df5c(0x113)+_0x3bcdbc(0xd5)](),yield{'type':_0x3bcdbc(0xb4),'text':_0x53e9df,'delta':_0x53e9df,'sessionId':_0x34ae4a},_0x2bbf75=_0x53e9df;continue;}_0x2bbf75+=_0x3a8aa2[_0x23df5c(0xb4)],yield{'type':_0x3bcdbc(0xb4),'text':_0x2bbf75,'delta':_0x3a8aa2[_0x3bcdbc(0xb4)],'sessionId':_0x34ae4a};}if(_0x23df5c(0xb3)in _0x3a8aa2){_0x5d2193++;let _0x4d5f2e;if(_0x3bcdbc(0xf4)in _0x3a8aa2&&_0x3a8aa2[_0x23df5c(0xf4)]&&typeof _0x3a8aa2[_0x23df5c(0xf4)]==='object'){const _0x2c731a=_0x3a8aa2['input'];if(_0x2c731a['run_in_bac'+_0x3bcdbc(0x14f)]===!![])_0x4d5f2e=!![];else{if(_0x2c731a[_0x23df5c(0xd2)+_0x3bcdbc(0x14f)]===![])_0x4d5f2e=![];}}let _0x3ae279;if(_0x23df5c(0xf4)in _0x3a8aa2&&_0x3a8aa2[_0x3bcdbc(0xf4)]!==undefined)try{const _0x2afee6=JSON[_0x3bcdbc(0x12f)](_0x3a8aa2['input']);_0x3ae279=_0x2afee6[_0x23df5c(0xc6)]>0x22c3*0x1+0xdd*-0x13+0x4b*-0x38?_0x2afee6[_0x3bcdbc(0x122)](0xe56+-0x75d*-0x1+0xb*-0x1f9,0x2606+-0xe*0x29+0x2*-0x10ea)+'…':_0x2afee6;}catch{}const _0x2b3bbc=_0x3a8aa2['id'];yield{'type':_0x23df5c(0xed),'toolName':_0x3a8aa2[_0x3bcdbc(0xb3)],'toolInput':_0x3ae279,'toolUseId':_0x2b3bbc,'runInBackground':_0x4d5f2e,'sessionId':_0x34ae4a};}}}if(_0x486079[_0x3bcdbc(0x107)]===_0x23df5c(0xae)){const _0x432d2b=_0x486079,_0x568903=_0x432d2b['message']?.[_0x3bcdbc(0x11c)];if(Array[_0x23df5c(0x10b)](_0x568903))for(const _0x59ed75 of _0x568903){if(_0x59ed75&&typeof _0x59ed75===_0x3bcdbc(0x117)&&_0x59ed75[_0x3bcdbc(0x107)]===_0x23df5c(0x11b)+'t'&&typeof _0x59ed75['tool_use_i'+'d']===_0x23df5c(0x12e)){let _0x230176='';if(typeof _0x59ed75[_0x3bcdbc(0x11c)]==='string')_0x230176=_0x59ed75[_0x3bcdbc(0x11c)];else Array[_0x23df5c(0x10b)](_0x59ed75[_0x3bcdbc(0x11c)])&&(_0x230176=_0x59ed75[_0x23df5c(0x11c)][_0x3bcdbc(0xa6)](_0x5be94f=>{const _0x2c2642=_0x23df5c,_0x417f87=_0x23df5c;if(_0x5be94f&&typeof _0x5be94f===_0x2c2642(0x117)&&_0x2c2642(0xb4)in _0x5be94f){const _0x5bc1da=_0x5be94f[_0x2c2642(0xb4)];return typeof _0x5bc1da===_0x417f87(0x12e)?_0x5bc1da:'';}return'';})[_0x3bcdbc(0x130)](''));yield{'type':'tool_resul'+'t','toolUseId':_0x59ed75[_0x3bcdbc(0x14d)+'d'],'toolResultContent':_0x230176,'sessionId':_0x34ae4a};}}}if(_0x486079['type']===_0x23df5c(0x123)){const _0x16c7ff=_0x486079,_0xa2f8a7=_0x23df5c(0x13e)in _0x16c7ff?_0x16c7ff[_0x3bcdbc(0x13e)]:null,_0x1e8d78=_0xa2f8a7?(_0xa2f8a7['input_toke'+'ns']||-0x2363+0x1395+0xfce)+(_0xa2f8a7[_0x3bcdbc(0x11f)+_0x3bcdbc(0x136)+_0x23df5c(0xa8)]||-0x210e+0xd06+-0x1*-0x1408)+(_0xa2f8a7['cache_read'+_0x23df5c(0xb1)+_0x23df5c(0x133)]||-0x67*-0x50+-0x626*-0x2+-0x92*0x4e):0x13a5+-0x43*-0x26+-0x3*0x9dd,_0x54289e=_0xa2f8a7?.[_0x23df5c(0x112)+_0x3bcdbc(0x133)]||0x4c9+-0x831+0x368;if(_0x2bbf75===''&&_0x54289e===0x22c9+-0x1*-0x2653+-0x491c){this['invalidate'+'Availabili'+_0x23df5c(0xd5)]();try{const _0x4823ac={'subtype':_0x16c7ff[_0x3bcdbc(0xc9)],'is_error':_0x16c7ff[_0x3bcdbc(0x129)],'num_turns':_0x16c7ff[_0x3bcdbc(0x132)],'duration_ms':_0x16c7ff[_0x23df5c(0xd9)+'s'],'duration_api_ms':_0x16c7ff[_0x3bcdbc(0xf6)+_0x23df5c(0xf7)],'total_cost_usd':_0x16c7ff[_0x3bcdbc(0x13c)+'_usd'],'session_id':_0x16c7ff[_0x3bcdbc(0x115)],'passed_session_id':_0x57a729[_0x23df5c(0x148)]??null,'usage':_0xa2f8a7,'modelOverride':_0x104b2a,'cwd':_0x57a729['workingDir'],'effort':_0x57a729[_0x23df5c(0x147)],'systemPromptLen':_0x4b7a8a[_0x3bcdbc(0xc6)],'promptLen':_0x5c0c09[_0x3bcdbc(0xc6)],'historyLen':_0x57a729[_0x3bcdbc(0xad)]?.['length']??0x17c7+0x80d+-0x3*0xa9c,'allowedToolsCount':(_0x57a729[_0x3bcdbc(0xe3)+'ls']??_0x1635cb)[_0x3bcdbc(0xc6)],'hasMcp':Object[_0x3bcdbc(0x145)](_0x369580)['length']>-0x61+0x658+-0x5f7*0x1};console['warn']('[empty-str'+_0x3bcdbc(0xff)+_0x23df5c(0x154)+'output\x20tok'+_0x23df5c(0x10f)+_0x23df5c(0x131)+'p:',JSON['stringify'](_0x4823ac));}catch(_0x39a570){console[_0x23df5c(0xa4)](_0x3bcdbc(0x140)+'eam]\x20SDK\x20r'+_0x3bcdbc(0x154)+_0x23df5c(0xe9)+'ens\x20(diagn'+_0x23df5c(0x138)+_0x3bcdbc(0x155)+_0x23df5c(0xa5)+_0x39a570+')');}const _0x303985=_0x23df5c(0xb6)+_0x3bcdbc(0xa7)+'mit\x20leerem'+_0x3bcdbc(0x143)+('Meist\x20Folg'+_0x23df5c(0x111)+_0x23df5c(0x127)+_0x3bcdbc(0xb0)+'\x20/extra-us'+_0x23df5c(0x13d)+_0x23df5c(0xaa)+_0x3bcdbc(0xf5)+'.\x20')+('Ich\x20starte'+_0x3bcdbc(0xba)+_0x23df5c(0xbc)+_0x23df5c(0x14b)+_0x3bcdbc(0x139)+_0x3bcdbc(0x100)+_0x23df5c(0x102)+_0x23df5c(0x134)+_0x23df5c(0x14e));yield{'type':_0x3bcdbc(0xb4),'text':_0x303985,'delta':_0x303985,'sessionId':_0x16c7ff[_0x23df5c(0x115)]||_0x34ae4a,'sessionResetRequested':!![]};}const _0x56cbc0='subtype'in _0x16c7ff&&_0x16c7ff[_0x23df5c(0xc9)]===_0x23df5c(0xda)&&typeof _0x16c7ff[_0x3bcdbc(0x123)]===_0x3bcdbc(0x12e)?_0x16c7ff['result']:undefined;yield{'type':_0x23df5c(0x103),'text':_0x2bbf75||'',..._0x56cbc0!==undefined?{'finalResult':_0x56cbc0}:{},'sessionId':_0x16c7ff[_0x23df5c(0x115)]||_0x34ae4a,'costUsd':'total_cost'+_0x3bcdbc(0xc3)in _0x16c7ff?_0x16c7ff[_0x23df5c(0x13c)+_0x3bcdbc(0xc3)]:0x146b+0x719+-0x4*0x6e1,'inputTokens':_0x1e8d78,'outputTokens':_0x54289e};}}}catch(_0x1bc051){_0x1bc051 instanceof Error&&_0x1bc051[_0x3bcdbc(0x126)]['includes']('abort')?yield{'type':_0x23df5c(0xfe),'error':'Request\x20ab'+_0x3bcdbc(0xca)}:yield{'type':_0x23df5c(0xfe),'error':_0x3bcdbc(0x152)+_0x3bcdbc(0xb7)+(_0x1bc051 instanceof Error?_0x1bc051[_0x23df5c(0x126)]:String(_0x1bc051))};}}async[_0x4e769c(0x125)+'e'](){const _0x1f491d=_0x5c88d4,_0x14c4fb=_0x5c88d4,_0x5e615e=Date[_0x1f491d(0xbb)]();if(this[_0x1f491d(0xd1)+_0x1f491d(0xd5)]&&this[_0x1f491d(0xd1)+_0x14c4fb(0xd5)][_0x1f491d(0x106)]>_0x5e615e)return this[_0x1f491d(0xd1)+'tyCache']['result'];const _0x1f05d2=_0x2d0cc0=>{const _0x356ee1=_0x14c4fb,_0x59613f=_0x1f491d;return this[_0x356ee1(0xd1)+'tyCache']={'result':_0x2d0cc0,'expiresAt':_0x5e615e+ClaudeSDKProvider[_0x59613f(0xcd)+_0x356ee1(0xe0)+'S']},_0x2d0cc0;};try{const _0x131854=findClaudeBinary();if(!_0x131854)return _0x1f05d2(![]);await execFileAsync(_0x131854,[_0x1f491d(0x144)],{'timeout':0x1388});try{const {stdout:_0x2facff}=await execFileAsync(_0x131854,[_0x14c4fb(0x137),_0x1f491d(0x128)],{'timeout':0x1388}),_0x291927=JSON['parse'](_0x2facff);if(_0x291927[_0x14c4fb(0x146)]===!![])return _0x1f05d2(!![]);return _0x1f05d2(![]);}catch(_0x1a1451){try{const {stdout:_0x4661fb}=await execFileAsync(_0x131854,['-p',_0x1f491d(0xb5),_0x14c4fb(0xbd)+_0x1f491d(0xc1),_0x14c4fb(0xb4)],{'timeout':0x3a98});return _0x1f05d2(!isAuthErrorOutput(_0x4661fb)&&!isQuotaLimitOutput(_0x4661fb));}catch{return void _0x1a1451,_0x1f05d2(![]);}}}catch{return _0x1f05d2(![]);}}[_0x4e769c(0x135)+'Availabili'+_0x5c88d4(0xd5)](){const _0x5ac024=_0x5c88d4,_0x3ac25b=_0x5c88d4;this[_0x5ac024(0xd1)+_0x5ac024(0xd5)]=null;}[_0x4e769c(0xe7)](){const _0x15a9a0=_0x4e769c,_0x5e85b9=_0x4e769c,_0x54dc9e=this['config']['model']===_0x15a9a0(0xf2)?_0x15a9a0(0x12a)+_0x15a9a0(0x12c):this[_0x5e85b9(0x120)]['model'];return{'name':this[_0x5e85b9(0x120)][_0x15a9a0(0xb3)],'model':_0x54dc9e,'status':'✅\x20Agent\x20SD'+'K\x20(CLI\x20aut'+'h)'};}}