claudish 10.6.3 → 10.7.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.
package/dist/index.js CHANGED
@@ -901,7 +901,7 @@ var init_onepassword_config = __esm(() => {
901
901
  });
902
902
 
903
903
  // src/version.ts
904
- var VERSION = "10.6.3";
904
+ var VERSION = "10.7.0";
905
905
 
906
906
  // src/logger.ts
907
907
  import { appendFile, existsSync as existsSync2, mkdirSync, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
@@ -18828,6 +18828,10 @@ function lookupModelReasoningStatus(modelId, cachePath) {
18828
18828
  const entry = findCacheEntry(modelId, cachePath);
18829
18829
  return entry ? reasoningStatusOf(entry) : undefined;
18830
18830
  }
18831
+ function lookupModelMaxOutputTokens(modelId, cachePath) {
18832
+ const value = findCacheEntry(modelId, cachePath)?.maxOutputTokens;
18833
+ return typeof value === "number" && value > 0 ? value : undefined;
18834
+ }
18831
18835
  function lookupRouteReasoningMode(modelId, provider, cachePath) {
18832
18836
  return findCacheEntry(modelId, cachePath)?.aggregators?.find((aggregator) => catalogRouteMatchesProvider(aggregator.route, provider))?.reasoning?.mode;
18833
18837
  }
@@ -20945,6 +20949,7 @@ ${merged}`;
20945
20949
  var AnthropicAPIFormat;
20946
20950
  var init_anthropic_api_format = __esm(() => {
20947
20951
  init_base_api_format();
20952
+ init_model_catalog();
20948
20953
  AnthropicAPIFormat = class AnthropicAPIFormat extends BaseAPIFormat {
20949
20954
  constructor(modelId, _providerName) {
20950
20955
  super(modelId);
@@ -20985,14 +20990,24 @@ var init_anthropic_api_format = __esm(() => {
20985
20990
  convertTools(claudeRequest, _summarize) {
20986
20991
  return claudeRequest.tools || [];
20987
20992
  }
20993
+ outputLimitFor(claudeRequest) {
20994
+ const inbound = claudeRequest?.max_tokens;
20995
+ if (typeof inbound === "number")
20996
+ return inbound;
20997
+ if (this.modelId.includes("@"))
20998
+ return;
20999
+ return lookupModelMaxOutputTokens(this.modelId);
21000
+ }
20988
21001
  buildPayload(claudeRequest, messages, tools) {
20989
21002
  const { messages: cleanMessages, hoisted } = hoistInlineSystem(messages);
20990
21003
  const payload = {
20991
21004
  model: this.modelId,
20992
21005
  messages: cleanMessages,
20993
- max_tokens: claudeRequest.max_tokens || 4096,
20994
21006
  stream: true
20995
21007
  };
21008
+ const maxTokens = this.outputLimitFor(claudeRequest);
21009
+ if (maxTokens !== undefined)
21010
+ payload.max_tokens = maxTokens;
20996
21011
  const system = mergeSystem(claudeRequest.system, hoisted);
20997
21012
  if (system !== undefined) {
20998
21013
  payload.system = system;
@@ -31135,6 +31150,7 @@ function resolveConnection(provider, modelName, cachePath = ALL_MODELS_CACHE_PAT
31135
31150
  wire: found.connection.wire,
31136
31151
  profile,
31137
31152
  generationId: cache.routeRegistry.generationId,
31153
+ ...typeof found.entry.maxOutputTokens === "number" && found.entry.maxOutputTokens > 0 ? { maxOutputTokens: found.entry.maxOutputTokens } : {},
31138
31154
  ...ownerWire ? { ownerWire } : {}
31139
31155
  }
31140
31156
  };
@@ -32575,6 +32591,19 @@ function wireChoicesFromClaudeRequest(claudeRequest, pinnedEffort) {
32575
32591
  maxTokens: typeof claudeRequest?.max_tokens === "number" ? claudeRequest.max_tokens : undefined
32576
32592
  };
32577
32593
  }
32594
+ function outputLimitToSend(wire, choices, result) {
32595
+ if (typeof choices.maxTokens === "number")
32596
+ return choices.maxTokens;
32597
+ if (!LIMIT_REQUIRED_APIS.has(wire.api))
32598
+ return;
32599
+ const ceiling = choices.catalogMaxOutputTokens;
32600
+ if (typeof ceiling === "number" && ceiling > 0) {
32601
+ result.notes.push(`request has no output limit: sent the catalog's maxOutputTokens ${ceiling}`);
32602
+ return ceiling;
32603
+ }
32604
+ result.notes.push("request has no output limit and the catalog publishes no maxOutputTokens: none sent");
32605
+ return;
32606
+ }
32578
32607
  function shapeRequestFromWire(body, wire, choices, owner) {
32579
32608
  const result = { headers: [], notes: [], borrowed: [] };
32580
32609
  stripWireDecisions(body, wire.api);
@@ -32585,12 +32614,13 @@ function shapeRequestFromWire(body, wire, choices, owner) {
32585
32614
  result.borrowed.push(path);
32586
32615
  };
32587
32616
  const sameApiOwner = owner && owner !== wire && owner.api === wire.api ? owner : undefined;
32617
+ const maxTokens = outputLimitToSend(wire, choices, result);
32588
32618
  if (typeof wire.tokenParam === "string") {
32589
- if (typeof choices.maxTokens === "number")
32590
- body[wire.tokenParam] = choices.maxTokens;
32619
+ if (typeof maxTokens === "number")
32620
+ body[wire.tokenParam] = maxTokens;
32591
32621
  } else if (wire.api !== "gemini") {
32592
- if (wire.tokenParam.status === "unknown" && sameApiOwner && typeof sameApiOwner.tokenParam === "string" && typeof choices.maxTokens === "number") {
32593
- borrow(`/${sameApiOwner.tokenParam}`, choices.maxTokens);
32622
+ if (wire.tokenParam.status === "unknown" && sameApiOwner && typeof sameApiOwner.tokenParam === "string" && typeof maxTokens === "number") {
32623
+ borrow(`/${sameApiOwner.tokenParam}`, maxTokens);
32594
32624
  result.notes.push(`tokenParam ${wire.tokenParam.status}: trying the owner's ${sameApiOwner.tokenParam}`);
32595
32625
  } else {
32596
32626
  result.notes.push(`tokenParam ${wire.tokenParam.status}: no output limit sent`);
@@ -32641,7 +32671,7 @@ function mergeWireHeaders(headers, extra) {
32641
32671
  headers[key] = `${existing},${header.value}`;
32642
32672
  }
32643
32673
  }
32644
- var WIRE_EFFORT_ORDER, WIRE_SPEEDS, TOKEN_LIMIT_FIELDS, DECISION_POINTERS;
32674
+ var WIRE_EFFORT_ORDER, WIRE_SPEEDS, TOKEN_LIMIT_FIELDS, DECISION_POINTERS, LIMIT_REQUIRED_APIS;
32645
32675
  var init_wire_request = __esm(() => {
32646
32676
  WIRE_EFFORT_ORDER = [
32647
32677
  "none",
@@ -32673,6 +32703,7 @@ var init_wire_request = __esm(() => {
32673
32703
  "/service_tier",
32674
32704
  "/speed"
32675
32705
  ];
32706
+ LIMIT_REQUIRED_APIS = new Set(["anthropic-messages"]);
32676
32707
  });
32677
32708
 
32678
32709
  // src/providers/wire-markers.ts
@@ -32921,7 +32952,7 @@ var init_vision_proxy = __esm(() => {
32921
32952
  init_catalog_query();
32922
32953
  });
32923
32954
 
32924
- // src/channel/home-dir.ts
32955
+ // src/mcp-session/home-dir.ts
32925
32956
  import { homedir as homedir23 } from "os";
32926
32957
  import { join as join23 } from "path";
32927
32958
  function userHomeFrom(env, homedirFn = homedir23) {
@@ -33251,8 +33282,8 @@ class SessionEventRegistry {
33251
33282
  }
33252
33283
  var MISS_TTL_MS = 5000, MAX_MISSES = 5, IDLE_SWEEP_MS, sessionEvents;
33253
33284
  var init_session_events = __esm(() => {
33254
- init_home_dir();
33255
33285
  init_logger();
33286
+ init_home_dir();
33256
33287
  init_event_translator();
33257
33288
  init_transcript_tailer();
33258
33289
  IDLE_SWEEP_MS = 30 * 60 * 1000;
@@ -37481,6 +37512,7 @@ class ComposedHandler {
37481
37512
  if (wire?.status === "known") {
37482
37513
  const choices = {
37483
37514
  ...wireChoicesFromClaudeRequest(claudeRequest, this.options.effortOverride),
37515
+ catalogMaxOutputTokens: this.options.connection?.maxOutputTokens,
37484
37516
  acceptServedModelChange: process.env.CLAUDISH_ACCEPT_SERVED_MODEL === "1"
37485
37517
  };
37486
37518
  const markers = wireMarkerContext.getStore();
@@ -43917,67 +43949,7 @@ var init_prehydrate = __esm(() => {
43917
43949
  init_op_source();
43918
43950
  });
43919
43951
 
43920
- // src/channel/diagnostics.ts
43921
- import { appendFileSync as appendFileSync5 } from "fs";
43922
- function traceEnabled() {
43923
- return process.env[TRACE_ENV] === "1";
43924
- }
43925
- function emit(line) {
43926
- const formatted = `[channel-trace] ${line}
43927
- `;
43928
- process.stderr.write(formatted);
43929
- const filePath = process.env[TRACE_FILE_ENV];
43930
- if (filePath) {
43931
- try {
43932
- appendFileSync5(filePath, formatted);
43933
- } catch {}
43934
- }
43935
- }
43936
- function wrapStateChange(fn) {
43937
- if (!traceEnabled())
43938
- return fn;
43939
- return (sessionId, event) => {
43940
- emit(`fired sid=${sessionId} type=${event.type} model=${event.model} elapsed=${event.elapsedSeconds}s`);
43941
- try {
43942
- fn(sessionId, event);
43943
- emit(`callback returned sid=${sessionId} type=${event.type}`);
43944
- } catch (err) {
43945
- emit(`callback THREW sid=${sessionId} type=${event.type} err=${err?.message ?? err}`);
43946
- throw err;
43947
- }
43948
- };
43949
- }
43950
- function watchNotificationResult(result, context) {
43951
- if (!traceEnabled())
43952
- return;
43953
- if (result && typeof result.then === "function") {
43954
- result.catch((err) => {
43955
- emit(`notification REJECTED sid=${context.sessionId} type=${context.eventType} err=${err?.message ?? err}`);
43956
- });
43957
- }
43958
- }
43959
- function installWireTap() {
43960
- if (!traceEnabled())
43961
- return;
43962
- if (wireTapInstalled)
43963
- return;
43964
- wireTapInstalled = true;
43965
- const originalWrite = process.stdout.write.bind(process.stdout);
43966
- process.stdout.write = (chunk, ...rest) => {
43967
- try {
43968
- const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf-8");
43969
- if (text.includes('"notifications/claude/channel"')) {
43970
- emit(`WIRE-OUT ${text.trim()}`);
43971
- }
43972
- } catch {}
43973
- return originalWrite(chunk, ...rest);
43974
- };
43975
- emit("wire tap installed");
43976
- }
43977
- var TRACE_ENV = "CLAUDISH_CHANNEL_TRACE", TRACE_FILE_ENV = "CLAUDISH_CHANNEL_TRACE_FILE", wireTapInstalled = false;
43978
- var init_diagnostics = () => {};
43979
-
43980
- // src/channel/scrollback-buffer.ts
43952
+ // src/mcp-session/scrollback-buffer.ts
43981
43953
  class ScrollbackBuffer {
43982
43954
  lines;
43983
43955
  head;
@@ -44098,8 +44070,116 @@ var init_contract = __esm(() => {
44098
44070
  };
44099
44071
  });
44100
44072
 
44073
+ // src/pane/reason-detail.ts
44074
+ import { closeSync as closeSync6, fstatSync, openSync as openSync6, readSync as readSync2 } from "fs";
44075
+ function reasonDetail(input, upstreamRecords = []) {
44076
+ if (!isTerminalState(input.state) || input.state === "COMPLETED")
44077
+ return null;
44078
+ if (input.reason === "api_error") {
44079
+ const last = upstreamRecords.length ? upstreamRecords[upstreamRecords.length - 1] : undefined;
44080
+ const upstream = last === undefined ? null : upstreamMessage(last);
44081
+ if (upstream)
44082
+ return oneLine4(upstream);
44083
+ const child = firstLine(input.detail);
44084
+ return child ? oneLine4(apiErrorText(child)) : null;
44085
+ }
44086
+ const first = firstLine(input.detail);
44087
+ return first ? oneLine4(first) : null;
44088
+ }
44089
+ function upstreamRecordsFor(input, upstreamLogPath) {
44090
+ if (!upstreamLogPath || input.reason !== "api_error" || !isTerminalState(input.state))
44091
+ return [];
44092
+ return readTailLines(upstreamLogPath, UPSTREAM_TAIL_BYTES);
44093
+ }
44094
+ function firstLine(text) {
44095
+ if (!text)
44096
+ return null;
44097
+ const line = text.split(/\r?\n/).find((l) => l.trim().length > 0);
44098
+ return line ? line.trim() : null;
44099
+ }
44100
+ function oneLine4(text) {
44101
+ const flat = text.replace(/\s+/g, " ").trim();
44102
+ if (!flat)
44103
+ return null;
44104
+ return flat.length > REASON_DETAIL_MAX_CHARS ? `${flat.slice(0, REASON_DETAIL_MAX_CHARS - 1).trimEnd()}\u2026` : flat;
44105
+ }
44106
+ function apiErrorText(detail) {
44107
+ const text = detail.split(" \xB7 ")[0].replace(/^The turn ended in an API error(?:\s*\(status \d+\))?:\s*/i, "").replace(/^API Error:?\s*(?:\d{3}\b)?\s*/i, "").trim();
44108
+ if (/^[[{]/.test(text))
44109
+ return messageOfJsonText(text) ?? "";
44110
+ return text;
44111
+ }
44112
+ function upstreamMessage(record) {
44113
+ let parsed;
44114
+ try {
44115
+ parsed = JSON.parse(record);
44116
+ } catch {
44117
+ return null;
44118
+ }
44119
+ if (!isObject3(parsed))
44120
+ return null;
44121
+ const body = parsed.body;
44122
+ if (typeof body === "string")
44123
+ return messageOfJsonText(body);
44124
+ return messageOf(body);
44125
+ }
44126
+ function messageOfJsonText(text) {
44127
+ try {
44128
+ return messageOf(JSON.parse(text));
44129
+ } catch {
44130
+ const m = /"error"\s*:\s*\{[^{}]*?"message"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(text);
44131
+ if (!m)
44132
+ return null;
44133
+ try {
44134
+ return nonEmpty2(JSON.parse(`"${m[1]}"`));
44135
+ } catch {
44136
+ return null;
44137
+ }
44138
+ }
44139
+ }
44140
+ function messageOf(value) {
44141
+ const v = Array.isArray(value) ? value[0] : value;
44142
+ if (!isObject3(v) || !isObject3(v.error))
44143
+ return null;
44144
+ return nonEmpty2(v.error.message);
44145
+ }
44146
+ function nonEmpty2(v) {
44147
+ return typeof v === "string" && v.trim().length > 0 ? v : null;
44148
+ }
44149
+ function isObject3(v) {
44150
+ return typeof v === "object" && v !== null && !Array.isArray(v);
44151
+ }
44152
+ function readTailLines(path, maxBytes) {
44153
+ let fd = null;
44154
+ try {
44155
+ fd = openSync6(path, "r");
44156
+ const size = fstatSync(fd).size;
44157
+ const start = Math.max(0, size - maxBytes);
44158
+ const buf = Buffer.alloc(size - start);
44159
+ readSync2(fd, buf, 0, buf.length, start);
44160
+ const lines = buf.toString("utf-8").split(`
44161
+ `);
44162
+ if (start > 0)
44163
+ lines.shift();
44164
+ return lines.filter((l) => l.trim().length > 0);
44165
+ } catch {
44166
+ return [];
44167
+ } finally {
44168
+ if (fd !== null) {
44169
+ try {
44170
+ closeSync6(fd);
44171
+ } catch {}
44172
+ }
44173
+ }
44174
+ }
44175
+ var REASON_DETAIL_MAX_CHARS = 160, UPSTREAM_TAIL_BYTES;
44176
+ var init_reason_detail = __esm(() => {
44177
+ init_contract();
44178
+ UPSTREAM_TAIL_BYTES = 16 * 1024;
44179
+ });
44180
+
44101
44181
  // src/pane/slot-row.ts
44102
- function toSlotRow(id, snap, acct, now = Date.now()) {
44182
+ function toSlotRow(id, snap, acct, now = Date.now(), upstreamRecords = []) {
44103
44183
  const terminal = isTerminalState(snap.state);
44104
44184
  let idle = null;
44105
44185
  if (!terminal && snap.lastActivityAt) {
@@ -44113,6 +44193,7 @@ function toSlotRow(id, snap, acct, now = Date.now()) {
44113
44193
  provider: acct.provider,
44114
44194
  state: snap.state,
44115
44195
  reason: snap.state === "COMPLETED" || !terminal ? null : snap.reason,
44196
+ reason_detail: reasonDetail({ state: snap.state, reason: snap.reason, detail: snap.detail }, upstreamRecords),
44116
44197
  tokens_in: acct.tokensIn,
44117
44198
  tokens_out: acct.tokensOut,
44118
44199
  cost_usd: acct.costUsd,
@@ -44126,6 +44207,7 @@ function toSlotRow(id, snap, acct, now = Date.now()) {
44126
44207
  }
44127
44208
  var init_slot_row = __esm(() => {
44128
44209
  init_contract();
44210
+ init_reason_detail();
44129
44211
  });
44130
44212
 
44131
44213
  // src/pane/prompt-delivery.ts
@@ -51963,7 +52045,7 @@ function truncateKeepingLink(text, max = 400) {
51963
52045
  const prose = (lastSpace > room * 0.5 ? head.slice(0, lastSpace) : head).trimEnd();
51964
52046
  return `${prose}... ${url}`;
51965
52047
  }
51966
- function oneLine4(text) {
52048
+ function oneLine5(text) {
51967
52049
  return text.replace(/\s+/g, " ").trim();
51968
52050
  }
51969
52051
  function messageFromJson(text) {
@@ -51986,9 +52068,9 @@ function extractErrorMessage(body) {
51986
52068
  return;
51987
52069
  const direct = messageFromJson(body);
51988
52070
  if (direct)
51989
- return truncateKeepingLink(oneLine4(unwrapFrame(direct)));
52071
+ return truncateKeepingLink(oneLine5(unwrapFrame(direct)));
51990
52072
  const unwrapped = unwrapFrame(body);
51991
- const trimmed = oneLine4(unwrapped);
52073
+ const trimmed = oneLine5(unwrapped);
51992
52074
  if (!trimmed)
51993
52075
  return;
51994
52076
  return truncateKeepingLink(trimmed);
@@ -57035,7 +57117,7 @@ If you cannot use structured tool_calls, format as JSON:
57035
57117
  });
57036
57118
 
57037
57119
  // src/handlers/native-handler-advisor.ts
57038
- import { appendFileSync as appendFileSync6 } from "fs";
57120
+ import { appendFileSync as appendFileSync5 } from "fs";
57039
57121
  function loadAdvisorSwapConfig(cliModels, cliCollector) {
57040
57122
  return {
57041
57123
  enabled: process.env.CLAUDISH_SWAP_ADVISOR === "1" || (cliModels?.length ?? 0) > 0,
@@ -57130,7 +57212,7 @@ function appendLine(path, line) {
57130
57212
  if (!path)
57131
57213
  return;
57132
57214
  try {
57133
- appendFileSync6(path, `${line}
57215
+ appendFileSync5(path, `${line}
57134
57216
  `);
57135
57217
  } catch {}
57136
57218
  }
@@ -59501,7 +59583,7 @@ var init_pricing_cache = __esm(() => {
59501
59583
  });
59502
59584
 
59503
59585
  // src/proxy-server.ts
59504
- import { appendFileSync as appendFileSync7, mkdirSync as mkdirSync15 } from "fs";
59586
+ import { appendFileSync as appendFileSync6, mkdirSync as mkdirSync15 } from "fs";
59505
59587
  import { join as join35 } from "path";
59506
59588
  function isTerminalRoutingFailure(e) {
59507
59589
  return e instanceof RoutingError;
@@ -59535,7 +59617,7 @@ function maybeCaptureClassifierRequest(c, body) {
59535
59617
  "x-api-key": c.req.header("x-api-key") ? "<present>" : null
59536
59618
  }
59537
59619
  };
59538
- appendFileSync7(join35(dir, "classifier-capture.jsonl"), `${JSON.stringify(record)}
59620
+ appendFileSync6(join35(dir, "classifier-capture.jsonl"), `${JSON.stringify(record)}
59539
59621
  `);
59540
59622
  } catch {}
59541
59623
  }
@@ -61565,7 +61647,7 @@ ${h("ENVIRONMENT VARIABLES")}
61565
61647
  ${blue("CLAUDISH_DIAG_MODE")} Diagnostic output: auto / logfile / off
61566
61648
  ${blue("CLAUDISH_DEBUG")} Always enable debug logging: 1 / true ${dim("(same as -d)")}
61567
61649
  ${blue("CLAUDISH_ANTHROPIC_API_BILLING")} Bill native Claude to your API key ${dim("(see --anthropic-api-billing)")}
61568
- ${blue("CLAUDISH_MCP_TOOLS")} MCP tool gating: all / low-level / agentic / channel
61650
+ ${blue("CLAUDISH_MCP_TOOLS")} MCP tool gating: all / low-level / agentic / session / debug
61569
61651
  ${blue("CLAUDISH_MODEL_OPUS")} Override model for Opus role
61570
61652
  ${blue("CLAUDISH_MODEL_SONNET")} Override model for Sonnet role
61571
61653
  ${blue("CLAUDISH_MODEL_HAIKU")} Override model for Haiku role
@@ -61875,11 +61957,11 @@ var init_magmux_binary = () => {};
61875
61957
  // src/launcher/magmux-wrapper.ts
61876
61958
  import {
61877
61959
  chmodSync,
61878
- closeSync as closeSync6,
61960
+ closeSync as closeSync7,
61879
61961
  existsSync as existsSync27,
61880
61962
  mkdirSync as mkdirSync17,
61881
61963
  mkdtempSync,
61882
- openSync as openSync6,
61964
+ openSync as openSync7,
61883
61965
  rmSync as rmSync2,
61884
61966
  writeFileSync as writeFileSync16
61885
61967
  } from "fs";
@@ -61955,11 +62037,11 @@ function planMagmuxWrap(input) {
61955
62037
  const scriptPath = join38(scriptDir, "claude-launch.sh");
61956
62038
  const parentEnv = input.parentEnv ?? process.env;
61957
62039
  const deltas = envDeltas(parentEnv, input.childEnv);
61958
- const fd = openSync6(scriptPath, "wx", 384);
62040
+ const fd = openSync7(scriptPath, "wx", 384);
61959
62041
  try {
61960
62042
  writeFileSync16(fd, buildLauncherScript(input.claudeBinary, input.claudeArgs, deltas));
61961
62043
  } finally {
61962
- closeSync6(fd);
62044
+ closeSync7(fd);
61963
62045
  }
61964
62046
  const env = { ...input.childEnv };
61965
62047
  for (const k of STRIPPED_CHILD_VARS)
@@ -62427,13 +62509,13 @@ function sockPathFor(root, id) {
62427
62509
  throw new PaneRootError(`pane socket path ${p} is ${Buffer.byteLength(p)} bytes; it must be < 100`);
62428
62510
  return p;
62429
62511
  }
62430
- function strippedFromPane(key) {
62512
+ function isStrippedFromChildEnv(key) {
62431
62513
  return STRIPPED_CHILD_VARS.includes(key) || key.startsWith("MAGMUX_") || TERMINAL_IDENTITY_VARS.includes(key) || TERMINAL_IDENTITY_PREFIXES.some((p) => key.startsWith(p)) || HOST_IDENTITY_VARS.includes(key);
62432
62514
  }
62433
62515
  function buildPaneEnv(input) {
62434
62516
  const env = {};
62435
62517
  for (const [k, v] of Object.entries(input.parentEnv)) {
62436
- if (v === undefined || strippedFromPane(k))
62518
+ if (v === undefined || isStrippedFromChildEnv(k))
62437
62519
  continue;
62438
62520
  env[k] = v;
62439
62521
  }
@@ -63364,7 +63446,7 @@ var init_pane_registry = __esm(() => {
63364
63446
  sweptRoots = new Set;
63365
63447
  });
63366
63448
 
63367
- // src/channel/parent-session.ts
63449
+ // src/mcp-session/parent-session.ts
63368
63450
  import { readFile as readFile4 } from "fs/promises";
63369
63451
  import { join as join42 } from "path";
63370
63452
  function positiveInt(value) {
@@ -64013,11 +64095,11 @@ var init_slot_state = __esm(() => {
64013
64095
 
64014
64096
  // src/pane/transcript-follower.ts
64015
64097
  import {
64016
- closeSync as closeSync7,
64098
+ closeSync as closeSync8,
64017
64099
  existsSync as existsSync29,
64018
- fstatSync,
64019
- openSync as openSync7,
64020
- readSync as readSync2,
64100
+ fstatSync as fstatSync2,
64101
+ openSync as openSync8,
64102
+ readSync as readSync3,
64021
64103
  readdirSync as readdirSync7,
64022
64104
  realpathSync as realpathSync2,
64023
64105
  statSync as statSync8
@@ -64452,16 +64534,16 @@ class Tail {
64452
64534
  read() {
64453
64535
  let fd;
64454
64536
  try {
64455
- fd = openSync7(this.path, "r");
64537
+ fd = openSync8(this.path, "r");
64456
64538
  } catch {
64457
64539
  return [];
64458
64540
  }
64459
64541
  try {
64460
- const size = fstatSync(fd).size;
64542
+ const size = fstatSync2(fd).size;
64461
64543
  if (size <= this.offset)
64462
64544
  return [];
64463
64545
  const chunk = Buffer.alloc(size - this.offset);
64464
- const got = readSync2(fd, chunk, 0, chunk.length, this.offset);
64546
+ const got = readSync3(fd, chunk, 0, chunk.length, this.offset);
64465
64547
  this.offset += got;
64466
64548
  const fresh = chunk.subarray(0, got);
64467
64549
  const buf = this.rest.length ? Buffer.concat([this.rest, fresh]) : fresh;
@@ -64478,7 +64560,7 @@ class Tail {
64478
64560
  this.rest = Buffer.from(buf.subarray(start));
64479
64561
  return out;
64480
64562
  } finally {
64481
- closeSync7(fd);
64563
+ closeSync8(fd);
64482
64564
  }
64483
64565
  }
64484
64566
  }
@@ -65204,9 +65286,12 @@ class PaneSessionImpl {
65204
65286
  this.deliver(this.admission);
65205
65287
  }
65206
65288
  async deliver(adm) {
65207
- const plan = adm.plan;
65289
+ if (await this.typeAndSubmit(adm.plan))
65290
+ adm.deliveredAt = Date.now();
65291
+ }
65292
+ async typeAndSubmit(plan) {
65208
65293
  if (plan.mode !== "typed" && plan.mode !== "file" && plan.mode !== "command")
65209
- return;
65294
+ return false;
65210
65295
  if (plan.mode === "command") {
65211
65296
  await this.typeLine(plan.line, false);
65212
65297
  await this.nextFrame(500);
@@ -65218,7 +65303,7 @@ class PaneSessionImpl {
65218
65303
  } else {
65219
65304
  await this.typeLine(plan.line, true);
65220
65305
  }
65221
- adm.deliveredAt = Date.now();
65306
+ return true;
65222
65307
  }
65223
65308
  async typeLine(text, enter) {
65224
65309
  let why = "disconnected";
@@ -65322,16 +65407,44 @@ class PaneSessionImpl {
65322
65407
  this.fire("admit_abandoned");
65323
65408
  return true;
65324
65409
  }
65410
+ async awaitClearedBox(adm, head) {
65411
+ const end = Date.now() + this.t("nudgeClearDeadlineMs", NUDGE_CLEAR_DEADLINE_MS);
65412
+ for (;; ) {
65413
+ if (this.admission !== adm || this.phase !== "ADMITTING")
65414
+ return "gone";
65415
+ const box = inputBox(this.screen);
65416
+ if (box && box.text === "")
65417
+ return "empty";
65418
+ if (box && !box.text.startsWith(head))
65419
+ return "other";
65420
+ const left = end - Date.now();
65421
+ if (left <= 0)
65422
+ return box ? "line" : "other";
65423
+ await this.nextFrame(left);
65424
+ }
65425
+ }
65325
65426
  nudge(adm) {
65326
65427
  const box = inputBox(this.screen);
65327
65428
  const line = adm.plan.mode === "control" || adm.plan.mode === "refused" ? "" : adm.plan.line;
65328
- if (!adm.resent && box && line && box.text.startsWith(line.slice(0, 40))) {
65429
+ const head = line.slice(0, 40);
65430
+ if (!adm.resent && box && line && box.text.startsWith(head)) {
65329
65431
  adm.resent = true;
65330
65432
  this.anomaly("resent_enter");
65331
65433
  (async () => {
65332
65434
  if (box.menuOpen)
65333
65435
  await this.key("escape");
65334
- await this.key("enter");
65436
+ await this.key("ctrl-u");
65437
+ const after = await this.awaitClearedBox(adm, head);
65438
+ if (after === "gone")
65439
+ return;
65440
+ if (after === "empty") {
65441
+ this.anomaly("retyped_prompt");
65442
+ await this.typeAndSubmit(adm.plan);
65443
+ } else if (after === "line") {
65444
+ await this.key("enter");
65445
+ } else {
65446
+ this.anomaly("clear_failed");
65447
+ }
65335
65448
  })();
65336
65449
  return;
65337
65450
  }
@@ -66045,7 +66158,7 @@ async function startPaneSession(o) {
66045
66158
  await session.start({ magmuxBinary: magmux.binary, env: p.magmuxEnv, cwd: p.cwd });
66046
66159
  return session;
66047
66160
  }
66048
- var BOOT_TIMEOUT_MS = 90000, ADMIT_TIMEOUT_MS = 30000, RESEND_AFTER_MS = 1e4, DEGRADED_ENTRY_MS = 1e4, SCREEN_SETTLE_QUIET_MS = 3000, PANEL_SETTLE_MS = 500, REPL_STABLE_MS = 500, BOOT_STATIC_MS = 5000, TICK_MS = 250, WATCH_FPS = 4, POLL_BACKSTOP_MS = 1000, TURN_END_MISSING_FACTOR = 3, REGISTRY_READ_MS = 250, REGISTRY_DISAGREE_MS = 2000, REGISTRY_MISSING_MS = 5000, MAX_ANOMALY_KEYS = 64, KEPT_ANSWERS = 4, EVENT_REASON, VERDICT_EVENT, PaneStartError;
66161
+ var BOOT_TIMEOUT_MS = 90000, ADMIT_TIMEOUT_MS = 30000, RESEND_AFTER_MS = 1e4, DEGRADED_ENTRY_MS = 1e4, SCREEN_SETTLE_QUIET_MS = 3000, PANEL_SETTLE_MS = 500, REPL_STABLE_MS = 3000, NUDGE_CLEAR_DEADLINE_MS = 3000, BOOT_STATIC_MS = 5000, TICK_MS = 250, WATCH_FPS = 4, POLL_BACKSTOP_MS = 1000, TURN_END_MISSING_FACTOR = 3, REGISTRY_READ_MS = 250, REGISTRY_DISAGREE_MS = 2000, REGISTRY_MISSING_MS = 5000, MAX_ANOMALY_KEYS = 64, KEPT_ANSWERS = 4, EVENT_REASON, VERDICT_EVENT, PaneStartError;
66049
66162
  var init_pane_session = __esm(() => {
66050
66163
  init_parent_session();
66051
66164
  init_process_tree();
@@ -66085,6 +66198,7 @@ var init_pane_session = __esm(() => {
66085
66198
  // src/pane/index.ts
66086
66199
  var init_pane = __esm(() => {
66087
66200
  init_slot_row();
66201
+ init_reason_detail();
66088
66202
  init_prompt_delivery();
66089
66203
  init_accounting();
66090
66204
  init_pane_launch();
@@ -66110,7 +66224,7 @@ __export(exports_session_discovery, {
66110
66224
  transcriptPathFor: () => transcriptPathFor
66111
66225
  });
66112
66226
  import { execFile as execFile3, execFileSync as execFileSync3 } from "child_process";
66113
- import { closeSync as closeSync8, openSync as openSync8, readSync as readSync3, readdirSync as readdirSync8, realpathSync as realpathSync4, statSync as statSync10 } from "fs";
66227
+ import { closeSync as closeSync9, openSync as openSync9, readSync as readSync4, readdirSync as readdirSync8, realpathSync as realpathSync4, statSync as statSync10 } from "fs";
66114
66228
  import { basename as basename2, join as join46 } from "path";
66115
66229
  function projectsDir(env = process.env) {
66116
66230
  return join46(claudeConfigDir(env), "projects");
@@ -66360,16 +66474,16 @@ function readChunk(file, pos, len) {
66360
66474
  return "";
66361
66475
  let fd = null;
66362
66476
  try {
66363
- fd = openSync8(file, "r");
66477
+ fd = openSync9(file, "r");
66364
66478
  const buf = Buffer.allocUnsafe(len);
66365
- const n = readSync3(fd, buf, 0, len, pos);
66479
+ const n = readSync4(fd, buf, 0, len, pos);
66366
66480
  return buf.subarray(0, n).toString("utf-8");
66367
66481
  } catch {
66368
66482
  return "";
66369
66483
  } finally {
66370
66484
  if (fd !== null) {
66371
66485
  try {
66372
- closeSync8(fd);
66486
+ closeSync9(fd);
66373
66487
  } catch {}
66374
66488
  }
66375
66489
  }
@@ -66625,6 +66739,9 @@ function refreshAccounting(e, snap) {
66625
66739
  function notableAnomalies(snap) {
66626
66740
  return snap.anomalies.filter((a) => a.startsWith("background_shell_open") || a.startsWith("turn_end_record_missing") || a.startsWith("prompt_not_read"));
66627
66741
  }
66742
+ function upstreamLogPath(path, id) {
66743
+ return join47(path, "errors", `${id}-upstream.jsonl`);
66744
+ }
66628
66745
  function neverSpawnedRow(e, m) {
66629
66746
  return {
66630
66747
  slot: e.id,
@@ -66632,6 +66749,11 @@ function neverSpawnedRow(e, m) {
66632
66749
  provider: e.acct.provider,
66633
66750
  state: m?.state ?? "FAILED",
66634
66751
  reason: m?.error?.reason ?? "pane_lost",
66752
+ reason_detail: reasonDetail({
66753
+ state: m?.state ?? "FAILED",
66754
+ reason: m?.error?.reason ?? "pane_lost",
66755
+ detail: m?.error?.detail
66756
+ }),
66635
66757
  tokens_in: null,
66636
66758
  tokens_out: null,
66637
66759
  cost_usd: null,
@@ -66647,7 +66769,7 @@ function liveSlotRow(run, e) {
66647
66769
  if (!e.session)
66648
66770
  return neverSpawnedRow(e, run.status.models[e.id]);
66649
66771
  const snap = e.session.snapshot();
66650
- return toSlotRow({ slot: e.id, model: e.model, spawnModel: e.spawnModel }, snap, refreshAccounting(e, snap));
66772
+ return toSlotRow({ slot: e.id, model: e.model, spawnModel: e.spawnModel }, snap, refreshAccounting(e, snap), Date.now(), upstreamRecordsFor(snap, upstreamLogPath(run.path, e.id)));
66651
66773
  }
66652
66774
  function outcomeOf(states) {
66653
66775
  const ok = states.filter((s) => s === "COMPLETED").length;
@@ -66686,12 +66808,15 @@ function teamRunRowFromDisk(path, status) {
66686
66808
  const slots = Object.entries(status.models ?? {}).sort(([a], [b]) => a.localeCompare(b)).map(([id, m]) => {
66687
66809
  const { state, known } = closedState(m?.state);
66688
66810
  const terminal = isTerminalState(state);
66811
+ const reason = !known || !terminal || state === "COMPLETED" ? null : m?.error?.reason ?? null;
66812
+ const why = { state, reason, detail: m?.error?.detail };
66689
66813
  return {
66690
66814
  slot: id,
66691
66815
  model: m?.model ?? manifest?.models[id]?.model ?? "unknown",
66692
66816
  provider: m?.provider ?? null,
66693
66817
  state,
66694
- reason: !known || !terminal || state === "COMPLETED" ? null : m?.error?.reason ?? null,
66818
+ reason,
66819
+ reason_detail: reasonDetail(why, upstreamRecordsFor(why, upstreamLogPath(path, id))),
66695
66820
  tokens_in: m?.tokensIn ?? null,
66696
66821
  tokens_out: m?.tokensOut ?? null,
66697
66822
  cost_usd: m?.costUsd ?? null,
@@ -67085,7 +67210,7 @@ async function startModelsIn(flight, sessionPath, opts) {
67085
67210
  const entries = new Map;
67086
67211
  let run = null;
67087
67212
  const errorLogPathOf = (id) => join47(path, "errors", `${id}.log`);
67088
- const upstreamLogOf = (id) => join47(path, "errors", `${id}-upstream.jsonl`);
67213
+ const upstreamLogOf = (id) => upstreamLogPath(path, id);
67089
67214
  const commandOf = (e) => ["claudish", "-i", "--model", e.spawnModel ?? e.model, "-y", "--quiet", ...claudeFlags].join(" ");
67090
67215
  function writeResponse(e, text) {
67091
67216
  e.answer = text;
@@ -67647,17 +67772,17 @@ var init_team_orchestrator = __esm(() => {
67647
67772
  CANCELLED_DETAIL = `Stopped on the caller's instruction via team(mode:"cancel"). ` + "Whatever the child had written up to that point is in its response file.";
67648
67773
  });
67649
67774
 
67650
- // src/channel/session-manager.ts
67775
+ // src/mcp-session/session-manager.ts
67651
67776
  import { randomUUID as randomUUID6 } from "crypto";
67652
67777
  import {
67653
- appendFileSync as appendFileSync8,
67654
- closeSync as closeSync9,
67778
+ appendFileSync as appendFileSync7,
67779
+ closeSync as closeSync10,
67655
67780
  createWriteStream,
67656
67781
  existsSync as existsSync31,
67657
67782
  mkdirSync as mkdirSync20,
67658
- openSync as openSync9,
67783
+ openSync as openSync10,
67659
67784
  readFileSync as readFileSync30,
67660
- readSync as readSync4,
67785
+ readSync as readSync5,
67661
67786
  renameSync as renameSync4,
67662
67787
  statSync as statSync12,
67663
67788
  writeFileSync as writeFileSync21
@@ -67669,7 +67794,7 @@ function normaliseTimeoutSeconds(raw) {
67669
67794
  return DEFAULT_TIMEOUT;
67670
67795
  return Math.min(MAX_TIMEOUT, Math.max(1, Math.round(n)));
67671
67796
  }
67672
- function channelEventFor(snap) {
67797
+ function sessionEventFor(snap) {
67673
67798
  switch (snap.state) {
67674
67799
  case "STARTING":
67675
67800
  return { event: "starting", tool: null };
@@ -67691,7 +67816,7 @@ function channelEventFor(snap) {
67691
67816
  return { event: "failed", tool: null };
67692
67817
  }
67693
67818
  }
67694
- function sessionRowOf(info) {
67819
+ function sessionRowOf(info, upstreamRecords = []) {
67695
67820
  const terminal = isTerminalState(info.state);
67696
67821
  return {
67697
67822
  slot: info.sessionId,
@@ -67699,6 +67824,7 @@ function sessionRowOf(info) {
67699
67824
  provider: info.provider,
67700
67825
  state: info.state,
67701
67826
  reason: info.state === "COMPLETED" || !terminal ? null : info.reason,
67827
+ reason_detail: reasonDetail(info, upstreamRecords),
67702
67828
  tokens_in: info.tokensIn,
67703
67829
  tokens_out: info.tokensOut,
67704
67830
  cost_usd: info.costUsd,
@@ -67753,15 +67879,6 @@ function writeJsonAtomic(path, value) {
67753
67879
  writeFileSync21(tmp, JSON.stringify(value, null, 2), "utf-8");
67754
67880
  renameSync4(tmp, path);
67755
67881
  }
67756
- function anomalyCount(anomalies, key) {
67757
- for (const a of anomalies) {
67758
- if (a === key)
67759
- return 1;
67760
- if (a.startsWith(`${key} \xD7`))
67761
- return Number(a.slice(key.length + 2)) || 1;
67762
- }
67763
- return 0;
67764
- }
67765
67882
  function anomalyKey(a) {
67766
67883
  const at = a.lastIndexOf(" \xD7");
67767
67884
  return at > 0 ? a.slice(0, at) : a;
@@ -67775,20 +67892,20 @@ function readTailText(path, maxBytes) {
67775
67892
  const start = Math.max(0, size - maxBytes);
67776
67893
  const length = size - start;
67777
67894
  const buf = Buffer.alloc(length);
67778
- fd = openSync9(path, "r");
67779
- readSync4(fd, buf, 0, length, start);
67895
+ fd = openSync10(path, "r");
67896
+ readSync5(fd, buf, 0, length, start);
67780
67897
  return { text: buf.toString("utf-8"), truncated: start > 0 };
67781
67898
  } catch {
67782
67899
  return null;
67783
67900
  } finally {
67784
67901
  if (fd !== null) {
67785
67902
  try {
67786
- closeSync9(fd);
67903
+ closeSync10(fd);
67787
67904
  } catch {}
67788
67905
  }
67789
67906
  }
67790
67907
  }
67791
- function readTailLines(path, maxBytes) {
67908
+ function readTailLines2(path, maxBytes) {
67792
67909
  const tail = readTailText(path, maxBytes);
67793
67910
  if (!tail)
67794
67911
  return [];
@@ -67875,7 +67992,6 @@ class SessionManager {
67875
67992
  scrollbackCapacity;
67876
67993
  sessionsDir;
67877
67994
  terminalRetentionMs;
67878
- onStateChange;
67879
67995
  parentEnv;
67880
67996
  paneTimings;
67881
67997
  starting = 0;
@@ -67892,7 +68008,6 @@ class SessionManager {
67892
68008
  this.scrollbackCapacity = options?.scrollbackCapacity ?? DEFAULT_SCROLLBACK;
67893
68009
  this.terminalRetentionMs = options?.terminalRetentionMs ?? TERMINAL_RETENTION_MS;
67894
68010
  this.sessionsDir = options?.sessionsDir ?? sessionsDirFrom(process.env);
67895
- this.onStateChange = options?.onStateChange;
67896
68011
  this.parentEnv = options?.parentEnv ?? process.env;
67897
68012
  this.paneTimings = options?.paneTimings;
67898
68013
  }
@@ -68099,16 +68214,9 @@ class SessionManager {
68099
68214
  waitSince: null,
68100
68215
  ended: false,
68101
68216
  evictHandle: null,
68102
- lastEvent: "starting",
68103
- lastFrameTool: null,
68104
- lastFrameToolCount: 0,
68105
- lastToolFrameAt: 0,
68106
68217
  lastLoggedTool: null,
68107
68218
  assistantIdsLogged: 0,
68108
- anomaliesLogged: new Set,
68109
- sendRejectedSeen: 0,
68110
- pendingMeta: {},
68111
- blockText: null
68219
+ anomaliesLogged: new Set
68112
68220
  };
68113
68221
  }
68114
68222
  async startPane(entry, opts, p) {
@@ -68157,7 +68265,6 @@ class SessionManager {
68157
68265
  info.elapsedSeconds = elapsedSecondsBetween(info.startedAt, Date.parse(at));
68158
68266
  this.appendEvent(entry, { type: "state", from: "STARTING", to: "FAILED", at });
68159
68267
  this.endRecords(entry, null);
68160
- this.emitFrame(entry, { state: "FAILED", activity: null, toolCalls: 0 });
68161
68268
  }
68162
68269
  decide(entry, turn) {
68163
68270
  this.appendAnswer(entry, turn.index, turn.answer);
@@ -68178,7 +68285,6 @@ class SessionManager {
68178
68285
  return { state: "FAILED", reason: "api_error", detail: v?.detail ?? "API error" };
68179
68286
  }
68180
68287
  if (turn.delivery.complete === false) {
68181
- entry.pendingMeta.prompt_not_read = "true";
68182
68288
  this.appendEvent(entry, {
68183
68289
  type: "anomaly",
68184
68290
  key: "prompt_not_read",
@@ -68190,8 +68296,7 @@ class SessionManager {
68190
68296
  }
68191
68297
  return "continue";
68192
68298
  }
68193
- onBlocked(entry, b) {
68194
- entry.blockText = b.text;
68299
+ onBlocked(_entry, _b) {
68195
68300
  return "wait";
68196
68301
  }
68197
68302
  onPaneTransition(entry, t) {
@@ -68202,18 +68307,14 @@ class SessionManager {
68202
68307
  this.recordWaitTransition(entry, t.from, t.to, t.at, snap);
68203
68308
  this.appendEvent(entry, { type: "state", from: t.from, to: t.to, at: t.at });
68204
68309
  this.logPaneFacts(entry, snap);
68205
- if (!isWaiting(t.to))
68206
- entry.blockText = null;
68207
68310
  if (isTerminalState(t.to))
68208
68311
  this.onTerminal(entry, snap);
68209
- this.emitFrame(entry, snap);
68210
68312
  }
68211
68313
  onPaneChange(entry, snap) {
68212
68314
  if (entry.ended)
68213
68315
  return;
68214
68316
  this.applySnapshot(entry, snap);
68215
68317
  this.logPaneFacts(entry, snap);
68216
- this.emitFrame(entry, snap);
68217
68318
  }
68218
68319
  onTerminal(entry, snap) {
68219
68320
  const session = entry.session;
@@ -68251,7 +68352,7 @@ class SessionManager {
68251
68352
  wait: "closed",
68252
68353
  since: entry.waitSince,
68253
68354
  at: entry.info.completedAt ?? new Date().toISOString(),
68254
- to: channelEventFor(entry.info).event
68355
+ to: sessionEventFor(entry.info).event
68255
68356
  });
68256
68357
  entry.waitSince = null;
68257
68358
  }
@@ -68301,7 +68402,7 @@ class SessionManager {
68301
68402
  at
68302
68403
  });
68303
68404
  }
68304
- const { tool } = channelEventFor(snap);
68405
+ const { tool } = sessionEventFor(snap);
68305
68406
  if (tool && tool !== entry.lastLoggedTool)
68306
68407
  this.appendEvent(entry, { type: "tool", name: tool, at });
68307
68408
  entry.lastLoggedTool = tool;
@@ -68312,66 +68413,6 @@ class SessionManager {
68312
68413
  entry.anomaliesLogged.add(key);
68313
68414
  this.appendEvent(entry, { type: "anomaly", key, at });
68314
68415
  }
68315
- const rejected = anomalyCount(snap.anomalies, "send_not_accepted");
68316
- if (rejected > entry.sendRejectedSeen) {
68317
- entry.sendRejectedSeen = rejected;
68318
- entry.pendingMeta.send_rejected = "true";
68319
- }
68320
- }
68321
- emitFrame(entry, snap) {
68322
- const { event, tool } = channelEventFor(snap);
68323
- const now = Date.now();
68324
- const changed = event !== entry.lastEvent;
68325
- const toolRepeat = !changed && event === "tool_executing" && (tool !== entry.lastFrameTool || snap.toolCalls !== entry.lastFrameToolCount) && now - entry.lastToolFrameAt >= 1000;
68326
- if (!changed && !toolRepeat)
68327
- return;
68328
- entry.lastEvent = event;
68329
- if (event === "tool_executing") {
68330
- entry.lastFrameTool = tool;
68331
- entry.lastFrameToolCount = snap.toolCalls;
68332
- entry.lastToolFrameAt = now;
68333
- }
68334
- const extraMeta = {
68335
- ...tool ? { tool, tool_count: String(snap.toolCalls) } : {},
68336
- ...snap.activity ? { activity: snap.activity } : {},
68337
- ...entry.pendingMeta
68338
- };
68339
- entry.pendingMeta = {};
68340
- try {
68341
- this.onStateChange?.(entry.info.sessionId, {
68342
- type: event,
68343
- model: entry.info.model,
68344
- content: this.frameContent(entry, event, tool),
68345
- elapsedSeconds: entry.info.elapsedSeconds,
68346
- createdAt: entry.info.startedAt,
68347
- extraMeta
68348
- });
68349
- } catch {}
68350
- }
68351
- frameContent(entry, event, tool) {
68352
- const info = entry.info;
68353
- switch (event) {
68354
- case "running":
68355
- return "The turn is running.";
68356
- case "tool_executing":
68357
- return `Using ${tool}.`;
68358
- case "waiting_for_input":
68359
- return entry.blockText ? `The model asked a question; send_input declines it and becomes the next prompt.
68360
- ${entry.blockText}` : "The turn finished; waiting for send_input.";
68361
- case "awaiting_permission":
68362
- return `A permission dialog is open for ${info.activity ?? "a tool"}; send_input declines it and becomes the next prompt.${entry.blockText ? `
68363
- ${entry.blockText}` : ""}`;
68364
- case "completed":
68365
- return `Session completed (${info.turnsCompleted} turn(s)). Call get_output for the answer.`;
68366
- case "cancelled":
68367
- return "Session cancelled.";
68368
- case "timeout":
68369
- return `Timeout after ${info.timeoutSeconds}s; the pane was closed.`;
68370
- case "failed":
68371
- return `${info.state} ${info.reason ?? ""}${info.detail ? `: ${info.detail}` : ""}`.trim();
68372
- default:
68373
- return "";
68374
- }
68375
68416
  }
68376
68417
  sendInput(sessionId, text) {
68377
68418
  const entry = this.liveEntry(sessionId);
@@ -68415,7 +68456,7 @@ ${entry.blockText}` : ""}`;
68415
68456
  return {
68416
68457
  sessionId,
68417
68458
  state: info.state,
68418
- event: channelEventFor(info).event,
68459
+ event: sessionEventFor(info).event,
68419
68460
  reason: isTerminalState(info.state) && info.state !== "COMPLETED" ? info.reason : null,
68420
68461
  detail: info.detail,
68421
68462
  model: info.model,
@@ -68439,7 +68480,7 @@ ${entry.blockText}` : ""}`;
68439
68480
  ...this.paneFacts(entry),
68440
68481
  recentEvents: limit === 0 ? [] : entry.eventRing.slice(-limit),
68441
68482
  eventsTotal: entry.eventRing.length,
68442
- upstreamErrors: readTailLines(entry.upstreamErrorLogPath, UPSTREAM_ERROR_TAIL_BYTES),
68483
+ upstreamErrors: readTailLines2(entry.upstreamErrorLogPath, UPSTREAM_ERROR_TAIL_BYTES),
68443
68484
  claudeSessionId: info.claudeSessionId,
68444
68485
  transcriptPath: info.transcriptPath,
68445
68486
  sessionDir: entry.sessionDir,
@@ -68505,7 +68546,15 @@ ${entry.blockText}` : ""}`;
68505
68546
  return sessions;
68506
68547
  }
68507
68548
  listSessionRows(includeCompleted = false) {
68508
- return this.listSessions(includeCompleted).map(sessionRowOf);
68549
+ const rows = [];
68550
+ for (const entry of this.sessions.values()) {
68551
+ this.refresh(entry);
68552
+ if (!includeCompleted && isTerminalState(entry.info.state))
68553
+ continue;
68554
+ const info = { ...entry.info };
68555
+ rows.push(sessionRowOf(info, upstreamRecordsFor(info, entry.upstreamErrorLogPath)));
68556
+ }
68557
+ return rows;
68509
68558
  }
68510
68559
  getSession(sessionId) {
68511
68560
  const entry = this.sessions.get(sessionId);
@@ -68610,13 +68659,13 @@ ${entry.blockText}` : ""}`;
68610
68659
  const eventLogPath = join48(sessionDir, "events.jsonl");
68611
68660
  const upstreamErrorLogPath = join48(sessionDir, "upstream-errors.jsonl");
68612
68661
  const outputLogPath = join48(sessionDir, "output.log");
68613
- const events = readTailLines(eventLogPath, EVENT_TAIL_BYTES);
68662
+ const events = readTailLines2(eventLogPath, EVENT_TAIL_BYTES);
68614
68663
  const outputTail = readTailText(outputLogPath, OUTPUT_TAIL_BYTES);
68615
68664
  const screen = readTailText(join48(sessionDir, "screen.txt"), SCREEN_READ_BYTES);
68616
68665
  return {
68617
68666
  sessionId: info.sessionId,
68618
68667
  state: info.state,
68619
- event: channelEventFor(info).event,
68668
+ event: sessionEventFor(info).event,
68620
68669
  reason: info.reason,
68621
68670
  detail: info.detail,
68622
68671
  model: info.model,
@@ -68666,7 +68715,7 @@ ${entry.blockText}` : ""}`;
68666
68715
  };
68667
68716
  }),
68668
68717
  eventsTotal: events.length,
68669
- upstreamErrors: readTailLines(upstreamErrorLogPath, UPSTREAM_ERROR_TAIL_BYTES),
68718
+ upstreamErrors: readTailLines2(upstreamErrorLogPath, UPSTREAM_ERROR_TAIL_BYTES),
68670
68719
  claudeSessionId: info.claudeSessionId || null,
68671
68720
  transcriptPath: info.transcriptPath || null,
68672
68721
  sessionDir,
@@ -68720,7 +68769,7 @@ ${entry.blockText}` : ""}`;
68720
68769
  entry.eventLogBytes += Buffer.byteLength(payload, "utf-8");
68721
68770
  const capped = entry.eventLogBytes >= EVENT_LOG_LIMIT;
68722
68771
  try {
68723
- appendFileSync8(entry.eventLogPath, capped ? `${payload}{"type":"claudish_truncated","limit_bytes":${EVENT_LOG_LIMIT}}
68772
+ appendFileSync7(entry.eventLogPath, capped ? `${payload}{"type":"claudish_truncated","limit_bytes":${EVENT_LOG_LIMIT}}
68724
68773
  ` : payload);
68725
68774
  } catch {}
68726
68775
  }
@@ -68737,7 +68786,7 @@ ${entry.blockText}` : ""}`;
68737
68786
  wait: "closed",
68738
68787
  since: entry.waitSince ?? at,
68739
68788
  at,
68740
- to: channelEventFor(snap).event
68789
+ to: sessionEventFor(snap).event
68741
68790
  });
68742
68791
  entry.waitSince = null;
68743
68792
  }
@@ -68749,7 +68798,7 @@ ${entry.blockText}` : ""}`;
68749
68798
  `;
68750
68799
  entry.waitLogBytes += Buffer.byteLength(payload, "utf-8");
68751
68800
  try {
68752
- appendFileSync8(entry.waitLogPath, payload);
68801
+ appendFileSync7(entry.waitLogPath, payload);
68753
68802
  } catch (err) {
68754
68803
  process.stderr.write(`[claudish] session ${entry.info.sessionId}: could not append to waits.jsonl: ` + `${err instanceof Error ? err.message : String(err)}
68755
68804
  `);
@@ -68883,11 +68932,11 @@ var init_session_manager = __esm(() => {
68883
68932
  SCREEN_READ_BYTES = 64 * 1024;
68884
68933
  });
68885
68934
 
68886
- // src/channel/types.ts
68935
+ // src/mcp-session/types.ts
68887
68936
  var init_types3 = () => {};
68888
68937
 
68889
- // src/channel/index.ts
68890
- var init_channel = __esm(() => {
68938
+ // src/mcp-session/index.ts
68939
+ var init_mcp_session = __esm(() => {
68891
68940
  init_scrollback_buffer();
68892
68941
  init_session_manager();
68893
68942
  init_types3();
@@ -68990,10 +69039,243 @@ var init_progress_heartbeat = __esm(() => {
68990
69039
  });
68991
69040
  });
68992
69041
 
69042
+ // src/mcp/run-prompt-claude-code.ts
69043
+ import { spawn as spawn2 } from "child_process";
69044
+ import { mkdirSync as mkdirSync21, mkdtempSync as mkdtempSync3, rmSync as rmSync5, writeFileSync as writeFileSync22 } from "fs";
69045
+ import { tmpdir as tmpdir2 } from "os";
69046
+ import { join as join49 } from "path";
69047
+ function claudeCodePrintArgv(model, systemPromptFile) {
69048
+ const head = [PRINT_FLAGS[0], "--model", model, ...PRINT_FLAGS.slice(1)];
69049
+ return systemPromptFile !== undefined ? [...head, "--system-prompt-file", systemPromptFile] : [...head, "--system-prompt", ""];
69050
+ }
69051
+ function claudeCodePrintEnv(parent) {
69052
+ const env = {};
69053
+ for (const [k, v] of Object.entries(parent)) {
69054
+ if (v === undefined || isStrippedFromChildEnv(k))
69055
+ continue;
69056
+ if (PRINT_CHILD_DROPPED_MARKERS.includes(k))
69057
+ continue;
69058
+ env[k] = v;
69059
+ }
69060
+ delete env.ANTHROPIC_API_KEY;
69061
+ delete env.ANTHROPIC_AUTH_TOKEN;
69062
+ delete env.ANTHROPIC_BASE_URL;
69063
+ return env;
69064
+ }
69065
+ function isFrame(v) {
69066
+ return typeof v === "object" && v !== null && !Array.isArray(v);
69067
+ }
69068
+ function parseJsonDocument(stdout) {
69069
+ const text = stdout.trim();
69070
+ if (!text)
69071
+ return;
69072
+ try {
69073
+ return JSON.parse(text);
69074
+ } catch {
69075
+ const lines = text.split(`
69076
+ `);
69077
+ for (let i = lines.length - 1;i >= 0; i--) {
69078
+ const line = lines[i].trim();
69079
+ if (!line.startsWith("[") && !line.startsWith("{"))
69080
+ continue;
69081
+ try {
69082
+ return JSON.parse(line);
69083
+ } catch {}
69084
+ }
69085
+ return;
69086
+ }
69087
+ }
69088
+ function num(v) {
69089
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
69090
+ }
69091
+ function parseClaudeCodePrintOutput(stdout) {
69092
+ const doc = parseJsonDocument(stdout);
69093
+ const frames = Array.isArray(doc) ? doc.filter(isFrame) : isFrame(doc) ? [doc] : [];
69094
+ let result;
69095
+ let init;
69096
+ for (const f of frames) {
69097
+ if (f.type === "result")
69098
+ result = f;
69099
+ else if (f.type === "system" && f.subtype === "init" && init === undefined)
69100
+ init = f;
69101
+ }
69102
+ if (!result)
69103
+ return null;
69104
+ const parsed = {
69105
+ result: typeof result.result === "string" ? result.result : "",
69106
+ isError: result.is_error === true,
69107
+ apiErrorStatus: typeof result.api_error_status === "number" ? result.api_error_status : null
69108
+ };
69109
+ if (typeof result.terminal_reason === "string")
69110
+ parsed.terminalReason = result.terminal_reason;
69111
+ if (isFrame(result.usage)) {
69112
+ const u = result.usage;
69113
+ parsed.usage = {
69114
+ input: num(u.input_tokens) + num(u.cache_creation_input_tokens) + num(u.cache_read_input_tokens),
69115
+ output: num(u.output_tokens)
69116
+ };
69117
+ }
69118
+ if (init && typeof init.apiKeySource === "string")
69119
+ parsed.apiKeySource = init.apiKeySource;
69120
+ return parsed;
69121
+ }
69122
+ function authFrom(apiKeySource) {
69123
+ if (apiKeySource === undefined)
69124
+ return;
69125
+ return apiKeySource === "none" ? "subscription" : apiKeySource;
69126
+ }
69127
+ function killGroup(proc) {
69128
+ const send = (sig) => {
69129
+ if (proc.exitCode !== null || proc.signalCode !== null)
69130
+ return;
69131
+ try {
69132
+ if (proc.pid !== undefined)
69133
+ process.kill(-proc.pid, sig);
69134
+ else
69135
+ proc.kill(sig);
69136
+ } catch {
69137
+ try {
69138
+ proc.kill(sig);
69139
+ } catch {}
69140
+ }
69141
+ };
69142
+ send("SIGTERM");
69143
+ const timer = setTimeout(() => send("SIGKILL"), KILL_GRACE_MS);
69144
+ timer.unref?.();
69145
+ }
69146
+ function stopAllClaudeCodePrintChildren() {
69147
+ for (const proc of inFlight2)
69148
+ killGroup(proc);
69149
+ }
69150
+ function stderrTail(stderr) {
69151
+ return sanitizeForReport(stderr.slice(-STDERR_TAIL_CHARS).trim());
69152
+ }
69153
+ async function runPromptViaClaudeCode(model, prompt, systemPrompt, opts = {}) {
69154
+ const signal = opts.signal;
69155
+ if (signal?.aborted)
69156
+ throw new Error("cancelled");
69157
+ const parentEnv = opts.parentEnv ?? process.env;
69158
+ let launch;
69159
+ try {
69160
+ launch = resolveClaudishLaunch(parentEnv);
69161
+ } catch (e) {
69162
+ throw new Error(`cannot start claudish (${parentEnv.CLAUDISH_BIN?.trim() || "claudish"}): ${e instanceof Error ? e.message : String(e)}`);
69163
+ }
69164
+ const root = mkdtempSync3(join49(tmpdir2(), "claudish-run-prompt-"));
69165
+ try {
69166
+ const cwd = join49(root, "cwd");
69167
+ mkdirSync21(cwd, { mode: 448 });
69168
+ let systemPromptFile;
69169
+ if (typeof systemPrompt === "string" && systemPrompt.length > 0) {
69170
+ systemPromptFile = join49(root, "system-prompt.txt");
69171
+ writeFileSync22(systemPromptFile, systemPrompt, { mode: 384 });
69172
+ }
69173
+ const argv = claudeCodePrintArgv(model, systemPromptFile);
69174
+ const outcome = await runChild(launch, argv, cwd, claudeCodePrintEnv(parentEnv), prompt, signal);
69175
+ if (signal?.aborted)
69176
+ throw new Error("cancelled");
69177
+ const parsed = parseClaudeCodePrintOutput(outcome.stdout);
69178
+ if (parsed === null) {
69179
+ const how = outcome.code !== null ? `exited ${outcome.code}` : `exited ${outcome.signal ?? "?"}`;
69180
+ const tail = stderrTail(outcome.stderr);
69181
+ const noFrame = outcome.code === 0 ? " with no result frame in its output" : "";
69182
+ throw new Error(`claudish -p ${how}${noFrame}${tail ? `: ${tail}` : ""}`);
69183
+ }
69184
+ if (parsed.isError) {
69185
+ const status = parsed.apiErrorStatus !== null ? ` (HTTP ${parsed.apiErrorStatus})` : "";
69186
+ throw new Error(`Claude Code: ${parsed.result || parsed.terminalReason || "error"}${status}`);
69187
+ }
69188
+ if (parsed.result === "")
69189
+ throw new Error("Model returned empty response");
69190
+ const answer = { content: parsed.result };
69191
+ if (parsed.usage)
69192
+ answer.usage = parsed.usage;
69193
+ const auth = authFrom(parsed.apiKeySource);
69194
+ if (auth !== undefined)
69195
+ answer.auth = auth;
69196
+ return answer;
69197
+ } finally {
69198
+ rmSync5(root, { recursive: true, force: true });
69199
+ }
69200
+ }
69201
+ function runChild(launch, argv, cwd, env, prompt, signal) {
69202
+ return new Promise((resolvePromise, reject) => {
69203
+ let proc;
69204
+ try {
69205
+ proc = spawn2(launch.command, [...launch.prefixArgs, ...argv], {
69206
+ cwd,
69207
+ env,
69208
+ stdio: ["pipe", "pipe", "pipe"],
69209
+ detached: true
69210
+ });
69211
+ } catch (e) {
69212
+ reject(startError(launch.command, e));
69213
+ return;
69214
+ }
69215
+ let stdout = "";
69216
+ let stderr = "";
69217
+ let settled = false;
69218
+ const onAbort = () => killGroup(proc);
69219
+ const finish = (fn) => {
69220
+ if (settled)
69221
+ return;
69222
+ settled = true;
69223
+ inFlight2.delete(proc);
69224
+ signal?.removeEventListener("abort", onAbort);
69225
+ fn();
69226
+ };
69227
+ proc.stdout?.setEncoding("utf8");
69228
+ proc.stderr?.setEncoding("utf8");
69229
+ proc.stdout?.on("data", (chunk) => {
69230
+ stdout += chunk;
69231
+ });
69232
+ proc.stderr?.on("data", (chunk) => {
69233
+ stderr += chunk;
69234
+ });
69235
+ proc.stdin?.on("error", () => {});
69236
+ proc.on("error", (e) => finish(() => reject(startError(launch.command, e))));
69237
+ proc.on("close", (code, sig) => finish(() => resolvePromise({ code, signal: sig, stdout, stderr })));
69238
+ inFlight2.add(proc);
69239
+ signal?.addEventListener("abort", onAbort, { once: true });
69240
+ if (signal?.aborted)
69241
+ onAbort();
69242
+ proc.stdin?.end(prompt);
69243
+ });
69244
+ }
69245
+ function startError(command, e) {
69246
+ const code = e?.code;
69247
+ const detail = typeof code === "string" ? code : e instanceof Error ? e.message : String(e ?? "unknown");
69248
+ return new Error(`cannot start claudish (${command}): ${detail}`);
69249
+ }
69250
+ var PRINT_FLAGS, PRINT_CHILD_DROPPED_MARKERS, inFlight2, KILL_GRACE_MS = 5000, STDERR_TAIL_CHARS = 2000;
69251
+ var init_run_prompt_claude_code = __esm(() => {
69252
+ init_config();
69253
+ init_child_env();
69254
+ init_pane_launch();
69255
+ init_redact();
69256
+ PRINT_FLAGS = [
69257
+ "-p",
69258
+ "--output-format",
69259
+ "json",
69260
+ "--tools",
69261
+ "",
69262
+ "--strict-mcp-config",
69263
+ "--setting-sources",
69264
+ "",
69265
+ "--disable-slash-commands",
69266
+ "--no-session-persistence"
69267
+ ];
69268
+ PRINT_CHILD_DROPPED_MARKERS = [
69269
+ ...PANE_LAUNCH_VARS,
69270
+ ENV.CLAUDISH_PANE_CHILD
69271
+ ];
69272
+ inFlight2 = new Set;
69273
+ });
69274
+
68993
69275
  // src/mcp-server.ts
68994
- import { existsSync as existsSync32, mkdirSync as mkdirSync21, readFileSync as readFileSync31, readdirSync as readdirSync10, writeFileSync as writeFileSync22 } from "fs";
69276
+ import { existsSync as existsSync32, mkdirSync as mkdirSync22, readFileSync as readFileSync31, readdirSync as readdirSync10, writeFileSync as writeFileSync23 } from "fs";
68995
69277
  import { homedir as homedir33 } from "os";
68996
- import { dirname as dirname14, join as join49, resolve as resolve6 } from "path";
69278
+ import { dirname as dirname14, join as join50, resolve as resolve6 } from "path";
68997
69279
  import { fileURLToPath as fileURLToPath3 } from "url";
68998
69280
  async function loadAllModels(forceRefresh = false) {
68999
69281
  if (!forceRefresh && existsSync32(OPENROUTER_MODELS_CACHE_PATH)) {
@@ -69012,8 +69294,8 @@ async function loadAllModels(forceRefresh = false) {
69012
69294
  throw new Error(`API returned ${response.status}`);
69013
69295
  const data = await response.json();
69014
69296
  const models = data.data || [];
69015
- mkdirSync21(CLAUDISH_CACHE_DIR, { recursive: true });
69016
- writeFileSync22(OPENROUTER_MODELS_CACHE_PATH, JSON.stringify({ lastUpdated: new Date().toISOString(), models }), "utf-8");
69297
+ mkdirSync22(CLAUDISH_CACHE_DIR, { recursive: true });
69298
+ writeFileSync23(OPENROUTER_MODELS_CACHE_PATH, JSON.stringify({ lastUpdated: new Date().toISOString(), models }), "utf-8");
69017
69299
  return models;
69018
69300
  } catch {
69019
69301
  if (existsSync32(OPENROUTER_MODELS_CACHE_PATH)) {
@@ -69069,12 +69351,11 @@ function parseAnthropicSse(raw) {
69069
69351
  }
69070
69352
  return { text, usage: hasUsage ? { input: inputTokens, output: outputTokens } : undefined };
69071
69353
  }
69072
- async function runPromptViaProxy(model, prompt, systemPrompt, maxTokens) {
69354
+ async function runPromptViaProxy(model, prompt, systemPrompt) {
69073
69355
  const proxy = await getProxy();
69074
69356
  const body = {
69075
69357
  model,
69076
69358
  messages: [{ role: "user", content: prompt }],
69077
- max_tokens: maxTokens || 4096,
69078
69359
  stream: true
69079
69360
  };
69080
69361
  if (systemPrompt) {
@@ -69096,6 +69377,26 @@ async function runPromptViaProxy(model, prompt, systemPrompt, maxTokens) {
69096
69377
  }
69097
69378
  return { content: parsed.text, usage: parsed.usage };
69098
69379
  }
69380
+ async function runPrompt(model, prompt, systemPrompt, signal) {
69381
+ if (nativeRouteFor(model) !== null) {
69382
+ return runPromptViaClaudeCode(model, prompt, systemPrompt, { signal });
69383
+ }
69384
+ return runPromptViaProxy(model, prompt, systemPrompt);
69385
+ }
69386
+ function formatRunPromptResult(result) {
69387
+ const footer = [];
69388
+ if (result.usage) {
69389
+ footer.push(`Tokens: ${result.usage.input} input, ${result.usage.output} output`);
69390
+ }
69391
+ if (result.auth !== undefined) {
69392
+ footer.push(result.auth === "subscription" ? "Auth: Claude Code login (subscription)" : `Auth: ${result.auth}`);
69393
+ }
69394
+ return footer.length > 0 ? `${result.content}
69395
+
69396
+ ---
69397
+ ${footer.join(`
69398
+ `)}` : result.content;
69399
+ }
69099
69400
  function fuzzyScore(text, query) {
69100
69401
  const lowerText = text.toLowerCase();
69101
69402
  const lowerQuery = query.toLowerCase();
@@ -69310,7 +69611,7 @@ async function teamContractVerb(mode, args) {
69310
69611
  return contractErrorAnswer(e);
69311
69612
  }
69312
69613
  }
69313
- function defineTools(sessionManager, notifyChannel, nested) {
69614
+ function defineTools(sessionManager, nested) {
69314
69615
  const tools = [];
69315
69616
  const reportHint = (text) => nested ? "" : text;
69316
69617
  function withOpFailureContext(message, subject) {
@@ -69322,33 +69623,25 @@ ${block.join(`
69322
69623
  }
69323
69624
  tools.push({
69324
69625
  name: "run_prompt",
69325
- description: "Run a prompt through any model \u2014 supports all providers (Kimi, GLM, Qwen, MiniMax, Gemini, GPT, Grok, etc.) with auto-routing, fallback chains, and custom routing rules.",
69626
+ description: "One quick prompt, straight to one model's API: a single request and its answer. No " + "Claude Code session, no tools, no files, no conversation state \u2014 this is not subagent " + "work. For a task that needs tools, files or more than one turn, use create_session " + "(one model) or team (several models). Non-Claude models (Kimi, GLM, Qwen, MiniMax, " + "Gemini, GPT, Grok, \u2026) go through claudish's routing straight to the provider's API. " + "A Claude model name (claude-*, opus, sonnet, haiku) runs as one Claude Code " + "print-mode call on the user's own Claude Code login, with tools, MCP servers and " + "settings off.",
69326
69627
  inputSchema: {
69327
69628
  type: "object",
69328
69629
  properties: {
69329
69630
  model: {
69330
69631
  type: "string",
69331
- description: "Model name or ID. Short names auto-route to the best provider (e.g., 'kimi-k2.5', 'glm-5', 'gpt-5.4'). Provider prefix optional (e.g., 'google@gemini-3.1-pro-preview', 'or@x-ai/grok-3')."
69632
+ description: "Model name or model spec. A bare name auto-routes to the best provider; " + "'provider@model' pins the provider (e.g. 'google@gemini-4-argon', " + "'or@x-ai/grok-4.7'). A bare Claude name (claude-*, opus, sonnet, haiku) runs on " + "Claude Code's own login."
69332
69633
  },
69333
69634
  prompt: { type: "string", description: "The prompt to send to the model" },
69334
- system_prompt: { type: "string", description: "Optional system prompt" },
69335
- max_tokens: { type: "number", description: "Maximum tokens in response (default: 4096)" }
69635
+ system_prompt: { type: "string", description: "Optional system prompt" }
69336
69636
  },
69337
69637
  required: ["model", "prompt"]
69338
69638
  },
69339
69639
  group: "low-level",
69340
69640
  heartbeat: true,
69341
- handler: async (args) => {
69641
+ handler: async (args, ctx) => {
69342
69642
  try {
69343
- const result = await runPromptViaProxy(args.model, args.prompt, args.system_prompt, args.max_tokens);
69344
- let response = result.content;
69345
- if (result.usage) {
69346
- response += `
69347
-
69348
- ---
69349
- Tokens: ${result.usage.input} input, ${result.usage.output} output`;
69350
- }
69351
- return { content: [{ type: "text", text: response }] };
69643
+ const result = await runPrompt(args.model, args.prompt, args.system_prompt, ctx.signal);
69644
+ return { content: [{ type: "text", text: formatRunPromptResult(result) }] };
69352
69645
  } catch (error) {
69353
69646
  const errMsg = error instanceof Error ? error.message : String(error);
69354
69647
  return {
@@ -69500,35 +69793,30 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
69500
69793
  });
69501
69794
  tools.push({
69502
69795
  name: "compare_models",
69503
- description: "Run the same prompt through multiple models and compare responses",
69796
+ description: "DEBUG. Send the same single prompt to several models, one after another, and show " + "their answers side by side \u2014 to check that routes answer or to eyeball raw answers. " + "Each model gets exactly what run_prompt sends: one request, no tools, no Claude Code " + "session. Not for real work: use team for a blind-judged multi-model run, or " + "create_session for one model doing a task.",
69504
69797
  inputSchema: {
69505
69798
  type: "object",
69506
69799
  properties: {
69507
69800
  models: {
69508
69801
  type: "array",
69509
69802
  items: { type: "string" },
69510
- description: "List of model IDs to compare"
69803
+ description: "List of model names or model specs to compare, in the order to run them"
69511
69804
  },
69512
69805
  prompt: { type: "string", description: "The prompt to send to all models" },
69513
- system_prompt: { type: "string", description: "Optional system prompt" },
69514
- max_tokens: {
69515
- type: "number",
69516
- description: "Maximum tokens in response (omit to let model decide)"
69517
- }
69806
+ system_prompt: { type: "string", description: "Optional system prompt" }
69518
69807
  },
69519
69808
  required: ["models", "prompt"]
69520
69809
  },
69521
- group: "low-level",
69810
+ group: "debug",
69522
69811
  heartbeat: true,
69523
69812
  handler: async (args, ctx) => {
69524
69813
  const modelIds = args.models;
69525
69814
  const prompt = args.prompt;
69526
69815
  const systemPrompt = args.system_prompt;
69527
- const maxTokens = args.max_tokens;
69528
69816
  const results = [];
69529
69817
  for (const model of modelIds) {
69530
69818
  try {
69531
- const result = await runPromptViaProxy(model, prompt, systemPrompt, maxTokens);
69819
+ const result = await runPrompt(model, prompt, systemPrompt, ctx.signal);
69532
69820
  results.push({ model, response: result.content, tokens: result.usage });
69533
69821
  } catch (error) {
69534
69822
  results.push({
@@ -69782,28 +70070,18 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
69782
70070
  const minOutputBytes = args.min_output_bytes;
69783
70071
  const childFlags = buildChildClaudeFlags(args.agent, args.claude_flags) ?? [];
69784
70072
  const resolved = validateSessionPath(path);
69785
- const teamSessionId = resolved.split("/").filter(Boolean).pop() ?? "team";
69786
- const teamCreatedAt = new Date().toISOString();
69787
70073
  const runOpts = {
69788
70074
  requirePattern,
69789
70075
  minOutputBytes,
69790
70076
  claudeFlags: childFlags,
69791
70077
  onProgress: (u) => {
69792
70078
  ctx.reportProgress(`team: ${u.phase}`);
69793
- notifyChannel({
69794
- content: u.rendered,
69795
- sessionId: teamSessionId,
69796
- event: u.phase === "settled" ? u.allFailed ? "failed" : "completed" : "running",
69797
- model: "team",
69798
- elapsedSeconds: (Date.now() - Date.parse(teamCreatedAt)) / 1000,
69799
- createdAt: teamCreatedAt
69800
- });
69801
70079
  }
69802
70080
  };
69803
70081
  const promptText = () => {
69804
70082
  if (input !== undefined)
69805
70083
  return input;
69806
- const existing = join49(resolved, "input.md");
70084
+ const existing = join50(resolved, "input.md");
69807
70085
  return existsSync32(existing) ? readFileSync31(existing, "utf-8") : undefined;
69808
70086
  };
69809
70087
  switch (mode) {
@@ -69962,16 +70240,16 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
69962
70240
  const sp = session_path;
69963
70241
  for (const file of ["status.json", "manifest.json", "input.md"]) {
69964
70242
  try {
69965
- sessionData[file] = readFileSync31(join49(sp, file), "utf-8");
70243
+ sessionData[file] = readFileSync31(join50(sp, file), "utf-8");
69966
70244
  } catch {}
69967
70245
  }
69968
70246
  try {
69969
- const errorDir = join49(sp, "errors");
70247
+ const errorDir = join50(sp, "errors");
69970
70248
  if (existsSync32(errorDir)) {
69971
70249
  for (const f of readdirSync10(errorDir)) {
69972
70250
  if (f.endsWith(".log")) {
69973
70251
  try {
69974
- sessionData[`errors/${f}`] = readFileSync31(join49(errorDir, f), "utf-8");
70252
+ sessionData[`errors/${f}`] = readFileSync31(join50(errorDir, f), "utf-8");
69975
70253
  } catch {}
69976
70254
  }
69977
70255
  }
@@ -69981,7 +70259,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
69981
70259
  for (const f of readdirSync10(sp)) {
69982
70260
  if (f.startsWith("response-") && f.endsWith(".md")) {
69983
70261
  try {
69984
- const content = readFileSync31(join49(sp, f), "utf-8");
70262
+ const content = readFileSync31(join50(sp, f), "utf-8");
69985
70263
  sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
69986
70264
  } catch {}
69987
70265
  }
@@ -69990,7 +70268,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
69990
70268
  }
69991
70269
  let version = "unknown";
69992
70270
  try {
69993
- const pkgPath = join49(__dirname3, "../package.json");
70271
+ const pkgPath = join50(__dirname3, "../package.json");
69994
70272
  if (existsSync32(pkgPath)) {
69995
70273
  version = JSON.parse(readFileSync31(pkgPath, "utf-8")).version;
69996
70274
  }
@@ -70070,7 +70348,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
70070
70348
  });
70071
70349
  tools.push({
70072
70350
  name: "create_session",
70073
- description: "Create a new claudish proxy session for an external model: an interactive Claude Code running " + "it in its own headless magmux pane. Returns at once with state STARTING; the session produces " + "channel notifications as it runs. With a prompt it is one-shot (it ends when that turn " + "settles); without one it is interactive and waits for send_input. Needs magmux >= 0.14.0 " + "(darwin and linux).",
70351
+ description: "Create a new claudish proxy session for an external model: an interactive Claude Code running " + "it in its own headless magmux pane. Returns at once with state STARTING; nothing is " + "pushed while it runs: poll list_sessions (about once every 10 s) for its state, then " + "call get_output once it is COMPLETED. With a prompt it is one-shot (it ends when that turn " + "settles); without one it is interactive and waits for send_input. Needs magmux >= 0.14.0 " + "(darwin and linux).",
70074
70352
  inputSchema: {
70075
70353
  type: "object",
70076
70354
  properties: {
@@ -70103,7 +70381,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
70103
70381
  },
70104
70382
  required: ["model"]
70105
70383
  },
70106
- group: "channel",
70384
+ group: "session",
70107
70385
  handler: async (args) => {
70108
70386
  try {
70109
70387
  const claudishFlags = buildChildClaudeFlags(args.agent, args.claude_flags) ?? [];
@@ -70171,7 +70449,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
70171
70449
  },
70172
70450
  required: ["session_id", "text"]
70173
70451
  },
70174
- group: "channel",
70452
+ group: "session",
70175
70453
  handler: async (args) => {
70176
70454
  const result = sessionManager.sendInput(args.session_id, args.text);
70177
70455
  return {
@@ -70181,7 +70459,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
70181
70459
  });
70182
70460
  tools.push({
70183
70461
  name: "get_output",
70184
- description: "Get a session's answer prose (each settled turn's assistant text, from its transcript). " + "Call after the 'completed' notification to get the full response.",
70462
+ description: "Get a session's answer prose (each settled turn's assistant text, from its transcript). " + "Call once list_sessions shows the session COMPLETED (or between turns of an " + "interactive session).",
70185
70463
  inputSchema: {
70186
70464
  type: "object",
70187
70465
  properties: {
@@ -70193,7 +70471,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
70193
70471
  },
70194
70472
  required: ["session_id"]
70195
70473
  },
70196
- group: "channel",
70474
+ group: "session",
70197
70475
  handler: async (args) => {
70198
70476
  try {
70199
70477
  const output = sessionManager.getOutput(args.session_id, args.tail_lines);
@@ -70223,7 +70501,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
70223
70501
  },
70224
70502
  required: ["session_id"]
70225
70503
  },
70226
- group: "channel",
70504
+ group: "session",
70227
70505
  handler: async (args) => {
70228
70506
  try {
70229
70507
  const sessionId = optionalString(args.session_id, "session_id");
@@ -70237,7 +70515,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
70237
70515
  });
70238
70516
  tools.push({
70239
70517
  name: "list_sessions",
70240
- description: "List channel sessions: {contract_version, capabilities, sessions}. Optionally include " + "finished ones. Each row reports `state`, `activity` and `idle_seconds`: how long since " + "the session's screen or transcript last changed. Nothing kills a session for being " + "idle \u2014 a child inside a long Bash call is silent and working \u2014 so this is yours to " + "judge against the task you set, and `cancel_session` is yours to call if the answer is no.",
70518
+ description: "List sessions: {contract_version, capabilities, sessions}. Optionally include " + "finished ones. Each row reports `state`, `activity` and `idle_seconds`: how long since " + "the session's screen or transcript last changed. Nothing kills a session for being " + "idle \u2014 a child inside a long Bash call is silent and working \u2014 so this is yours to " + "judge against the task you set, and `cancel_session` is yours to call if the answer is no. " + "A failed row's `reason_detail` is one line saying why (for api_error, the provider's " + "own error message); it is null while the session is live and on COMPLETED.",
70241
70519
  inputSchema: {
70242
70520
  type: "object",
70243
70521
  properties: {
@@ -70247,7 +70525,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
70247
70525
  }
70248
70526
  }
70249
70527
  },
70250
- group: "channel",
70528
+ group: "session",
70251
70529
  handler: async (args) => {
70252
70530
  try {
70253
70531
  const includeCompleted = optionalBoolean(args.include_completed, "include_completed");
@@ -70262,7 +70540,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
70262
70540
  });
70263
70541
  tools.push({
70264
70542
  name: "get_diagnostics",
70265
- description: "Explain what a channel session actually did \u2014 its final screen, upstream error bodies, " + "the recent state records, anomalies, the resolved model chain, accounting, and the paths " + "to the full records (transcript included). Call this FIRST whenever a session fails, times " + "out, or completes with empty or surprising output; it needs no re-run and no debug flag. " + "`idleSeconds` reports how long since the screen or transcript last changed, and is null " + "once the session is no longer live. It is information, never a verdict: claudish does " + "not terminate a session for silence.",
70543
+ description: "Explain what a session actually did \u2014 its final screen, upstream error bodies, " + "the recent state records, anomalies, the resolved model chain, accounting, and the paths " + "to the full records (transcript included). Call this FIRST whenever a session fails, times " + "out, or completes with empty or surprising output; it needs no re-run and no debug flag. " + "`idleSeconds` reports how long since the screen or transcript last changed, and is null " + "once the session is no longer live. It is information, never a verdict: claudish does " + "not terminate a session for silence.",
70266
70544
  inputSchema: {
70267
70545
  type: "object",
70268
70546
  properties: {
@@ -70274,7 +70552,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
70274
70552
  },
70275
70553
  required: ["session_id"]
70276
70554
  },
70277
- group: "channel",
70555
+ group: "session",
70278
70556
  handler: async (args) => {
70279
70557
  try {
70280
70558
  const diagnostics = sessionManager.getDiagnostics(args.session_id, args.event_limit);
@@ -70312,7 +70590,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
70312
70590
  },
70313
70591
  required: ["session_id"]
70314
70592
  },
70315
- group: "channel",
70593
+ group: "session",
70316
70594
  handler: async (args) => {
70317
70595
  try {
70318
70596
  const sessionId = optionalString(args.session_id, "session_id");
@@ -70334,77 +70612,34 @@ function resolveToolGroups(mode) {
70334
70612
  return new Set(["low-level"]);
70335
70613
  case "agentic":
70336
70614
  return new Set(["agentic"]);
70337
- case "channel":
70338
- return new Set(["channel"]);
70615
+ case "session":
70616
+ return new Set(["session"]);
70617
+ case "debug":
70618
+ return new Set(["debug"]);
70339
70619
  default:
70340
- return new Set(["low-level", "agentic", "channel"]);
70620
+ return new Set(["low-level", "agentic", "session", "debug"]);
70341
70621
  }
70342
70622
  }
70343
- function mapEventToTaskStatus(event) {
70344
- return EVENT_TO_TASK_STATUS.get(event) ?? "working";
70623
+ function unknownToolModeWarning(mode) {
70624
+ if (TOOL_MODES.includes(mode))
70625
+ return;
70626
+ const renamed = mode === "channel" ? " (`channel` was renamed to `session`)" : "";
70627
+ return `[claudish] CLAUDISH_MCP_TOOLS=${JSON.stringify(mode)} is not a tool mode${renamed}; selecting all tools. Valid values: ${TOOL_MODES.join(", ")}`;
70345
70628
  }
70346
70629
  async function main() {
70347
70630
  const toolMode = (process.env.CLAUDISH_MCP_TOOLS || "all").toLowerCase();
70348
70631
  const nested = inMcpSession();
70349
70632
  const enabledGroups = resolveToolGroups(toolMode);
70350
- const channelEnabled = !nested && enabledGroups.has("channel");
70351
- const server = new Server({ name: "claudish", version: "9.0.0" }, {
70352
- capabilities: {
70353
- ...channelEnabled ? { experimental: { "claude/channel": {} } } : {},
70354
- tools: {}
70355
- },
70633
+ const toolModeWarning = unknownToolModeWarning(toolMode);
70634
+ if (toolModeWarning)
70635
+ console.error(toolModeWarning);
70636
+ const server = new Server({ name: "claudish", version: VERSION }, {
70637
+ capabilities: { tools: {} },
70356
70638
  instructions: nested ? NESTED_INSTRUCTIONS : INSTRUCTIONS
70357
70639
  });
70358
- const sessionManager = new SessionManager({
70359
- onStateChange: wrapStateChange((sessionId, event) => {
70360
- const notificationContent = event.type === "failed" || event.type === "timeout" ? `${event.content}
70361
-
70362
- Call get_diagnostics with session_id: "${sessionId}" for the final screen, the upstream error bodies and the transcript path. To report it, use the report_error tool with error_type: "provider_failure" and model: "${event.model}".` : event.content;
70363
- const result = server.notification({
70364
- method: "notifications/claude/channel",
70365
- params: {
70366
- content: notificationContent,
70367
- meta: {
70368
- session_id: sessionId,
70369
- event: event.type,
70370
- model: event.model,
70371
- elapsed_seconds: String(event.elapsedSeconds),
70372
- task_id: sessionId,
70373
- status: mapEventToTaskStatus(event.type),
70374
- created_at: event.createdAt,
70375
- last_updated_at: new Date().toISOString(),
70376
- ...event.extraMeta
70377
- }
70378
- }
70379
- });
70380
- watchNotificationResult(result, { sessionId, eventType: event.type });
70381
- })
70382
- });
70383
- const notifyChannel = (p) => {
70384
- if (!channelEnabled)
70385
- return;
70386
- try {
70387
- const result = server.notification({
70388
- method: "notifications/claude/channel",
70389
- params: {
70390
- content: p.content,
70391
- meta: {
70392
- session_id: p.sessionId,
70393
- event: p.event,
70394
- model: p.model,
70395
- elapsed_seconds: String(Math.round(p.elapsedSeconds)),
70396
- task_id: p.sessionId,
70397
- status: mapEventToTaskStatus(p.event),
70398
- created_at: p.createdAt,
70399
- last_updated_at: new Date().toISOString()
70400
- }
70401
- }
70402
- });
70403
- watchNotificationResult(result, { sessionId: p.sessionId, eventType: p.event });
70404
- } catch {}
70405
- };
70640
+ const sessionManager = new SessionManager;
70406
70641
  const progressIntervalMs = resolveProgressIntervalMs();
70407
- const allTools = defineTools(sessionManager, notifyChannel, nested);
70642
+ const allTools = defineTools(sessionManager, nested);
70408
70643
  const nestedNames = NESTED_MCP_TOOL_NAMES;
70409
70644
  const enabledTools = allTools.filter((t) => enabledGroups.has(t.group) && (!nested || nestedNames.includes(t.name)));
70410
70645
  const toolMap = new Map(enabledTools.map((t) => [t.name, t]));
@@ -70432,7 +70667,8 @@ Call get_diagnostics with session_id: "${sessionId}" for the final screen, the u
70432
70667
  send: (frame) => extra.sendNotification({ method: "notifications/progress", params: frame })
70433
70668
  }) : NOOP_HEARTBEAT;
70434
70669
  const ctx = {
70435
- reportProgress: (message) => heartbeat.tick(message)
70670
+ reportProgress: (message) => heartbeat.tick(message),
70671
+ signal: extra.signal
70436
70672
  };
70437
70673
  try {
70438
70674
  return await tool.handler(args ?? {}, ctx);
@@ -70451,7 +70687,6 @@ Call get_diagnostics with session_id: "${sessionId}" for the final screen, the u
70451
70687
  }
70452
70688
  });
70453
70689
  const transport = new StdioServerTransport;
70454
- installWireTap();
70455
70690
  await server.connect(transport);
70456
70691
  installMcpShutdown(sessionManager);
70457
70692
  ensureSwept(sockRootFor()).catch(() => {
@@ -70460,6 +70695,7 @@ Call get_diagnostics with session_id: "${sessionId}" for the final screen, the u
70460
70695
  }
70461
70696
  function installMcpShutdown(sessionManager) {
70462
70697
  const before = async () => {
70698
+ stopAllClaudeCodePrintChildren();
70463
70699
  await Promise.allSettled([shutdownAllTeamRuns(), sessionManager.shutdownAll()]);
70464
70700
  };
70465
70701
  installPaneShutdownHooks({ stdin: true, before });
@@ -70470,50 +70706,43 @@ function startMcpServer() {
70470
70706
  process.exit(1);
70471
70707
  });
70472
70708
  }
70473
- var import_dotenv2, __filename3, __dirname3, CLAUDISH_CACHE_DIR, OPENROUTER_MODELS_CACHE_PATH, CACHE_MAX_AGE_DAYS = 2, INSTRUCTIONS = `Claudish MCP server provides access to external AI models (OpenRouter, Ollama, LM Studio, etc.) for coding tasks.
70474
-
70475
- ## Channel Mode \u2014 External Model Sessions
70709
+ var import_dotenv2, __filename3, __dirname3, CLAUDISH_CACHE_DIR, OPENROUTER_MODELS_CACHE_PATH, CACHE_MAX_AGE_DAYS = 2, INSTRUCTIONS = `Claudish MCP server gives you access to external AI models (OpenRouter, Ollama, LM Studio and every claudish provider), and to Claude models on the user's own Claude Code login.
70476
70710
 
70477
- When channel mode is active, you receive <channel source="claudish" ...> notifications about running external model sessions. Each session is an interactive Claude Code running the model in its own headless terminal pane.
70711
+ ## Which tool
70478
70712
 
70479
- ### Events
70713
+ - run_prompt: one quick prompt to one model's API. One request, one answer; no tools, no files, no session.
70714
+ - create_session: one model doing a task as a full Claude Code session (tools, files, several turns).
70715
+ - team: several models on the same task, each a full Claude Code session, with optional blind judging.
70480
70716
 
70481
- - running: The session's turn is running (its prompt was accepted). Note the session_id for future calls.
70482
- - tool_executing: The model is using a tool (Read, Write, Bash, etc.). Carries tool and tool_count.
70483
- - input_required (event waiting_for_input): The session waits for send_input: an interactive session between turns, or a session stopped on a question (meta activity "AskUserQuestion"). A send declines a question and becomes the next prompt.
70484
- - input_required (event awaiting_permission): A permission or plan-approval dialog is open. A send declines it and becomes the next prompt.
70485
- - completed: The session finished successfully. Call get_output to retrieve the full output.
70486
- - failed: The session failed (boot, prompt not accepted or not read, child exited, API error, pane lost). Call get_diagnostics for the cause.
70487
- - timeout: The session hit its timeout_seconds; the pane was closed. Call get_diagnostics to see how far it got.
70488
- - cancelled: The session was cancelled via cancel_session.
70717
+ ## Sessions
70489
70718
 
70490
- ### Workflow
70719
+ Each session is an interactive Claude Code running the model in its own headless terminal pane. Nothing is pushed to you while it runs: poll.
70491
70720
 
70492
- 1. Call create_session with a model and prompt to start an async session (state STARTING while Claude Code boots).
70493
- 2. Watch for <channel> notifications \u2014 they arrive automatically.
70494
- 3. send_input may be called at any time; it is queued until the session is idle. On input_required, call send_input with the answer.
70495
- 4. On completed: call get_output to get the full response.
70496
- 5. On failed or timeout \u2014 or on a completed session whose output is empty or
70497
- surprising \u2014 call get_diagnostics. It returns the child's final screen, the
70498
- upstream error bodies, the recent state records, the resolved model chain and the
70499
- paths to the full records. It needs no re-run and no debug flag.
70500
- 6. Use list_sessions to see sessions: each row has state, activity, idle_seconds and accounting.
70501
- 7. Use capture_session to read a session's current terminal screen.
70502
- 8. Use cancel_session to stop a running session.
70721
+ 1. create_session returns {session_id, state: "STARTING"} at once while Claude Code boots.
70722
+ 2. Poll list_sessions (include_completed: true), about once every 10 seconds. Each row has state, activity, idle_seconds and accounting.
70723
+ - STARTING: booting, or the first prompt is not yet accepted.
70724
+ - RUNNING: a turn is in progress (activity names the tool in use).
70725
+ - AWAITING_INPUT: waiting for send_input \u2014 an interactive session between turns, or a turn stopped on a question (activity "AskUserQuestion"). A send declines a question and becomes the next prompt.
70726
+ - AWAITING_PERMISSION: a permission or plan-approval dialog is open. A send declines it and becomes the next prompt.
70727
+ - COMPLETED, FAILED, TIMEOUT, CANCELLED, EMPTY: finished.
70728
+ 3. send_input may be called at any time; it is queued until the session is idle.
70729
+ 4. COMPLETED: call get_output for the answer.
70730
+ 5. FAILED or TIMEOUT \u2014 or COMPLETED with an empty or surprising answer \u2014 call get_diagnostics. It returns the child's final screen, the upstream error bodies, the recent state records, the resolved model chain and the paths to the full records. It needs no re-run and no debug flag.
70731
+ 6. capture_session reads a session's current screen; cancel_session stops it. Nothing stops a session for being idle: a child inside a long build is silent and working.
70503
70732
 
70504
- The session_id in the channel tag's meta attributes is the key for all tool calls.`, proxyInstance = null, proxyStarting = null, SCORE_TIE_EPSILON = 0.000001, NEXT_STEP, sanitize2, TASK_STATUS_BY_EVENT, EVENT_TO_TASK_STATUS;
70733
+ The session_id from create_session is the key for every session tool.`, proxyInstance = null, proxyStarting = null, SCORE_TIE_EPSILON = 0.000001, NEXT_STEP, sanitize2, TOOL_MODES;
70505
70734
  var init_mcp_server = __esm(() => {
70506
70735
  init_server2();
70507
70736
  init_stdio2();
70508
70737
  init_types();
70509
70738
  init_model_catalog();
70510
70739
  init_prehydrate();
70511
- init_diagnostics();
70512
- init_channel();
70513
- init_parent_session();
70514
70740
  init_remote_provider_types();
70741
+ init_mcp_session();
70742
+ init_parent_session();
70515
70743
  init_nested_mode();
70516
70744
  init_progress_heartbeat();
70745
+ init_run_prompt_claude_code();
70517
70746
  init_model_loader();
70518
70747
  init_child_env();
70519
70748
  init_pane();
@@ -70532,8 +70761,8 @@ var init_mcp_server = __esm(() => {
70532
70761
  import_dotenv2.config({ quiet: true });
70533
70762
  __filename3 = fileURLToPath3(import.meta.url);
70534
70763
  __dirname3 = dirname14(__filename3);
70535
- CLAUDISH_CACHE_DIR = join49(homedir33(), ".claudish");
70536
- OPENROUTER_MODELS_CACHE_PATH = join49(CLAUDISH_CACHE_DIR, "openrouter-models.json");
70764
+ CLAUDISH_CACHE_DIR = join50(homedir33(), ".claudish");
70765
+ OPENROUTER_MODELS_CACHE_PATH = join50(CLAUDISH_CACHE_DIR, "openrouter-models.json");
70537
70766
  NEXT_STEP = {
70538
70767
  cancelled: "you stopped this slot; nothing is wrong with it. Re-run it if you still want its vote",
70539
70768
  timeout: "grid mode only \u2014 magmux ended the pane. The orchestrator has no deadline",
@@ -70552,18 +70781,7 @@ var init_mcp_server = __esm(() => {
70552
70781
  shape_mismatch: "the answer (assistant text after the task was read) did not match. Every assistant " + "message of the turn was read from the transcript, so nothing was lost in transit \u2014 " + "the model did not produce it. Re-prompt with the required format restated; do NOT " + "count this slot as a vote"
70553
70782
  };
70554
70783
  sanitize2 = sanitizeForReport;
70555
- TASK_STATUS_BY_EVENT = {
70556
- starting: "working",
70557
- running: "working",
70558
- tool_executing: "working",
70559
- waiting_for_input: "input_required",
70560
- awaiting_permission: "input_required",
70561
- completed: "completed",
70562
- failed: "failed",
70563
- cancelled: "cancelled",
70564
- timeout: "failed"
70565
- };
70566
- EVENT_TO_TASK_STATUS = new Map(Object.entries(TASK_STATUS_BY_EVENT));
70784
+ TOOL_MODES = ["all", "low-level", "agentic", "session", "debug"];
70567
70785
  });
70568
70786
 
70569
70787
  // src/serve-command.ts
@@ -70666,7 +70884,7 @@ var init_serve_command = __esm(() => {
70666
70884
  });
70667
70885
 
70668
70886
  // src/behavior-command.ts
70669
- import { existsSync as existsSync34, readFileSync as readFileSync33, writeFileSync as writeFileSync23 } from "fs";
70887
+ import { existsSync as existsSync34, readFileSync as readFileSync33, writeFileSync as writeFileSync24 } from "fs";
70670
70888
  function severityColor(sev) {
70671
70889
  if (sev === "fix")
70672
70890
  return green(sev);
@@ -70774,7 +70992,7 @@ function setTelemetryEnabled(value) {
70774
70992
  const behavior = cfg.behavior && typeof cfg.behavior === "object" && !Array.isArray(cfg.behavior) ? { ...cfg.behavior } : {};
70775
70993
  behavior.telemetry = { enabled: value };
70776
70994
  cfg.behavior = behavior;
70777
- writeFileSync23(path, `${JSON.stringify(cfg, null, 2)}
70995
+ writeFileSync24(path, `${JSON.stringify(cfg, null, 2)}
70778
70996
  `, "utf-8");
70779
70997
  }
70780
70998
  function showTelemetry(action, json) {
@@ -70866,10 +71084,10 @@ var init_behavior_command = __esm(() => {
70866
71084
  });
70867
71085
 
70868
71086
  // src/team-grid.ts
70869
- import { spawn as spawn2 } from "child_process";
70870
- import { existsSync as existsSync35, readFileSync as readFileSync34, writeFileSync as writeFileSync24 } from "fs";
71087
+ import { spawn as spawn3 } from "child_process";
71088
+ import { existsSync as existsSync35, readFileSync as readFileSync34, writeFileSync as writeFileSync25 } from "fs";
70871
71089
  import { connect as netConnect2 } from "net";
70872
- import { join as join50 } from "path";
71090
+ import { join as join51 } from "path";
70873
71091
  import { setTimeout as wait } from "timers/promises";
70874
71092
  function paneRouteLine(explanation) {
70875
71093
  const origin = describeRouteExplanation(explanation);
@@ -71019,9 +71237,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
71019
71237
  const keep = opts?.keep ?? false;
71020
71238
  const manifest = setupSession(sessionPath, models, input);
71021
71239
  const startedAt = new Date().toISOString();
71022
- const gridfilePath = join50(sessionPath, "gridfile.txt");
71023
- const prompt = readFileSync34(join50(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
71024
- const rawPrompt = readFileSync34(join50(sessionPath, "input.md"), "utf-8");
71240
+ const gridfilePath = join51(sessionPath, "gridfile.txt");
71241
+ const prompt = readFileSync34(join51(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
71242
+ const rawPrompt = readFileSync34(join51(sessionPath, "input.md"), "utf-8");
71025
71243
  const usedBannerColors = new Set;
71026
71244
  const routeLines = mode === "interactive" ? new Map : await resolvePaneRouteLines(Object.values(manifest.models).map((entry) => entry.model));
71027
71245
  const gridLines = Object.entries(manifest.models).map(([anonId]) => {
@@ -71033,7 +71251,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
71033
71251
  const header = buildPaneHeader(model, routeLines.get(model) ?? "", rawPrompt, bg);
71034
71252
  return `${header} claudish --model ${model} -y --quiet '${prompt}'`;
71035
71253
  });
71036
- writeFileSync24(gridfilePath, `${gridLines.join(`
71254
+ writeFileSync25(gridfilePath, `${gridLines.join(`
71037
71255
  `)}
71038
71256
  `, "utf-8");
71039
71257
  const magmuxPath = findMagmuxBinary();
@@ -71041,7 +71259,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
71041
71259
  if (!keep && mode === "default") {
71042
71260
  spawnArgs.push("-w");
71043
71261
  }
71044
- const proc = spawn2(magmuxPath, spawnArgs, {
71262
+ const proc = spawn3(magmuxPath, spawnArgs, {
71045
71263
  stdio: "inherit",
71046
71264
  env: { ...process.env }
71047
71265
  });
@@ -71053,8 +71271,8 @@ async function runWithGrid(sessionPath, models, input, opts) {
71053
71271
  });
71054
71272
  const [{ results }] = await Promise.all([subscription, procExit]);
71055
71273
  const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
71056
- const statusPath = join50(sessionPath, "status.json");
71057
- writeFileSync24(statusPath, JSON.stringify(status, null, 2), "utf-8");
71274
+ const statusPath = join51(sessionPath, "status.json");
71275
+ writeFileSync25(statusPath, JSON.stringify(status, null, 2), "utf-8");
71058
71276
  return status;
71059
71277
  }
71060
71278
  var BANNER_BG_COLORS;
@@ -71074,7 +71292,7 @@ var init_team_grid = __esm(() => {
71074
71292
 
71075
71293
  // src/team-cli.ts
71076
71294
  import { readFileSync as readFileSync35 } from "fs";
71077
- import { join as join51 } from "path";
71295
+ import { join as join52 } from "path";
71078
71296
  async function runPaneTeam(sessionPath, models, input, opts) {
71079
71297
  installPaneShutdownHooks({ exitAfter: true });
71080
71298
  try {
@@ -71212,7 +71430,7 @@ async function teamCommand(args) {
71212
71430
  }
71213
71431
  case "judge": {
71214
71432
  await judgeResponses(sessionPath, { judges });
71215
- console.log(readFileSync35(join51(sessionPath, "verdict.md"), "utf-8"));
71433
+ console.log(readFileSync35(join52(sessionPath, "verdict.md"), "utf-8"));
71216
71434
  break;
71217
71435
  }
71218
71436
  case "run-and-judge": {
@@ -71228,7 +71446,7 @@ async function teamCommand(args) {
71228
71446
  });
71229
71447
  printStatus(status);
71230
71448
  await judgeResponses(sessionPath, { judges });
71231
- console.log(readFileSync35(join51(sessionPath, "verdict.md"), "utf-8"));
71449
+ console.log(readFileSync35(join52(sessionPath, "verdict.md"), "utf-8"));
71232
71450
  break;
71233
71451
  }
71234
71452
  case "status": {
@@ -71802,7 +72020,7 @@ var init_keychain_command = __esm(() => {
71802
72020
  import { spawnSync as spawnSync2 } from "child_process";
71803
72021
  import { existsSync as existsSync36, unlinkSync as unlinkSync9 } from "fs";
71804
72022
  import { homedir as homedir34 } from "os";
71805
- import { join as join52 } from "path";
72023
+ import { join as join53 } from "path";
71806
72024
  async function defaultSuggestModel() {
71807
72025
  try {
71808
72026
  const tok = readSharedAntigravityToken();
@@ -71923,7 +72141,7 @@ No session detected yet. Starting the Antigravity CLI interactively \u2014
71923
72141
  async logout(deps) {
71924
72142
  deleteSharedAntigravityToken(deps);
71925
72143
  try {
71926
- const tokenFile = join52(homedir34(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
72144
+ const tokenFile = join53(homedir34(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
71927
72145
  if (existsSync36(tokenFile))
71928
72146
  unlinkSync9(tokenFile);
71929
72147
  } catch {}
@@ -80185,20 +80403,20 @@ var init_terminal_isolation = __esm(() => {
80185
80403
  });
80186
80404
 
80187
80405
  // src/claude-runner.ts
80188
- import { spawn as spawn3, spawnSync as spawnSync4 } from "child_process";
80406
+ import { spawn as spawn4, spawnSync as spawnSync4 } from "child_process";
80189
80407
  import {
80190
- closeSync as closeSync10,
80408
+ closeSync as closeSync11,
80191
80409
  existsSync as existsSync38,
80192
- mkdirSync as mkdirSync22,
80193
- openSync as openSync10,
80410
+ mkdirSync as mkdirSync23,
80411
+ openSync as openSync11,
80194
80412
  readFileSync as readFileSync36,
80195
80413
  readdirSync as readdirSync11,
80196
80414
  statSync as statSync13,
80197
80415
  unlinkSync as unlinkSync10,
80198
- writeFileSync as writeFileSync25
80416
+ writeFileSync as writeFileSync26
80199
80417
  } from "fs";
80200
- import { homedir as homedir35, tmpdir as tmpdir2 } from "os";
80201
- import { dirname as dirname15, join as join53 } from "path";
80418
+ import { homedir as homedir35, tmpdir as tmpdir3 } from "os";
80419
+ import { dirname as dirname15, join as join54 } from "path";
80202
80420
  import { isatty } from "tty";
80203
80421
  function releaseTerminalIsolation() {
80204
80422
  if (!restoreTerminal)
@@ -80263,7 +80481,7 @@ function hasResolvableAnthropicAuth(deps = {}) {
80263
80481
  if (isRealAnthropicEnvCredential(env, "ANTHROPIC_API_KEY") || isRealAnthropicEnvCredential(env, "ANTHROPIC_AUTH_TOKEN")) {
80264
80482
  return true;
80265
80483
  }
80266
- if (fileExists(join53(homedir35(), ".claude", ".credentials.json")))
80484
+ if (fileExists(join54(homedir35(), ".claude", ".credentials.json")))
80267
80485
  return true;
80268
80486
  return keychainProbe();
80269
80487
  }
@@ -80278,7 +80496,7 @@ function isProxyAuthMode(config) {
80278
80496
  }
80279
80497
  function managedSettingsPath() {
80280
80498
  if (isWindows2()) {
80281
- return join53(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
80499
+ return join54(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
80282
80500
  }
80283
80501
  if (process.platform === "darwin") {
80284
80502
  return "/Library/Application Support/ClaudeCode/managed-settings.json";
@@ -80298,10 +80516,10 @@ function isWindows2() {
80298
80516
  return process.platform === "win32";
80299
80517
  }
80300
80518
  function createStatusLineScript(tokenFilePath) {
80301
- const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
80302
- const claudishDir = join53(homeDir, ".claudish");
80519
+ const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir3();
80520
+ const claudishDir = join54(homeDir, ".claudish");
80303
80521
  const timestamp = Date.now();
80304
- const scriptPath = join53(claudishDir, `status-${timestamp}.js`);
80522
+ const scriptPath = join54(claudishDir, `status-${timestamp}.js`);
80305
80523
  const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
80306
80524
  const light = getThemeMode() === "light";
80307
80525
  const cyanCode = light ? "38;2;14;116;144" : "96";
@@ -80434,13 +80652,13 @@ process.stdin.on('end', () => {
80434
80652
  }
80435
80653
  });
80436
80654
  `;
80437
- writeFileSync25(scriptPath, script, "utf-8");
80655
+ writeFileSync26(scriptPath, script, "utf-8");
80438
80656
  return scriptPath;
80439
80657
  }
80440
80658
  function initializeTokenFile(tokenFilePath) {
80441
80659
  try {
80442
- mkdirSync22(dirname15(tokenFilePath), { recursive: true });
80443
- writeFileSync25(tokenFilePath, JSON.stringify({
80660
+ mkdirSync23(dirname15(tokenFilePath), { recursive: true });
80661
+ writeFileSync26(tokenFilePath, JSON.stringify({
80444
80662
  input_tokens: 0,
80445
80663
  output_tokens: 0,
80446
80664
  total_tokens: 0,
@@ -80471,7 +80689,7 @@ function cleanupStaleTokenFiles(dir, now = Date.now(), maxAgeMs = STALE_TOKEN_FI
80471
80689
  if (!name.startsWith("tokens-") || !name.endsWith(".json"))
80472
80690
  continue;
80473
80691
  scanned++;
80474
- const full = join53(dir, name);
80692
+ const full = join54(dir, name);
80475
80693
  try {
80476
80694
  if (statSync13(full).mtimeMs >= cutoff)
80477
80695
  continue;
@@ -80500,9 +80718,9 @@ function parseSettingsArgSafe(value) {
80500
80718
  }
80501
80719
  function userSettingsFileCandidates(cwd) {
80502
80720
  return [
80503
- join53(homedir35(), ".claude", "settings.json"),
80504
- join53(cwd, ".claude", "settings.json"),
80505
- join53(cwd, ".claude", "settings.local.json")
80721
+ join54(homedir35(), ".claude", "settings.json"),
80722
+ join54(cwd, ".claude", "settings.json"),
80723
+ join54(cwd, ".claude", "settings.local.json")
80506
80724
  ];
80507
80725
  }
80508
80726
  function discoverUserStatusLineCommand(claudeArgs = [], cwd = process.cwd()) {
@@ -80542,13 +80760,13 @@ function buildChainedStatusCommand(userCommand, claudishBody, claudishSegment) {
80542
80760
  return `JSON=$(cat); ${runUser}; ${claudishBody}; SEG=$(${claudishSegment}); ${separator}; ${emit}`;
80543
80761
  }
80544
80762
  function createTempSettingsFile(_modelDisplay, port, proxyAuthMode, userStatusLineCommand) {
80545
- const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
80546
- const claudishDir = join53(homeDir, ".claudish");
80763
+ const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir3();
80764
+ const claudishDir = join54(homeDir, ".claudish");
80547
80765
  try {
80548
- mkdirSync22(claudishDir, { recursive: true });
80766
+ mkdirSync23(claudishDir, { recursive: true });
80549
80767
  } catch {}
80550
80768
  const timestamp = Date.now();
80551
- const tempPath = join53(claudishDir, `settings-${timestamp}.json`);
80769
+ const tempPath = join54(claudishDir, `settings-${timestamp}.json`);
80552
80770
  const assignedFile = assignedTokenFile(process.env) !== null;
80553
80771
  const tokenFilePath = resolveTokenFilePath(port);
80554
80772
  cleanupStaleTokenFiles(claudishDir);
@@ -80585,7 +80803,7 @@ function createTempSettingsFile(_modelDisplay, port, proxyAuthMode, userStatusLi
80585
80803
  padding: 0
80586
80804
  };
80587
80805
  const settings = buildClaudishSettingsOverlay(statusLine, proxyAuthMode);
80588
- writeFileSync25(tempPath, JSON.stringify(settings, null, 2), "utf-8");
80806
+ writeFileSync26(tempPath, JSON.stringify(settings, null, 2), "utf-8");
80589
80807
  return { path: tempPath, statusLine, tokenFilePath };
80590
80808
  }
80591
80809
  function scrubChildEnv(env, opts) {
@@ -80603,6 +80821,7 @@ function buildClaudishSettingsOverlay(statusLine, proxyAuthMode, paneChild = isP
80603
80821
  }
80604
80822
  if (paneChild) {
80605
80823
  settings.skipDangerousModePermissionPrompt = true;
80824
+ settings.editorMode = "normal";
80606
80825
  }
80607
80826
  return settings;
80608
80827
  }
@@ -80624,7 +80843,10 @@ function mergeUserSettingsIfPresent(config, tempSettingsPath, statusLine, proxyA
80624
80843
  if (paneChild && !("skipDangerousModePermissionPrompt" in userSettings)) {
80625
80844
  userSettings.skipDangerousModePermissionPrompt = true;
80626
80845
  }
80627
- writeFileSync25(tempSettingsPath, JSON.stringify(userSettings, null, 2), "utf-8");
80846
+ if (paneChild) {
80847
+ userSettings.editorMode = "normal";
80848
+ }
80849
+ writeFileSync26(tempSettingsPath, JSON.stringify(userSettings, null, 2), "utf-8");
80628
80850
  } catch {
80629
80851
  if (!config.quiet) {
80630
80852
  console.warn(`[claudish] Warning: could not merge user settings: ${userSettingsValue}`);
@@ -80923,7 +81145,7 @@ async function runClaudeWithProxy(config, proxyUrl, onCleanup) {
80923
81145
  console.error(`
80924
81146
  Or set CLAUDE_PATH to your custom installation:`);
80925
81147
  const home = homedir35();
80926
- const localPath = isWindows2() ? join53(home, ".claude", "local", "claude.exe") : join53(home, ".claude", "local", "claude");
81148
+ const localPath = isWindows2() ? join54(home, ".claude", "local", "claude.exe") : join54(home, ".claude", "local", "claude");
80927
81149
  console.error(` export CLAUDE_PATH=${localPath}`);
80928
81150
  process.exit(1);
80929
81151
  }
@@ -80934,11 +81156,11 @@ Or set CLAUDE_PATH to your custom installation:`);
80934
81156
  const childWantsTty = config.interactive && !process.stdout.isTTY && Boolean(process.stdin.isTTY);
80935
81157
  if (childWantsTty) {
80936
81158
  try {
80937
- const fd = openSync10("/dev/fd/0", "r+");
81159
+ const fd = openSync11("/dev/fd/0", "r+");
80938
81160
  if (isatty(fd)) {
80939
81161
  ttyFd = fd;
80940
81162
  } else {
80941
- closeSync10(fd);
81163
+ closeSync11(fd);
80942
81164
  }
80943
81165
  } catch {
80944
81166
  ttyFd = undefined;
@@ -80957,7 +81179,7 @@ Or set CLAUDE_PATH to your custom installation:`);
80957
81179
  stdoutIsTty: Boolean(process.stdout.isTTY),
80958
81180
  magmuxBinary: paneCapability.magmux
80959
81181
  }) : null;
80960
- const proc = wrap ? spawn3(wrap.command, wrap.args, { env: wrap.env, stdio, shell: false }) : spawn3(spawnCommand, claudeArgs, {
81182
+ const proc = wrap ? spawn4(wrap.command, wrap.args, { env: wrap.env, stdio, shell: false }) : spawn4(spawnCommand, claudeArgs, {
80961
81183
  env,
80962
81184
  stdio,
80963
81185
  shell: needsShell
@@ -80983,7 +81205,7 @@ Or set CLAUDE_PATH to your custom installation:`);
80983
81205
  const fdToClose = ttyFd;
80984
81206
  proc.on("spawn", () => {
80985
81207
  try {
80986
- closeSync10(fdToClose);
81208
+ closeSync11(fdToClose);
80987
81209
  } catch {}
80988
81210
  });
80989
81211
  }
@@ -81036,15 +81258,15 @@ async function findClaudeBinary() {
81036
81258
  }
81037
81259
  }
81038
81260
  const home = homedir35();
81039
- const localPath = isWindows ? join53(home, ".claude", "local", "claude.exe") : join53(home, ".claude", "local", "claude");
81261
+ const localPath = isWindows ? join54(home, ".claude", "local", "claude.exe") : join54(home, ".claude", "local", "claude");
81040
81262
  if (existsSync38(localPath)) {
81041
81263
  return localPath;
81042
81264
  }
81043
81265
  if (isWindows) {
81044
81266
  const windowsPaths = [
81045
- join53(home, "AppData", "Roaming", "npm", "claude.cmd"),
81046
- join53(home, ".npm-global", "claude.cmd"),
81047
- join53(home, "node_modules", ".bin", "claude.cmd")
81267
+ join54(home, "AppData", "Roaming", "npm", "claude.cmd"),
81268
+ join54(home, ".npm-global", "claude.cmd"),
81269
+ join54(home, "node_modules", ".bin", "claude.cmd")
81048
81270
  ];
81049
81271
  for (const path of windowsPaths) {
81050
81272
  if (existsSync38(path)) {
@@ -81055,11 +81277,11 @@ async function findClaudeBinary() {
81055
81277
  const commonPaths = [
81056
81278
  "/usr/local/bin/claude",
81057
81279
  "/opt/homebrew/bin/claude",
81058
- join53(home, ".npm-global/bin/claude"),
81059
- join53(home, ".local/bin/claude"),
81060
- join53(home, "node_modules/.bin/claude"),
81280
+ join54(home, ".npm-global/bin/claude"),
81281
+ join54(home, ".local/bin/claude"),
81282
+ join54(home, "node_modules/.bin/claude"),
81061
81283
  "/data/data/com.termux/files/usr/bin/claude",
81062
- join53(home, "../usr/bin/claude")
81284
+ join54(home, "../usr/bin/claude")
81063
81285
  ];
81064
81286
  for (const path of commonPaths) {
81065
81287
  if (existsSync38(path)) {
@@ -81069,7 +81291,7 @@ async function findClaudeBinary() {
81069
81291
  }
81070
81292
  try {
81071
81293
  const shellCommand = isWindows ? "where claude" : "command -v claude";
81072
- const proc = spawn3(shellCommand, [], {
81294
+ const proc = spawn4(shellCommand, [], {
81073
81295
  stdio: "pipe",
81074
81296
  shell: true
81075
81297
  });
@@ -81142,18 +81364,18 @@ var init_claude_runner = __esm(() => {
81142
81364
  });
81143
81365
 
81144
81366
  // src/diag-output.ts
81145
- import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync23, unlinkSync as unlinkSync11, writeFileSync as writeFileSync26 } from "fs";
81367
+ import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync24, unlinkSync as unlinkSync11, writeFileSync as writeFileSync27 } from "fs";
81146
81368
  import { homedir as homedir36 } from "os";
81147
- import { join as join54 } from "path";
81369
+ import { join as join55 } from "path";
81148
81370
  function getClaudishDir() {
81149
- const dir = join54(homedir36(), ".claudish");
81371
+ const dir = join55(homedir36(), ".claudish");
81150
81372
  try {
81151
- mkdirSync23(dir, { recursive: true });
81373
+ mkdirSync24(dir, { recursive: true });
81152
81374
  } catch {}
81153
81375
  return dir;
81154
81376
  }
81155
81377
  function getDiagLogPath() {
81156
- return join54(getClaudishDir(), `diag-${process.pid}.log`);
81378
+ return join55(getClaudishDir(), `diag-${process.pid}.log`);
81157
81379
  }
81158
81380
 
81159
81381
  class LogFileDiagOutput {
@@ -81162,7 +81384,7 @@ class LogFileDiagOutput {
81162
81384
  constructor() {
81163
81385
  this.logPath = getDiagLogPath();
81164
81386
  try {
81165
- writeFileSync26(this.logPath, `--- claudish diag session ${new Date().toISOString()} ---
81387
+ writeFileSync27(this.logPath, `--- claudish diag session ${new Date().toISOString()} ---
81166
81388
  `);
81167
81389
  } catch {}
81168
81390
  this.stream = createWriteStream2(this.logPath, { flags: "a" });
@@ -81643,7 +81865,7 @@ var init_advisor_startup = __esm(() => {
81643
81865
  });
81644
81866
 
81645
81867
  // src/session/conversation.ts
81646
- import { closeSync as closeSync11, openSync as openSync11, readSync as readSync5, statSync as statSync14 } from "fs";
81868
+ import { closeSync as closeSync12, openSync as openSync12, readSync as readSync6, statSync as statSync14 } from "fs";
81647
81869
  import { StringDecoder } from "string_decoder";
81648
81870
  function looksLikeTurn(line) {
81649
81871
  const assistant = line.includes('"type":"assistant"');
@@ -81699,7 +81921,7 @@ function readConversation(file, opts = {}) {
81699
81921
  let fd = null;
81700
81922
  try {
81701
81923
  const size = statSync14(file).size;
81702
- fd = openSync11(file, "r");
81924
+ fd = openSync12(file, "r");
81703
81925
  const buf = Buffer.allocUnsafe(chunkBytes);
81704
81926
  const decoder = new StringDecoder("utf-8");
81705
81927
  let pending = "";
@@ -81731,7 +81953,7 @@ function readConversation(file, opts = {}) {
81731
81953
  take({ role: raw.role, text, elided });
81732
81954
  };
81733
81955
  while (pos < size) {
81734
- const n = readSync5(fd, buf, 0, Math.min(chunkBytes, size - pos), pos);
81956
+ const n = readSync6(fd, buf, 0, Math.min(chunkBytes, size - pos), pos);
81735
81957
  if (n <= 0)
81736
81958
  break;
81737
81959
  pos += n;
@@ -81755,7 +81977,7 @@ function readConversation(file, opts = {}) {
81755
81977
  } catch {} finally {
81756
81978
  if (fd !== null) {
81757
81979
  try {
81758
- closeSync11(fd);
81980
+ closeSync12(fd);
81759
81981
  } catch {}
81760
81982
  }
81761
81983
  }
@@ -83369,30 +83591,30 @@ function readSessionStats(port, opts) {
83369
83591
  return null;
83370
83592
  const d = raw;
83371
83593
  const processStartMs = opts?.processStartMs ?? Date.now() - Math.round(process.uptime() * 1000);
83372
- const trackerStartedAt = num(d.started_at);
83594
+ const trackerStartedAt = num2(d.started_at);
83373
83595
  if (trackerStartedAt <= 0 || trackerStartedAt < processStartMs)
83374
83596
  return null;
83375
- const inputTokens = num(d.input_tokens);
83376
- const outputTokens = num(d.output_tokens);
83597
+ const inputTokens = num2(d.input_tokens);
83598
+ const outputTokens = num2(d.output_tokens);
83377
83599
  if (inputTokens <= 0 && outputTokens <= 0)
83378
83600
  return null;
83379
- const costUsd = num(d.total_cost);
83601
+ const costUsd = num2(d.total_cost);
83380
83602
  const isFree = d.is_free === true;
83381
83603
  const contextWindow = typeof d.context_window === "number" ? d.context_window : null;
83382
83604
  const contextUsed = contextWindow && contextWindow > 0 ? Math.min(1, Math.max(0, inputTokens / contextWindow)) : null;
83383
- const toolCalls = Array.isArray(d.tool_calls) ? d.tool_calls.map((t) => t).filter((t) => typeof t?.name === "string" && num(t.count) > 0).map((t) => ({ name: String(t.name), count: num(t.count) })) : [];
83384
- const startedAt = num(d.started_at);
83385
- const updatedAt = num(d.updated_at);
83605
+ const toolCalls = Array.isArray(d.tool_calls) ? d.tool_calls.map((t) => t).filter((t) => typeof t?.name === "string" && num2(t.count) > 0).map((t) => ({ name: String(t.name), count: num2(t.count) })) : [];
83606
+ const startedAt = num2(d.started_at);
83607
+ const updatedAt = num2(d.updated_at);
83386
83608
  const durationMs = startedAt > 0 && updatedAt > startedAt ? updatedAt - startedAt : 0;
83387
- const billedInputTokens = num(d.billed_input_tokens) || inputTokens;
83388
- const rawIn = billedInputTokens / 1e6 * num(d.input_per_m);
83389
- const rawOut = outputTokens / 1e6 * num(d.output_per_m);
83609
+ const billedInputTokens = num2(d.billed_input_tokens) || inputTokens;
83610
+ const rawIn = billedInputTokens / 1e6 * num2(d.input_per_m);
83611
+ const rawOut = outputTokens / 1e6 * num2(d.output_per_m);
83390
83612
  const rawTotal = rawIn + rawOut;
83391
83613
  const scale = rawTotal > 0 && costUsd > 0 ? costUsd / rawTotal : 0;
83392
83614
  return {
83393
83615
  inputTokens,
83394
83616
  outputTokens,
83395
- totalTokens: num(d.total_tokens) || inputTokens + outputTokens,
83617
+ totalTokens: num2(d.total_tokens) || inputTokens + outputTokens,
83396
83618
  costUsd,
83397
83619
  isFree,
83398
83620
  isEstimated: d.is_estimated === true,
@@ -83420,7 +83642,7 @@ function computeSavings(inputTokens, outputTokens, actualUsd) {
83420
83642
  };
83421
83643
  });
83422
83644
  }
83423
- var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
83645
+ var num2 = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
83424
83646
  var init_session_stats = __esm(() => {
83425
83647
  init_baseline_pricing();
83426
83648
  init_token_file();
@@ -83722,7 +83944,7 @@ init_startup_trace();
83722
83944
  init_picker_cancelled();
83723
83945
  var import_dotenv3 = __toESM(require_main(), 1);
83724
83946
  import { existsSync as existsSync39, readFileSync as readFileSync38 } from "fs";
83725
- import { join as join55, resolve as resolve7 } from "path";
83947
+ import { join as join56, resolve as resolve7 } from "path";
83726
83948
 
83727
83949
  // src/tui/runtime/should-open-picker.ts
83728
83950
  function noModelConfigured(gate) {
@@ -84030,7 +84252,7 @@ async function runCli() {
84030
84252
  process.exit(1);
84031
84253
  }
84032
84254
  const mode = cliConfig.teamMode ?? "default";
84033
- const sessionPath = join55(process.cwd(), `.claudish-team-${Date.now()}`);
84255
+ const sessionPath = join56(process.cwd(), `.claudish-team-${Date.now()}`);
84034
84256
  if (mode === "json") {
84035
84257
  await Promise.resolve().then(() => init_pane());
84036
84258
  await Promise.resolve().then(() => init_team_orchestrator());
@@ -84050,7 +84272,7 @@ async function runCli() {
84050
84272
  const status = await runModels(sessionPath);
84051
84273
  const result = { ...status, responses: {} };
84052
84274
  for (const anonId of Object.keys(status.models)) {
84053
- const responsePath = join55(sessionPath, `response-${anonId}.md`);
84275
+ const responsePath = join56(sessionPath, `response-${anonId}.md`);
84054
84276
  try {
84055
84277
  const raw = readFileSync38(responsePath, "utf-8").trim();
84056
84278
  try {