openmausbot 0.1.78 → 0.1.80
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.
- package/dist/assets/index-Cu8BkIfo.js +305 -0
- package/dist/assets/{index-BqDJqf2C.js → index-D6RZKWks.js} +1 -1
- package/dist/assets/index-tfpeJAIG.css +1 -0
- package/dist/index.html +2 -2
- package/dist-server/container-mcp.js +11 -5
- package/dist-server/drivers/agents-proxy.js +21 -6
- package/dist-server/enterprise/server/index.js +0 -1
- package/dist-server/index.js +15942 -6859
- package/dist-server/local-computer.js +0 -1
- package/dist-server/mcp-server.js +8 -1
- package/dist-server/openmausbot.js +9303 -786
- package/dist-server/pair-cli.js +9303 -786
- package/dist-server/proxy-paths.js +0 -1
- package/dist-server/server/box.js +98 -41
- package/dist-server/server/browser-engine.js +1 -1
- package/dist-server/server/browser-runtime.js +11 -3
- package/dist-server/server/browser-tool-shape.js +72 -0
- package/dist-server/server/claude-accounts.js +1 -0
- package/dist-server/server/cli-setup.js +1 -1
- package/dist-server/server/composio.js +18 -0
- package/dist-server/server/config.js +16 -4
- package/dist-server/server/container-computer.js +0 -12
- package/dist-server/server/drivers/acp/core.js +4 -19
- package/dist-server/server/drivers/agents-proxy.js +27 -2
- package/dist-server/server/drivers/boxagent.js +48 -4
- package/dist-server/server/drivers/chat-mcp-tools.js +368 -0
- package/dist-server/server/drivers/chat-tool-approval.js +42 -0
- package/dist-server/server/drivers/claude.js +86 -38
- package/dist-server/server/drivers/codex.js +225 -75
- package/dist-server/server/drivers/grok.js +4 -0
- package/dist-server/server/drivers/minimax.js +11 -3
- package/dist-server/server/drivers/openai-chat-protocol.js +92 -0
- package/dist-server/server/drivers/openai-chat.js +332 -88
- package/dist-server/server/drivers/openai-compat.js +4 -0
- package/dist-server/server/drivers/pi.js +1 -9
- package/dist-server/server/harness/registry.js +2 -2
- package/dist-server/server/index.js +267 -50
- package/dist-server/server/managed-desktop.js +205 -0
- package/dist-server/server/model-context-window.js +20 -0
- package/dist-server/server/proxy-paths.js +0 -1
- package/dist-server/server/redact.js +1 -0
- package/dist-server/server/room-handoffs.js +57 -9
- package/dist-server/server/store.js +13 -1
- package/dist-server/server/tts/chatterbox.js +83 -0
- package/dist-server/server/tts/index.js +45 -12
- package/dist-server/server/workspace.js +12 -2
- package/dist-server/shared/ask-question.js +28 -0
- package/dist-server/shared/computer-contention.js +17 -0
- package/dist-server/vps-container-mcp.js +11 -5
- package/enterprise/server/index.js +0 -1
- package/package.json +1 -1
- package/dist/assets/index-DjwAroIZ.js +0 -305
- package/dist/assets/index-Pbb6Ao0s.css +0 -1
- package/dist-server/computer-proxy.js +0 -1196
- package/dist-server/server/computer-proxy.js +0 -1070
- package/dist-server/server/remote-computer.js +0 -170
|
@@ -18,7 +18,6 @@ import { augmentedPath } from "../env-path.js";
|
|
|
18
18
|
import { brokerSocketPath, describeSpawnFailure, execCli, killCliTree, spawnCli } from "../procs.js";
|
|
19
19
|
import { classifyResumeFailure, mayReplay, recoveryPromptFor } from "../resume-recovery.js";
|
|
20
20
|
import { ClaudeLoginController } from "./claude-login-auth.js";
|
|
21
|
-
import { computerProxyEnv } from "../container-computer.js";
|
|
22
21
|
import { gateServer, resultBudget } from "../mcp-gate-config.js";
|
|
23
22
|
import { newEventId, newId } from "../contracts.js";
|
|
24
23
|
import { askInputSummary, commandSummary, toolDetailPreview } from "../tool-summary.js";
|
|
@@ -26,7 +25,7 @@ import { classifyError, computeBackoff, interruptibleDelay, RETRY_MAX_ATTEMPTS }
|
|
|
26
25
|
import { applyClaudeInject, decodeInjectId, mergeLocalInject, probeLocalInjects, resolveInjectId, } from "./local-inject.js";
|
|
27
26
|
import { appendNative } from "./native.js";
|
|
28
27
|
import { SPAWNED_PROXIES } from "../proxy-paths.js";
|
|
29
|
-
import { ASK_USER_QUESTION_TOOL, askQuestionSummary, parseAskQuestions, questionChoices, } from "../../shared/ask-question.js";
|
|
28
|
+
import { ASK_USER_QUESTION_TOOL, askQuestionSummary, parseAskQuestions, parseChoices, questionChoices, } from "../../shared/ask-question.js";
|
|
30
29
|
/** Whether `claude` has been signed in.
|
|
31
30
|
*
|
|
32
31
|
* Credential storage is deliberately not inspected here. Claude Code uses the
|
|
@@ -244,11 +243,14 @@ export const CLAUDE_FLAG_FLOORS = {
|
|
|
244
243
|
"--strict-mcp-config": [1, 0, 60],
|
|
245
244
|
"--setting-sources": [1, 0, 122],
|
|
246
245
|
"--autocompact": [2, 1, 122],
|
|
246
|
+
// 2.1.267 is the first CLI that accepts it; below that the recorded prompt
|
|
247
|
+
// simply is not refreshed, which is the pre-existing behaviour.
|
|
248
|
+
"--system-prompt-snapshot": [2, 1, 267],
|
|
247
249
|
};
|
|
248
250
|
/** The newest floor above: a CLI at or past it accepts everything the
|
|
249
251
|
* harness sends. Below it the engine still works, minus the flags the CLI
|
|
250
252
|
* predates, and the Engines page suggests an update. */
|
|
251
|
-
export const CLAUDE_CONTEXT_CONTROL_MIN_VERSION = CLAUDE_FLAG_FLOORS["--
|
|
253
|
+
export const CLAUDE_CONTEXT_CONTROL_MIN_VERSION = CLAUDE_FLAG_FLOORS["--system-prompt-snapshot"];
|
|
252
254
|
/** `claude --version` prints "2.1.232 (Claude Code)"; the first dotted triple
|
|
253
255
|
* is the version. Null when nothing parses, e.g. a wrapper that prints its
|
|
254
256
|
* own banner first — see claudeCliSupports for how that is treated. */
|
|
@@ -274,9 +276,7 @@ export function claudeCliSupports(version, flag) {
|
|
|
274
276
|
return version === null || versionAtLeast(version, CLAUDE_FLAG_FLOORS[flag]);
|
|
275
277
|
}
|
|
276
278
|
/** The Engines-page notice for a CLI older than the newest floor. The engine
|
|
277
|
-
* keeps working
|
|
278
|
-
* no harness-picked compaction window and, on a very old CLI, no isolation
|
|
279
|
-
* from this machine's own Claude Code setup. */
|
|
279
|
+
* keeps working without the flags its CLI predates. */
|
|
280
280
|
export function claudeCliUpdate(version, cli) {
|
|
281
281
|
const parsed = parseClaudeCliVersion(version);
|
|
282
282
|
if (!parsed || versionAtLeast(parsed, CLAUDE_CONTEXT_CONTROL_MIN_VERSION))
|
|
@@ -284,12 +284,15 @@ export function claudeCliUpdate(version, cli) {
|
|
|
284
284
|
const floor = CLAUDE_CONTEXT_CONTROL_MIN_VERSION.join(".");
|
|
285
285
|
const missing = Object.keys(CLAUDE_FLAG_FLOORS)
|
|
286
286
|
.filter((flag) => !claudeCliSupports(parsed, flag));
|
|
287
|
+
const effects = [
|
|
288
|
+
...(missing.includes("--autocompact") ? ["no compaction window picked by OpenMausBot"] : []),
|
|
289
|
+
...(missing.includes("--setting-sources") ? ["bots still see this machine's own Claude Code setup"] : []),
|
|
290
|
+
...(missing.includes("--system-prompt-snapshot") ? ["coordinated resumed turns cannot refresh stale system prompts"] : []),
|
|
291
|
+
];
|
|
287
292
|
return {
|
|
288
293
|
title: "Update Claude Code for context controls",
|
|
289
294
|
message: `Claude Code ${parsed.join(".")} predates ${floor}, so bots run without ${missing.join(", ")}: ` +
|
|
290
|
-
"
|
|
291
|
-
(missing.includes("--setting-sources") ? ", and bots still see this machine's own Claude Code setup" : "") +
|
|
292
|
-
". Update it, then refresh Engines.",
|
|
295
|
+
`${effects.join("; ")}. Update it, then refresh Engines.`,
|
|
293
296
|
command: cli === "claude" ? "claude update" : `${cli} update`,
|
|
294
297
|
};
|
|
295
298
|
}
|
|
@@ -338,12 +341,15 @@ function extrasFromUnknown(value) {
|
|
|
338
341
|
* ANTHROPIC_API_KEY ("Not logged in · Please run /login"). Live injects
|
|
339
342
|
* come from mergeLocalInject. */
|
|
340
343
|
export function readClaudeModelCatalog(env = process.env) {
|
|
344
|
+
// A missing or unreadable settings.json is not fatal: an instance whose
|
|
345
|
+
// environment sets ANTHROPIC_MODEL (a Claude Code install pointed at an
|
|
346
|
+
// Anthropic-compatible host) still lists that model as Custom.
|
|
341
347
|
let settings = {};
|
|
342
348
|
try {
|
|
343
349
|
settings = JSON.parse(readFileSync(join(resolveClaudeConfigDir(undefined, env), "settings.json"), "utf8"));
|
|
344
350
|
}
|
|
345
351
|
catch {
|
|
346
|
-
|
|
352
|
+
settings = {};
|
|
347
353
|
}
|
|
348
354
|
const extras = [
|
|
349
355
|
...extrasFromUnknown(settings.availableModels),
|
|
@@ -367,7 +373,6 @@ export function readClaudeModelCatalog(env = process.env) {
|
|
|
367
373
|
// Resolved from the server root, never relative to this file: bundling inlines
|
|
368
374
|
// this module into an entry one directory up, so a `".."` here would climb too
|
|
369
375
|
// far. See server/proxy-paths.ts.
|
|
370
|
-
const PROXY_PATH = SPAWNED_PROXIES.computer;
|
|
371
376
|
const PERM_PROXY_PATH = SPAWNED_PROXIES.permission;
|
|
372
377
|
const DWEB_PROXY_PATH = SPAWNED_PROXIES.dweb;
|
|
373
378
|
// in the packaged app process.execPath is the Electron binary — this env
|
|
@@ -682,6 +687,7 @@ function decodeConfig(raw) {
|
|
|
682
687
|
return {
|
|
683
688
|
cli: typeof o.cli === "string" ? o.cli : "claude",
|
|
684
689
|
...(configDir ? { configDir } : {}),
|
|
690
|
+
...(o.managed === true ? { managed: true } : {}),
|
|
685
691
|
permissionMode: mode ?? "acceptEdits",
|
|
686
692
|
...(tools !== undefined ? { tools } : {}),
|
|
687
693
|
...(disallowedTools !== undefined ? { disallowedTools } : {}),
|
|
@@ -768,10 +774,12 @@ export const ClaudeDriver = {
|
|
|
768
774
|
defaultConfig: () => decodeConfig({}),
|
|
769
775
|
async create(input) {
|
|
770
776
|
const { instanceId, config } = input;
|
|
771
|
-
const environment = (model) => claudeEnvironment(model, { ...process.env, ...input.environment }, config.configDir, input.environment);
|
|
777
|
+
const environment = (model) => claudeEnvironment(config.managed ? undefined : model, { ...process.env, ...input.environment }, config.configDir, input.environment);
|
|
772
778
|
const catalogEnv = environment();
|
|
773
779
|
let models = STATIC_CLAUDE_MODELS;
|
|
774
780
|
const refreshModels = async () => {
|
|
781
|
+
if (config.managed)
|
|
782
|
+
return;
|
|
775
783
|
try {
|
|
776
784
|
const resolved = await mergeLocalInject(readClaudeModelCatalog(catalogEnv), catalogEnv);
|
|
777
785
|
if (resolved.options.length)
|
|
@@ -787,10 +795,14 @@ export const ClaudeDriver = {
|
|
|
787
795
|
// harness snapshots every instance whenever it describes them — app
|
|
788
796
|
// load, the Engines page, and right after `claude update`, which is
|
|
789
797
|
// exactly when the answer changes — so a turn normally finds it filled.
|
|
790
|
-
//
|
|
791
|
-
//
|
|
792
|
-
//
|
|
798
|
+
// Most turns before any snapshot assume a current CLI. A coordinated
|
|
799
|
+
// turn checks first because the snapshot-refresh flag is newer than the
|
|
800
|
+
// other context controls and an unknown flag would reject that request.
|
|
793
801
|
let cliVersion = null;
|
|
802
|
+
let cliVersionChecked = false;
|
|
803
|
+
const readCliVersion = (env) => new Promise((resolve) => {
|
|
804
|
+
execCli(config.cli, ["--version"], { timeout: 8000, env }, (err, stdout) => resolve(err ? null : stdout.trim() || null));
|
|
805
|
+
});
|
|
794
806
|
const listeners = new Set();
|
|
795
807
|
// one active turn per thread; a second send while busy is a caller bug
|
|
796
808
|
const active = new Map();
|
|
@@ -875,8 +887,16 @@ export const ClaudeDriver = {
|
|
|
875
887
|
// is a fresh sendTurn, and the attempt cap must survive across launches
|
|
876
888
|
const retryState = new Map();
|
|
877
889
|
const sendTurn = async (turn, logicalTurnId) => {
|
|
890
|
+
if (config.managed && (!turn.model || turn.model.includes("::") || !config.configDir ||
|
|
891
|
+
!input.environment.ANTHROPIC_API_KEY || !input.environment.ANTHROPIC_BASE_URL)) {
|
|
892
|
+
throw new Error("Company model access is unavailable. Reconnect your organization; personal billing will not be used.");
|
|
893
|
+
}
|
|
878
894
|
const { threadId, botId } = turn;
|
|
879
|
-
|
|
895
|
+
// An internal relaunch (transient failure, rejected resume) keeps the
|
|
896
|
+
// logical turn's stop handle in `active` while it sets up, so Stop is
|
|
897
|
+
// never a silent no-op between two CLI processes of the same turn.
|
|
898
|
+
const relaunch = logicalTurnId !== undefined;
|
|
899
|
+
if (active.has(threadId) && !relaunch)
|
|
880
900
|
throw new Error("a turn is already running on this thread");
|
|
881
901
|
// A bot-level mode is authoritative for this turn. In particular, an
|
|
882
902
|
// old provider instance may still be configured with
|
|
@@ -901,7 +921,10 @@ export const ClaudeDriver = {
|
|
|
901
921
|
const turnId = logicalTurnId ?? newId();
|
|
902
922
|
const retryAbort = new AbortController();
|
|
903
923
|
const retry = retryState.get(threadId) ?? { attempt: 0, cancelled: false };
|
|
904
|
-
|
|
924
|
+
// A fresh user turn starts un-cancelled. A relaunch must keep a Stop
|
|
925
|
+
// that landed while it was being scheduled.
|
|
926
|
+
if (!relaunch)
|
|
927
|
+
retry.cancelled = false;
|
|
905
928
|
retryState.set(threadId, retry);
|
|
906
929
|
// a retry relaunches the whole CLI; the backoff is scaled down in tests
|
|
907
930
|
// so a fake's transient failures don't stall real seconds
|
|
@@ -924,6 +947,13 @@ export const ClaudeDriver = {
|
|
|
924
947
|
args.push("--disallowedTools", config.disallowedTools.join(","));
|
|
925
948
|
}
|
|
926
949
|
const turnEnvironment = environment();
|
|
950
|
+
if (turn.refreshSystemPrompt && !cliVersionChecked) {
|
|
951
|
+
const version = await readCliVersion(turnEnvironment);
|
|
952
|
+
if (version) {
|
|
953
|
+
cliVersion = parseClaudeCliVersion(version);
|
|
954
|
+
cliVersionChecked = true;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
927
957
|
const isolated = !inheritsUserConfig(turnEnvironment);
|
|
928
958
|
if (isolated) {
|
|
929
959
|
// A bot gets the tools and instructions its owner gave it, not
|
|
@@ -944,8 +974,16 @@ export const ClaudeDriver = {
|
|
|
944
974
|
if (compactWindow && claudeCliSupports(cliVersion, "--autocompact")) {
|
|
945
975
|
args.push("--autocompact", compactWindow);
|
|
946
976
|
}
|
|
947
|
-
|
|
948
|
-
|
|
977
|
+
// An old pair conversation can still carry its first assignment in
|
|
978
|
+
// Claude's recorded system prompt. The current brief rides in the user
|
|
979
|
+
// turn, so refresh the recorded prompt on --resume too. Gated by the
|
|
980
|
+
// version floor like every other flag the CLI may predate: an unknown
|
|
981
|
+
// flag is a hard argument error, not a graceful degrade.
|
|
982
|
+
if (turn.refreshSystemPrompt && cliVersionChecked && claudeCliSupports(cliVersion, "--system-prompt-snapshot")) {
|
|
983
|
+
args.push("--system-prompt-snapshot", "off");
|
|
984
|
+
}
|
|
985
|
+
const turnModel = config.managed ? turn.model : await resolveClaudeTurnModel(turn.model, turnEnvironment);
|
|
986
|
+
const injected = config.managed ? { model: turnModel ?? null, injected: false } : applyClaudeInject({ ...turnEnvironment }, turnModel);
|
|
949
987
|
if (injected.model)
|
|
950
988
|
args.push("--model", injected.model);
|
|
951
989
|
if (turn.effort)
|
|
@@ -964,15 +1002,7 @@ export const ClaudeDriver = {
|
|
|
964
1002
|
mcpServers.composio = { ...turn.integrations.composio };
|
|
965
1003
|
allowed.push("mcp__composio");
|
|
966
1004
|
}
|
|
967
|
-
if (turn.integrations?.
|
|
968
|
-
mcpServers.computer = {
|
|
969
|
-
command: process.execPath,
|
|
970
|
-
args: [PROXY_PATH],
|
|
971
|
-
env: { ...NODE_ENV_FLAG, ...computerProxyEnv(turn.integrations.computer) },
|
|
972
|
-
};
|
|
973
|
-
allowed.push("mcp__computer");
|
|
974
|
-
}
|
|
975
|
-
else if (turn.integrations?.localComputer) {
|
|
1005
|
+
if (turn.integrations?.localComputer) {
|
|
976
1006
|
const local = turn.integrations.localComputer;
|
|
977
1007
|
mcpServers.computer = {
|
|
978
1008
|
command: local.command,
|
|
@@ -1216,9 +1246,7 @@ export const ClaudeDriver = {
|
|
|
1216
1246
|
questions: questions ?? undefined,
|
|
1217
1247
|
// A structured ask still offers flat labels, for the phone
|
|
1218
1248
|
// companions and any client that predates the question card.
|
|
1219
|
-
choices: questions
|
|
1220
|
-
? questionChoices(questions)
|
|
1221
|
-
: Array.isArray(ask.input?.choices) ? ask.input.choices.slice(0, 5) : undefined,
|
|
1249
|
+
choices: questions ? questionChoices(questions) : parseChoices(ask.input?.choices),
|
|
1222
1250
|
});
|
|
1223
1251
|
},
|
|
1224
1252
|
onResolve: (resolved) => {
|
|
@@ -1259,6 +1287,16 @@ export const ClaudeDriver = {
|
|
|
1259
1287
|
cleanupUnownedLaunch();
|
|
1260
1288
|
throw error;
|
|
1261
1289
|
}
|
|
1290
|
+
// Stop reached the relaunch handle while this attempt was still setting
|
|
1291
|
+
// up (model probe, broker). Settle the logical turn as interrupted
|
|
1292
|
+
// instead of spawning a process nobody wants.
|
|
1293
|
+
if (relaunch && retry.cancelled) {
|
|
1294
|
+
cleanupUnownedLaunch();
|
|
1295
|
+
if (active.get(threadId)?.turnId === turnId)
|
|
1296
|
+
active.delete(threadId);
|
|
1297
|
+
emit({ ...base(threadId, turnId), type: "turn.completed", ok: false, stopReason: "interrupted", cost: null });
|
|
1298
|
+
return { turnId };
|
|
1299
|
+
}
|
|
1262
1300
|
let child;
|
|
1263
1301
|
try {
|
|
1264
1302
|
child = spawnCli(config.cli, args, {
|
|
@@ -1409,6 +1447,9 @@ export const ClaudeDriver = {
|
|
|
1409
1447
|
...(typeof msg.usage.cache_read_input_tokens === "number"
|
|
1410
1448
|
? { cachedInput: msg.usage.cache_read_input_tokens }
|
|
1411
1449
|
: {}),
|
|
1450
|
+
// one assistant message = one model call, and its prompt is
|
|
1451
|
+
// everything in the window: fresh text, cache reads and writes
|
|
1452
|
+
contextTokens: (msg.usage.input_tokens || 0) + (msg.usage.cache_read_input_tokens || 0) + (msg.usage.cache_creation_input_tokens || 0),
|
|
1412
1453
|
});
|
|
1413
1454
|
}
|
|
1414
1455
|
break;
|
|
@@ -1544,14 +1585,18 @@ export const ClaudeDriver = {
|
|
|
1544
1585
|
});
|
|
1545
1586
|
return;
|
|
1546
1587
|
}
|
|
1547
|
-
//
|
|
1548
|
-
//
|
|
1549
|
-
|
|
1588
|
+
// Keep Stop reachable while the relaunch sets up: there is no
|
|
1589
|
+
// process yet, so this handle only records the cancellation and
|
|
1590
|
+
// the relaunched sendTurn honors it before spawning.
|
|
1591
|
+
retryState.set(threadId, retry);
|
|
1592
|
+
active.set(threadId, { stop: () => { retry.cancelled = true; retryAbort.abort(); }, turnId });
|
|
1550
1593
|
try {
|
|
1551
1594
|
const cursor = session.sessionId ?? sessionId ?? undefined;
|
|
1552
1595
|
await sendTurn({ ...turn, resumeCursor: cursor }, turnId);
|
|
1553
1596
|
}
|
|
1554
1597
|
catch (e) {
|
|
1598
|
+
if (active.get(threadId)?.turnId === turnId)
|
|
1599
|
+
active.delete(threadId);
|
|
1555
1600
|
retryState.delete(threadId);
|
|
1556
1601
|
emit({
|
|
1557
1602
|
...base(threadId, turnId),
|
|
@@ -1605,7 +1650,9 @@ export const ClaudeDriver = {
|
|
|
1605
1650
|
}
|
|
1606
1651
|
sessions.delete(threadId);
|
|
1607
1652
|
session.turn = null;
|
|
1608
|
-
|
|
1653
|
+
// Same relaunch handle as the transient-retry path above.
|
|
1654
|
+
retryState.set(threadId, retry);
|
|
1655
|
+
active.set(threadId, { stop: () => { retry.cancelled = true; retryAbort.abort(); }, turnId });
|
|
1609
1656
|
emit({
|
|
1610
1657
|
...base(threadId, turnId),
|
|
1611
1658
|
type: "turn.retrying",
|
|
@@ -1619,6 +1666,8 @@ export const ClaudeDriver = {
|
|
|
1619
1666
|
await sendTurn({ ...turn, resumeCursor: undefined, recoveryText: undefined, text: recovery.text }, turnId);
|
|
1620
1667
|
}
|
|
1621
1668
|
catch (e) {
|
|
1669
|
+
if (active.get(threadId)?.turnId === turnId)
|
|
1670
|
+
active.delete(threadId);
|
|
1622
1671
|
retryState.delete(threadId);
|
|
1623
1672
|
emit({
|
|
1624
1673
|
...base(threadId, turnId),
|
|
@@ -1687,12 +1736,11 @@ export const ClaudeDriver = {
|
|
|
1687
1736
|
const login = new ClaudeLoginController({ cli: config.cli, environment, onAuthenticated: async () => { await refreshModels(); } });
|
|
1688
1737
|
const snapshot = async () => {
|
|
1689
1738
|
const env = environment();
|
|
1690
|
-
const version = await
|
|
1691
|
-
execCli(config.cli, ["--version"], { timeout: 8000, env }, (err, stdout) => resolve(err ? null : stdout.trim()));
|
|
1692
|
-
});
|
|
1739
|
+
const version = await readCliVersion(env);
|
|
1693
1740
|
if (!version)
|
|
1694
1741
|
return { state: "unavailable", reason: `\`${config.cli}\` CLI not found` };
|
|
1695
1742
|
cliVersion = parseClaudeCliVersion(version);
|
|
1743
|
+
cliVersionChecked = true;
|
|
1696
1744
|
const auth = await claudeAuthStatus(config.cli, env);
|
|
1697
1745
|
// claudeEnvironment strips ANTHROPIC_API_KEY, so turns run on the
|
|
1698
1746
|
// CLI's own login (Pro/Max): the cost it reports is what the call
|