claudish 13.3.0 → 13.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +277 -161
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -575,7 +575,7 @@ var init_onepassword_config = __esm(() => {
575
575
  });
576
576
 
577
577
  // src/version.ts
578
- var VERSION = "13.3.0";
578
+ var VERSION = "13.4.0";
579
579
 
580
580
  // src/logger.ts
581
581
  import { appendFile, existsSync as existsSync2, mkdirSync, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
@@ -76472,23 +76472,122 @@ var init_team_orchestrator = __esm(() => {
76472
76472
  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.";
76473
76473
  });
76474
76474
 
76475
+ // src/mcp-session/inherited-settings.ts
76476
+ import { existsSync as existsSync34, readFileSync as readFileSync33, statSync as statSync13 } from "fs";
76477
+ import { join as join51, resolve as resolve6 } from "path";
76478
+ function isPlainObject6(value) {
76479
+ return typeof value === "object" && value !== null && !Array.isArray(value);
76480
+ }
76481
+ function uniqueByJson(values) {
76482
+ const seen = new Set;
76483
+ return values.filter((value) => {
76484
+ const key = JSON.stringify(value);
76485
+ if (seen.has(key))
76486
+ return false;
76487
+ seen.add(key);
76488
+ return true;
76489
+ });
76490
+ }
76491
+ function mergeSettingsLayers(base, over) {
76492
+ const merged = structuredClone(base);
76493
+ for (const [key, value] of Object.entries(over)) {
76494
+ const current = merged[key];
76495
+ if (isPlainObject6(current) && isPlainObject6(value)) {
76496
+ merged[key] = mergeSettingsLayers(current, value);
76497
+ } else if (Array.isArray(current) && Array.isArray(value)) {
76498
+ merged[key] = uniqueByJson([...current, ...structuredClone(value)]);
76499
+ } else {
76500
+ merged[key] = structuredClone(value);
76501
+ }
76502
+ }
76503
+ return merged;
76504
+ }
76505
+ function parseLayer(text, source) {
76506
+ let parsed;
76507
+ try {
76508
+ parsed = JSON.parse(text);
76509
+ } catch (err) {
76510
+ throw new Error(`invalid_args: settings ${source} is not valid JSON (${err.message})`);
76511
+ }
76512
+ if (!isPlainObject6(parsed)) {
76513
+ throw new Error(`invalid_args: settings ${source} is not a JSON object`);
76514
+ }
76515
+ return parsed;
76516
+ }
76517
+ function readSettingsValue(value) {
76518
+ if (value.trim().startsWith("{"))
76519
+ return parseLayer(value, value);
76520
+ let text;
76521
+ try {
76522
+ text = readFileSync33(value, "utf-8");
76523
+ } catch (err) {
76524
+ throw new Error(`invalid_args: settings ${value} cannot be read (${err.message})`);
76525
+ }
76526
+ return parseLayer(text, value);
76527
+ }
76528
+ function buildInheritedSettingsLayer(setupFrom, callerFlags) {
76529
+ const layers = [];
76530
+ for (const name of ["settings.json", "settings.local.json"]) {
76531
+ const file = join51(setupFrom, ".claude", name);
76532
+ if (!existsSync34(file))
76533
+ continue;
76534
+ layers.push(parseLayer(readFileSync33(file, "utf-8"), file));
76535
+ }
76536
+ const restFlags = [];
76537
+ for (let i = 0;i < callerFlags.length; i++) {
76538
+ const flag = callerFlags[i];
76539
+ if (flag === "--settings") {
76540
+ const value = callerFlags[i + 1];
76541
+ if (value === undefined)
76542
+ throw new Error("invalid_args: --settings needs a value");
76543
+ layers.push(readSettingsValue(value));
76544
+ i++;
76545
+ } else if (flag.startsWith("--settings=")) {
76546
+ layers.push(readSettingsValue(flag.slice("--settings=".length)));
76547
+ } else {
76548
+ restFlags.push(flag);
76549
+ }
76550
+ }
76551
+ if (layers.length === 0)
76552
+ return { layer: null, restFlags };
76553
+ const layer = layers.reduce((acc, next) => mergeSettingsLayers(acc, next), {});
76554
+ if (isPlainObject6(layer.permissions))
76555
+ delete layer.permissions.additionalDirectories;
76556
+ return { layer, restFlags };
76557
+ }
76558
+ function resolveSetupFrom(arg, workDir, serverCwd) {
76559
+ if (arg === null)
76560
+ return;
76561
+ let setupFrom = serverCwd;
76562
+ if (typeof arg === "string") {
76563
+ setupFrom = resolve6(arg);
76564
+ if (!statSync13(setupFrom, { throwIfNoEntry: false })?.isDirectory()) {
76565
+ throw new Error(`invalid_args: setup_from ${setupFrom} is not an existing directory`);
76566
+ }
76567
+ } else if (arg !== undefined) {
76568
+ throw new Error("invalid_args: setup_from must be a directory path or null");
76569
+ }
76570
+ return setupFrom === resolve6(workDir ?? serverCwd) ? undefined : setupFrom;
76571
+ }
76572
+ var init_inherited_settings = () => {};
76573
+
76475
76574
  // src/mcp-session/session-manager.ts
76476
76575
  import { randomUUID as randomUUID7 } from "crypto";
76477
76576
  import {
76478
76577
  appendFileSync as appendFileSync7,
76479
76578
  closeSync as closeSync11,
76480
76579
  createWriteStream,
76481
- existsSync as existsSync34,
76580
+ existsSync as existsSync35,
76482
76581
  mkdirSync as mkdirSync22,
76483
76582
  openSync as openSync11,
76484
- readFileSync as readFileSync33,
76583
+ readFileSync as readFileSync34,
76485
76584
  readSync as readSync6,
76486
76585
  renameSync as renameSync5,
76487
76586
  rmSync as rmSync9,
76488
- statSync as statSync13,
76587
+ statSync as statSync14,
76489
76588
  writeFileSync as writeFileSync23
76490
76589
  } from "fs";
76491
- import { join as join51, resolve as resolve6, sep as sep2 } from "path";
76590
+ import { join as join52, resolve as resolve7, sep as sep2 } from "path";
76492
76591
  function normaliseTimeoutSeconds(raw) {
76493
76592
  const n = typeof raw === "string" && raw.trim() !== "" ? Number(raw) : raw;
76494
76593
  if (typeof n !== "number" || !Number.isFinite(n))
@@ -76588,7 +76687,7 @@ function anomalyKey(a) {
76588
76687
  function readTailText(path, maxBytes) {
76589
76688
  let fd = null;
76590
76689
  try {
76591
- const size = statSync13(path).size;
76690
+ const size = statSync14(path).size;
76592
76691
  if (size === 0)
76593
76692
  return { text: "", truncated: false };
76594
76693
  const start = Math.max(0, size - maxBytes);
@@ -76619,7 +76718,7 @@ function readTailLines2(path, maxBytes) {
76619
76718
  }
76620
76719
  function fileSize2(path) {
76621
76720
  try {
76622
- return statSync13(path).size;
76721
+ return statSync14(path).size;
76623
76722
  } catch {
76624
76723
  return 0;
76625
76724
  }
@@ -76628,7 +76727,7 @@ function readJsonObject(path, maxBytes) {
76628
76727
  try {
76629
76728
  if (fileSize2(path) > maxBytes)
76630
76729
  return null;
76631
- const parsed = JSON.parse(readFileSync33(path, "utf-8"));
76730
+ const parsed = JSON.parse(readFileSync34(path, "utf-8"));
76632
76731
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
76633
76732
  return null;
76634
76733
  return parsed;
@@ -76654,7 +76753,7 @@ function dropLeadingFragment(tail) {
76654
76753
  return firstBreak === -1 ? tail.text : tail.text.slice(firstBreak + 1);
76655
76754
  }
76656
76755
  function diskAccounting(sessionDir) {
76657
- const stats = readTokenStatsAt(join51(sessionDir, "tokens.json"));
76756
+ const stats = readTokenStatsAt(join52(sessionDir, "tokens.json"));
76658
76757
  return {
76659
76758
  tokensIn: stats?.billed_input_tokens ?? null,
76660
76759
  tokensOut: stats?.output_tokens ?? null,
@@ -76737,7 +76836,7 @@ class SessionManager {
76737
76836
  let dir = "";
76738
76837
  for (let attempt = 0;; attempt++) {
76739
76838
  id = `team-${randomUUID7().replace(/-/g, "").slice(0, 8)}`;
76740
- dir = join51(this.sessionsDir, id);
76839
+ dir = join52(this.sessionsDir, id);
76741
76840
  try {
76742
76841
  mkdirSync22(dir);
76743
76842
  break;
@@ -76752,7 +76851,7 @@ class SessionManager {
76752
76851
  sessionId: id,
76753
76852
  parentClaudeSessionId: opts.parentClaudeSessionId,
76754
76853
  startedAt,
76755
- teamPath: resolve6(opts.teamPath),
76854
+ teamPath: resolve7(opts.teamPath),
76756
76855
  slots: opts.slots
76757
76856
  });
76758
76857
  this.teamRunStarts.set(id, startedAt);
@@ -76769,9 +76868,9 @@ class SessionManager {
76769
76868
  if (dir === null)
76770
76869
  throw new Error("not a record id");
76771
76870
  const completedAt = new Date().toISOString();
76772
- const startedAt = this.teamRunStarts.get(record) ?? metaString(readJsonObject(join51(dir, "spawn.json"), META_READ_LIMIT)?.startedAt) ?? completedAt;
76871
+ const startedAt = this.teamRunStarts.get(record) ?? metaString(readJsonObject(join52(dir, "spawn.json"), META_READ_LIMIT)?.startedAt) ?? completedAt;
76773
76872
  const elapsedMs = Date.parse(completedAt) - Date.parse(startedAt);
76774
- writeJsonAtomic(join51(dir, "meta.json"), {
76873
+ writeJsonAtomic(join52(dir, "meta.json"), {
76775
76874
  kind: "team",
76776
76875
  status: outcome.status,
76777
76876
  startedAt,
@@ -76803,7 +76902,7 @@ class SessionManager {
76803
76902
  startedAt,
76804
76903
  ...rest
76805
76904
  };
76806
- writeJsonAtomic(join51(dir, "spawn.json"), body);
76905
+ writeJsonAtomic(join52(dir, "spawn.json"), body);
76807
76906
  }
76808
76907
  async createSession(opts) {
76809
76908
  if (this.activeSessions + this.starting >= this.maxSessions) {
@@ -76812,10 +76911,12 @@ class SessionManager {
76812
76911
  if (opts.sessionId !== undefined && this.sessions.has(opts.sessionId)) {
76813
76912
  throw new Error(`Session id already in use: ${opts.sessionId}`);
76814
76913
  }
76815
- const flags = opts.claudishFlags ?? [];
76816
- const flagCheck = checkChildFlags(flags);
76914
+ const callerFlags = opts.claudishFlags ?? [];
76915
+ const flagCheck = checkChildFlags(callerFlags);
76817
76916
  if (!flagCheck.ok)
76818
76917
  throw new Error(`invalid_args: ${flagCheck.message}`);
76918
+ const inherited = opts.setupFrom ? buildInheritedSettingsLayer(opts.setupFrom, callerFlags) : { layer: null, restFlags: callerFlags };
76919
+ let flags = callerFlags;
76819
76920
  const readAvailable = !flagsRemoveRead(flags);
76820
76921
  if (opts.prompt) {
76821
76922
  const refusal = deliveryRefusal(opts.prompt, readAvailable);
@@ -76835,11 +76936,14 @@ class SessionManager {
76835
76936
  reservePanes(1, sockRootFor(parentEnv));
76836
76937
  let entry;
76837
76938
  try {
76838
- entry = this.recordSession(opts);
76939
+ entry = this.recordSession(opts, inherited.layer);
76839
76940
  } catch (err) {
76840
76941
  releasePaneReservations(1);
76841
76942
  throw err;
76842
76943
  }
76944
+ if (inherited.layer) {
76945
+ flags = [...inherited.restFlags, "--settings", join52(entry.sessionDir, INHERITED_SETTINGS)];
76946
+ }
76843
76947
  this.sessions.set(entry.info.sessionId, entry);
76844
76948
  uncount();
76845
76949
  const started = this.startPane(entry, opts, { flags, readAvailable, parentEnv });
@@ -76857,15 +76961,15 @@ class SessionManager {
76857
76961
  uncount();
76858
76962
  }
76859
76963
  }
76860
- recordSession(opts) {
76964
+ recordSession(opts, inheritedLayer) {
76861
76965
  const sessionId = opts.sessionId ?? randomUUID7().slice(0, 8);
76862
76966
  const claudeSessionId = randomUUID7();
76863
76967
  const timeout = normaliseTimeoutSeconds(opts.timeoutSeconds);
76864
76968
  const startedAt = new Date().toISOString();
76865
- const sessionDir = opts.sessionDir ?? join51(this.sessionsDir, sessionId);
76969
+ const sessionDir = opts.sessionDir ?? join52(this.sessionsDir, sessionId);
76866
76970
  mkdirSync22(sessionDir, { recursive: true });
76867
76971
  if (opts.prompt)
76868
- writeFileSync23(join51(sessionDir, "prompt.md"), opts.prompt, "utf-8");
76972
+ writeFileSync23(join52(sessionDir, "prompt.md"), opts.prompt, "utf-8");
76869
76973
  this.writeSpawnRecord(sessionDir, {
76870
76974
  kind: "session",
76871
76975
  sessionId,
@@ -76873,12 +76977,17 @@ class SessionManager {
76873
76977
  startedAt,
76874
76978
  model: opts.model,
76875
76979
  timeoutSeconds: timeout,
76876
- claudeSessionId
76980
+ claudeSessionId,
76981
+ ...opts.setupFrom ? { setupFrom: opts.setupFrom } : {}
76877
76982
  });
76983
+ if (inheritedLayer) {
76984
+ writeFileSync23(join52(sessionDir, INHERITED_SETTINGS), `${JSON.stringify(inheritedLayer, null, 2)}
76985
+ `, { encoding: "utf-8", mode: 384 });
76986
+ }
76878
76987
  const cwd = opts.cwd ?? process.cwd();
76879
76988
  const parentEnv = opts.parentEnv ?? this.parentEnv;
76880
76989
  const spawnModel = opts.spawnModel ?? null;
76881
- const tokenFile = opts.tokenFile ?? join51(sessionDir, "tokens.json");
76990
+ const tokenFile = opts.tokenFile ?? join52(sessionDir, "tokens.json");
76882
76991
  return {
76883
76992
  info: {
76884
76993
  sessionId,
@@ -76914,18 +77023,18 @@ class SessionManager {
76914
77023
  },
76915
77024
  session: null,
76916
77025
  scrollback: new ScrollbackBuffer(this.scrollbackCapacity),
76917
- outputLogStream: createWriteStream(join51(sessionDir, "output.log")),
77026
+ outputLogStream: createWriteStream(join52(sessionDir, "output.log")),
76918
77027
  sessionDir,
76919
77028
  cwd,
76920
77029
  tokenFile,
76921
- eventLogPath: join51(sessionDir, "events.jsonl"),
77030
+ eventLogPath: join52(sessionDir, "events.jsonl"),
76922
77031
  eventLogBytes: 0,
76923
- upstreamErrorLogPath: join51(sessionDir, "upstream-errors.jsonl"),
77032
+ upstreamErrorLogPath: join52(sessionDir, "upstream-errors.jsonl"),
76924
77033
  eventRing: [],
76925
77034
  proseBytes: 0,
76926
77035
  answeredTurns: new Map,
76927
77036
  inboxPath: null,
76928
- waitLogPath: join51(sessionDir, "waits.jsonl"),
77037
+ waitLogPath: join52(sessionDir, "waits.jsonl"),
76929
77038
  waitLogBytes: 0,
76930
77039
  waitSince: null,
76931
77040
  ended: false,
@@ -77114,7 +77223,7 @@ class SessionManager {
77114
77223
  try {
77115
77224
  const text = screenLines.join(`
77116
77225
  `).replace(/\s+$/, "");
77117
- writeFileSync23(join51(entry.sessionDir, "screen.txt"), `${redactSecrets2(text)}
77226
+ writeFileSync23(join52(entry.sessionDir, "screen.txt"), `${redactSecrets2(text)}
77118
77227
  `, "utf-8");
77119
77228
  } catch {}
77120
77229
  }
@@ -77128,7 +77237,7 @@ class SessionManager {
77128
77237
  entry.waitSince = null;
77129
77238
  }
77130
77239
  try {
77131
- writeJsonAtomic(join51(entry.sessionDir, "meta.json"), toMetaRecord(entry.info, entry.cwd));
77240
+ writeJsonAtomic(join52(entry.sessionDir, "meta.json"), toMetaRecord(entry.info, entry.cwd));
77132
77241
  } catch (err) {
77133
77242
  process.stderr.write(`[claudish] session ${entry.info.sessionId}: could not write meta.json: ` + `${err instanceof Error ? err.message : String(err)}
77134
77243
  `);
@@ -77387,9 +77496,9 @@ class SessionManager {
77387
77496
  diskSessionDir(sessionId) {
77388
77497
  if (!SESSION_ID_RE.test(sessionId))
77389
77498
  return null;
77390
- const root = resolve6(this.sessionsDir);
77391
- const dir = resolve6(root, sessionId);
77392
- if (dir !== join51(root, sessionId))
77499
+ const root = resolve7(this.sessionsDir);
77500
+ const dir = resolve7(root, sessionId);
77501
+ if (dir !== join52(root, sessionId))
77393
77502
  return null;
77394
77503
  if (!dir.startsWith(root + sep2))
77395
77504
  return null;
@@ -77401,17 +77510,17 @@ class SessionManager {
77401
77510
  return null;
77402
77511
  let dirMtimeMs;
77403
77512
  try {
77404
- const stat = statSync13(sessionDir);
77513
+ const stat = statSync14(sessionDir);
77405
77514
  if (!stat.isDirectory())
77406
77515
  return null;
77407
77516
  dirMtimeMs = stat.mtimeMs;
77408
77517
  } catch {
77409
77518
  return null;
77410
77519
  }
77411
- const spawnRecord = readJsonObject(join51(sessionDir, "spawn.json"), META_READ_LIMIT);
77520
+ const spawnRecord = readJsonObject(join52(sessionDir, "spawn.json"), META_READ_LIMIT);
77412
77521
  if (spawnRecord?.kind === "team")
77413
77522
  return null;
77414
- const meta = readJsonObject(join51(sessionDir, "meta.json"), META_READ_LIMIT);
77523
+ const meta = readJsonObject(join52(sessionDir, "meta.json"), META_READ_LIMIT);
77415
77524
  if (meta?.kind === "team")
77416
77525
  return null;
77417
77526
  const partial = meta === null;
@@ -77426,14 +77535,14 @@ class SessionManager {
77426
77535
  diskTranscriptPath(meta, uuid) {
77427
77536
  const stored = metaString(meta?.transcriptPath) ?? "";
77428
77537
  const cwd = metaString(meta?.cwd);
77429
- if (stored && existsSync34(stored))
77538
+ if (stored && existsSync35(stored))
77430
77539
  return stored;
77431
77540
  if (cwd && uuid)
77432
77541
  return transcriptPathFor(cwd, uuid, projectsDir(this.parentEnv));
77433
77542
  return stored;
77434
77543
  }
77435
77544
  diskOutput(record, tailLines) {
77436
- const tail = readTailText(join51(record.sessionDir, "output.log"), OUTPUT_TAIL_BYTES);
77545
+ const tail = readTailText(join52(record.sessionDir, "output.log"), OUTPUT_TAIL_BYTES);
77437
77546
  const buffer = new ScrollbackBuffer(this.scrollbackCapacity);
77438
77547
  if (tail?.text)
77439
77548
  buffer.append(dropLeadingFragment(tail));
@@ -77453,12 +77562,12 @@ class SessionManager {
77453
77562
  }
77454
77563
  diskDiagnostics(record, limit) {
77455
77564
  const { sessionDir, info } = record;
77456
- const eventLogPath = join51(sessionDir, "events.jsonl");
77457
- const upstreamErrorLogPath = join51(sessionDir, "upstream-errors.jsonl");
77458
- const outputLogPath = join51(sessionDir, "output.log");
77565
+ const eventLogPath = join52(sessionDir, "events.jsonl");
77566
+ const upstreamErrorLogPath = join52(sessionDir, "upstream-errors.jsonl");
77567
+ const outputLogPath = join52(sessionDir, "output.log");
77459
77568
  const events = readTailLines2(eventLogPath, EVENT_TAIL_BYTES);
77460
77569
  const outputTail = readTailText(outputLogPath, OUTPUT_TAIL_BYTES);
77461
- const screen = readTailText(join51(sessionDir, "screen.txt"), SCREEN_READ_BYTES);
77570
+ const screen = readTailText(join52(sessionDir, "screen.txt"), SCREEN_READ_BYTES);
77462
77571
  return {
77463
77572
  sessionId: info.sessionId,
77464
77573
  state: info.state,
@@ -77695,7 +77804,7 @@ function diskInfo(d) {
77695
77804
  function diskCaptureSource(v) {
77696
77805
  return v === "transcript" || v === "screen" || v === "none" ? v : null;
77697
77806
  }
77698
- var DEFAULT_MAX_SESSIONS = 20, DEFAULT_SCROLLBACK = 2000, DEFAULT_TIMEOUT = 600, MAX_TIMEOUT = 3600, TERMINAL_RETENTION_MS, MAX_TERMINAL_SESSIONS = 50, EVENT_LOG_LIMIT, WAIT_LOG_LIMIT, EVENT_RING_SIZE = 200, EVENT_PREVIEW_CHARS = 800, DEFAULT_EVENT_LIMIT = 40, UPSTREAM_ERROR_TAIL_BYTES, SPAWN_RECORD_SCHEMA = 1, NON_TOOL_ACTIVITY, META_STATUS, STATE_OF_10_4_STATUS, SESSION_ID_RE, META_READ_LIMIT, OUTPUT_TAIL_BYTES, EVENT_TAIL_BYTES, SCREEN_READ_BYTES, NO_TERMINAL_RECORD = "claudish_no_terminal_record", CLAUDISH_NOTE_PREFIX = "[claudish] ", metaString = (v) => typeof v === "string" && v.length > 0 ? v : null, optionalParent = (id) => id ? { parentClaudeSessionId: id } : {}, metaNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : null, metaReason = (v) => typeof v === "string" && FAILURE_REASONS.includes(v) ? v : null;
77807
+ var DEFAULT_MAX_SESSIONS = 20, DEFAULT_SCROLLBACK = 2000, DEFAULT_TIMEOUT = 600, MAX_TIMEOUT = 3600, TERMINAL_RETENTION_MS, MAX_TERMINAL_SESSIONS = 50, EVENT_LOG_LIMIT, WAIT_LOG_LIMIT, EVENT_RING_SIZE = 200, EVENT_PREVIEW_CHARS = 800, DEFAULT_EVENT_LIMIT = 40, UPSTREAM_ERROR_TAIL_BYTES, SPAWN_RECORD_SCHEMA = 1, INHERITED_SETTINGS = "inherited-settings.json", NON_TOOL_ACTIVITY, META_STATUS, STATE_OF_10_4_STATUS, SESSION_ID_RE, META_READ_LIMIT, OUTPUT_TAIL_BYTES, EVENT_TAIL_BYTES, SCREEN_READ_BYTES, NO_TERMINAL_RECORD = "claudish_no_terminal_record", CLAUDISH_NOTE_PREFIX = "[claudish] ", metaString = (v) => typeof v === "string" && v.length > 0 ? v : null, optionalParent = (id) => id ? { parentClaudeSessionId: id } : {}, metaNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : null, metaReason = (v) => typeof v === "string" && FAILURE_REASONS.includes(v) ? v : null;
77699
77808
  var init_session_manager = __esm(() => {
77700
77809
  init_config();
77701
77810
  init_upstream_error_capture();
@@ -77710,6 +77819,7 @@ var init_session_manager = __esm(() => {
77710
77819
  init_team_orchestrator();
77711
77820
  init_team_stats();
77712
77821
  init_home_dir();
77822
+ init_inherited_settings();
77713
77823
  init_parent_session();
77714
77824
  init_scrollback_buffer();
77715
77825
  TERMINAL_RETENTION_MS = 30 * 60000;
@@ -77854,7 +77964,7 @@ var init_progress_heartbeat = __esm(() => {
77854
77964
  import { spawn as spawn2 } from "child_process";
77855
77965
  import { mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync3, rmSync as rmSync10, writeFileSync as writeFileSync24 } from "fs";
77856
77966
  import { tmpdir as tmpdir2 } from "os";
77857
- import { join as join52 } from "path";
77967
+ import { join as join53 } from "path";
77858
77968
  function claudeCodePrintArgv(model, systemPromptFile) {
77859
77969
  const head = [PRINT_FLAGS[0], "--model", model, ...PRINT_FLAGS.slice(1)];
77860
77970
  return systemPromptFile !== undefined ? [...head, "--system-prompt-file", systemPromptFile] : [...head, "--system-prompt", ""];
@@ -77972,13 +78082,13 @@ async function runPromptViaClaudeCode(model, prompt, systemPrompt, opts = {}) {
77972
78082
  } catch (e) {
77973
78083
  throw new Error(`cannot start claudish (${parentEnv.CLAUDISH_BIN?.trim() || "claudish"}): ${e instanceof Error ? e.message : String(e)}`);
77974
78084
  }
77975
- const root = mkdtempSync3(join52(tmpdir2(), "claudish-run-prompt-"));
78085
+ const root = mkdtempSync3(join53(tmpdir2(), "claudish-run-prompt-"));
77976
78086
  try {
77977
- const cwd = join52(root, "cwd");
78087
+ const cwd = join53(root, "cwd");
77978
78088
  mkdirSync23(cwd, { mode: 448 });
77979
78089
  let systemPromptFile;
77980
78090
  if (typeof systemPrompt === "string" && systemPrompt.length > 0) {
77981
- systemPromptFile = join52(root, "system-prompt.txt");
78091
+ systemPromptFile = join53(root, "system-prompt.txt");
77982
78092
  writeFileSync24(systemPromptFile, systemPrompt, { mode: 384 });
77983
78093
  }
77984
78094
  const argv = claudeCodePrintArgv(model, systemPromptFile);
@@ -78084,14 +78194,14 @@ var init_run_prompt_claude_code = __esm(() => {
78084
78194
  });
78085
78195
 
78086
78196
  // src/mcp-server.ts
78087
- import { existsSync as existsSync35, mkdirSync as mkdirSync24, readFileSync as readFileSync34, readdirSync as readdirSync9, writeFileSync as writeFileSync25 } from "fs";
78197
+ import { existsSync as existsSync36, mkdirSync as mkdirSync24, readFileSync as readFileSync35, readdirSync as readdirSync9, writeFileSync as writeFileSync25 } from "fs";
78088
78198
  import { homedir as homedir35 } from "os";
78089
- import { dirname as dirname17, join as join53, resolve as resolve7 } from "path";
78199
+ import { dirname as dirname17, join as join54, resolve as resolve8 } from "path";
78090
78200
  import { fileURLToPath as fileURLToPath3 } from "url";
78091
78201
  async function loadAllModels(forceRefresh = false) {
78092
- if (!forceRefresh && existsSync35(OPENROUTER_MODELS_CACHE_PATH)) {
78202
+ if (!forceRefresh && existsSync36(OPENROUTER_MODELS_CACHE_PATH)) {
78093
78203
  try {
78094
- const cacheData = JSON.parse(readFileSync34(OPENROUTER_MODELS_CACHE_PATH, "utf-8"));
78204
+ const cacheData = JSON.parse(readFileSync35(OPENROUTER_MODELS_CACHE_PATH, "utf-8"));
78095
78205
  const lastUpdated = new Date(cacheData.lastUpdated);
78096
78206
  const ageInDays = (Date.now() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
78097
78207
  if (ageInDays <= CACHE_MAX_AGE_DAYS) {
@@ -78109,8 +78219,8 @@ async function loadAllModels(forceRefresh = false) {
78109
78219
  writeFileSync25(OPENROUTER_MODELS_CACHE_PATH, JSON.stringify({ lastUpdated: new Date().toISOString(), models }), "utf-8");
78110
78220
  return models;
78111
78221
  } catch {
78112
- if (existsSync35(OPENROUTER_MODELS_CACHE_PATH)) {
78113
- const cacheData = JSON.parse(readFileSync34(OPENROUTER_MODELS_CACHE_PATH, "utf-8"));
78222
+ if (existsSync36(OPENROUTER_MODELS_CACHE_PATH)) {
78223
+ const cacheData = JSON.parse(readFileSync35(OPENROUTER_MODELS_CACHE_PATH, "utf-8"));
78114
78224
  return cacheData.models || [];
78115
78225
  }
78116
78226
  return [];
@@ -78926,8 +79036,8 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
78926
79036
  const promptText = () => {
78927
79037
  if (input !== undefined)
78928
79038
  return input;
78929
- const existing = join53(resolved, "input.md");
78930
- return existsSync35(existing) ? readFileSync34(existing, "utf-8") : undefined;
79039
+ const existing = join54(resolved, "input.md");
79040
+ return existsSync36(existing) ? readFileSync35(existing, "utf-8") : undefined;
78931
79041
  };
78932
79042
  switch (mode) {
78933
79043
  case "run": {
@@ -79077,7 +79187,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
79077
79187
  let stderrFull = stderr_snippet || "";
79078
79188
  if (error_log_path) {
79079
79189
  try {
79080
- stderrFull = readFileSync34(error_log_path, "utf-8");
79190
+ stderrFull = readFileSync35(error_log_path, "utf-8");
79081
79191
  } catch {}
79082
79192
  }
79083
79193
  const sessionData = {};
@@ -79085,16 +79195,16 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
79085
79195
  const sp = session_path;
79086
79196
  for (const file of ["status.json", "manifest.json", "input.md"]) {
79087
79197
  try {
79088
- sessionData[file] = readFileSync34(join53(sp, file), "utf-8");
79198
+ sessionData[file] = readFileSync35(join54(sp, file), "utf-8");
79089
79199
  } catch {}
79090
79200
  }
79091
79201
  try {
79092
- const errorDir = join53(sp, "errors");
79093
- if (existsSync35(errorDir)) {
79202
+ const errorDir = join54(sp, "errors");
79203
+ if (existsSync36(errorDir)) {
79094
79204
  for (const f of readdirSync9(errorDir)) {
79095
79205
  if (f.endsWith(".log")) {
79096
79206
  try {
79097
- sessionData[`errors/${f}`] = readFileSync34(join53(errorDir, f), "utf-8");
79207
+ sessionData[`errors/${f}`] = readFileSync35(join54(errorDir, f), "utf-8");
79098
79208
  } catch {}
79099
79209
  }
79100
79210
  }
@@ -79104,7 +79214,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
79104
79214
  for (const f of readdirSync9(sp)) {
79105
79215
  if (f.startsWith("response-") && f.endsWith(".md")) {
79106
79216
  try {
79107
- const content = readFileSync34(join53(sp, f), "utf-8");
79217
+ const content = readFileSync35(join54(sp, f), "utf-8");
79108
79218
  sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
79109
79219
  } catch {}
79110
79220
  }
@@ -79113,9 +79223,9 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
79113
79223
  }
79114
79224
  let version = "unknown";
79115
79225
  try {
79116
- const pkgPath = join53(__dirname3, "../package.json");
79117
- if (existsSync35(pkgPath)) {
79118
- version = JSON.parse(readFileSync34(pkgPath, "utf-8")).version;
79226
+ const pkgPath = join54(__dirname3, "../package.json");
79227
+ if (existsSync36(pkgPath)) {
79228
+ version = JSON.parse(readFileSync35(pkgPath, "utf-8")).version;
79119
79229
  }
79120
79230
  } catch {}
79121
79231
  const report = {
@@ -79222,6 +79332,10 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
79222
79332
  work_dir: {
79223
79333
  type: "string",
79224
79334
  description: "Working directory for the session (default: current directory)"
79335
+ },
79336
+ setup_from: {
79337
+ type: ["string", "null"],
79338
+ description: "Directory whose .claude/settings.json and settings.local.json the session " + "inherits (enabled plugins, permissions, env), so a session in another work_dir " + "keeps the caller's plugins and agents; an explicit path must be an existing " + "directory. Default: the caller's project directory, " + "when work_dir differs from it. null keeps the session on work_dir's own settings only."
79225
79339
  }
79226
79340
  },
79227
79341
  required: ["model"]
@@ -79237,7 +79351,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
79237
79351
  const requestedModel = args.model;
79238
79352
  const workDir = args.work_dir;
79239
79353
  const plan = await prehydrateCredentialsForSpawn([requestedModel], {
79240
- pin: workDir === undefined || resolve7(workDir) === process.cwd()
79354
+ pin: workDir === undefined || resolve8(workDir) === process.cwd()
79241
79355
  });
79242
79356
  const parentClaudeSessionId = await parentSessionForCall({
79243
79357
  hostPid: sessionManager.hostPid
@@ -79249,6 +79363,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
79249
79363
  timeoutSeconds: args.timeout_seconds,
79250
79364
  claudishFlags,
79251
79365
  cwd: workDir,
79366
+ setupFrom: resolveSetupFrom(args.setup_from, workDir, process.cwd()),
79252
79367
  parentClaudeSessionId
79253
79368
  });
79254
79369
  return {
@@ -79638,6 +79753,7 @@ var init_mcp_server = __esm(() => {
79638
79753
  init_output_capture();
79639
79754
  init_logger();
79640
79755
  init_mcp_session();
79756
+ init_inherited_settings();
79641
79757
  init_parent_session();
79642
79758
  init_nested_mode();
79643
79759
  init_progress_heartbeat();
@@ -79658,8 +79774,8 @@ var init_mcp_server = __esm(() => {
79658
79774
  init_team_orchestrator();
79659
79775
  __filename3 = fileURLToPath3(import.meta.url);
79660
79776
  __dirname3 = dirname17(__filename3);
79661
- CLAUDISH_CACHE_DIR = join53(homedir35(), ".claudish");
79662
- OPENROUTER_MODELS_CACHE_PATH = join53(CLAUDISH_CACHE_DIR, "openrouter-models.json");
79777
+ CLAUDISH_CACHE_DIR = join54(homedir35(), ".claudish");
79778
+ OPENROUTER_MODELS_CACHE_PATH = join54(CLAUDISH_CACHE_DIR, "openrouter-models.json");
79663
79779
  NEXT_STEP = {
79664
79780
  cancelled: "you stopped this slot; nothing is wrong with it. Re-run it if you still want its vote",
79665
79781
  timeout: "grid mode only \u2014 magmux ended the pane. The orchestrator has no deadline",
@@ -79682,7 +79798,7 @@ var init_mcp_server = __esm(() => {
79682
79798
  });
79683
79799
 
79684
79800
  // src/serve-command.ts
79685
- import { existsSync as existsSync36, readFileSync as readFileSync35 } from "fs";
79801
+ import { existsSync as existsSync37, readFileSync as readFileSync36 } from "fs";
79686
79802
  function parseServeArgs(args) {
79687
79803
  const out = {};
79688
79804
  for (let i = 0;i < args.length; i++) {
@@ -79701,12 +79817,12 @@ function parseServeArgs(args) {
79701
79817
  return out;
79702
79818
  }
79703
79819
  function loadModelMap(path) {
79704
- if (!existsSync36(path)) {
79820
+ if (!existsSync37(path)) {
79705
79821
  throw new Error(`--models file not found: ${path}`);
79706
79822
  }
79707
79823
  let raw;
79708
79824
  try {
79709
- raw = readFileSync35(path, "utf-8");
79825
+ raw = readFileSync36(path, "utf-8");
79710
79826
  } catch (e) {
79711
79827
  throw new Error(`failed to read --models file ${path}: ${e instanceof Error ? e.message : String(e)}`);
79712
79828
  }
@@ -79787,9 +79903,9 @@ var init_serve_command = __esm(() => {
79787
79903
  var HOOKS_AMBIENT_DTS = '// claudish hook types \u2014 written by `claudish hooks init`. Do not edit: run\n// `claudish hooks init` from a newer claudish to refresh it.\n// With this file beside your hook, `import type { HookDefinition } from\n// "claudish/hooks"` type-checks with nothing installed.\ndeclare module "claudish/hooks" {\n /**\n * claudish/hooks \u2014 the public hook contract.\n *\n * Everything a hook author can import lives here, and nothing else does. This\n * file imports nothing from the rest of claudish and has no side effects, so it\n * can be built on its own into `dist/hooks.js` + `dist/hooks.d.ts` and served to\n * user modules as the `claudish/hooks` virtual module (see `loader.ts`).\n *\n * Every internal hooks module takes its types from here, so the contract has a\n * single source.\n *\n * ## Process isolation\n *\n * A hook module\'s top-level state is PER PROCESS. In the interactive launcher,\n * proxy events (`request` \u2026 `responseEnd`, raw) and session events\n * (`sessionStart` \u2026 `sessionEnd`) run in one process. In `create_session` and\n * team children they do not: proxy events run in the pane child, and session\n * events run in the MCP server or the CLI process that drives the pane. Pass\n * per-turn data from a proxy event to `sessionIdle` with `annotateTurn`, never\n * with module variables.\n *\n * ## Execution: a hook chain\n *\n * The hooks of one event run one after another, in effective order. Each hook\'s\n * actions are applied before the next hook is called, so `ctx.request`,\n * `ctx.tool.args` and `ctx.response` show what the earlier hooks did, and\n * `ctx.prior` lists it. A warn-severity or failing hook changes nothing for the\n * next one. Each event has a budget for all its hooks together; a hook\'s timeout\n * is cut to what is left of it.\n *\n * ## Output\n *\n * Log with `ctx.log`. `console.*` and `process.stdout`/`stderr` writes made by a\n * hook are routed to claudish\'s debug log, never to the terminal or the MCP\n * protocol stream.\n */\n export const HOOK_API_VERSION = 1;\n export type Severity = "off" | "warn" | "fix";\n export type HookOrder = "pre" | "normal" | "post";\n /** native = RouteInfo.native true; foreign = RouteInfo.native false; all = both */\n export type RouteScope = "foreign" | "native" | "all";\n export type HostMode = "interactive" | "pane-child" | "serve" | "mcp" | "other";\n export type JsonValue = string | number | boolean | null | ReadonlyArray<JsonValue> | {\n readonly [k: string]: JsonValue;\n };\n export interface HarnessFacts {\n readonly planModeActive: boolean;\n readonly planFilePath?: string;\n readonly planDir?: string;\n /** Claude Code session id from request metadata */\n readonly sessionId?: string;\n /** empty = no listing found, not "no skills" */\n readonly skills?: ReadonlyArray<{\n name: string;\n description: string;\n }>;\n }\n export interface RouteInfo {\n /** bare model name the handler serves, e.g. "glm-5" */\n readonly modelId: string;\n /** claudish provider name, e.g. "openrouter"; "anthropic" for native */\n readonly provider: string;\n /**\n * true when the request is served by the native Anthropic handler, OR when\n * !forceForeignModel && (/^claude[-.]/i.test(modelId) || provider === "anthropic")\n * where forceForeignModel is the provider profile\'s opt-in override. This is the exact\n * rule the plan-mode built-in has always used (a claude-* uid on an aggregator that sets\n * forceForeignModel is foreign).\n */\n readonly native: boolean;\n }\n export interface ClaudeTool {\n name: string;\n description?: string;\n input_schema?: unknown;\n }\n /** A Claude-format content block. Only `text` blocks are editable by closed actions. */\n export type ClaudeContentBlock = {\n type: "text";\n text: string;\n } | {\n type: "tool_use";\n id: string;\n name: string;\n input: unknown;\n } | {\n type: "tool_result";\n tool_use_id: string;\n content?: unknown;\n is_error?: boolean;\n } | {\n type: "thinking";\n thinking: string;\n signature?: string;\n } | {\n type: string;\n [k: string]: unknown;\n };\n export interface ClaudeMessage {\n role: "user" | "assistant";\n content: string | ReadonlyArray<ClaudeContentBlock>;\n }\n /**\n * In `request`, the request as the earlier steps of the hook chain left it. On\n * the response side and in `claims()`, the request chain\'s final view.\n */\n export interface RequestFacts {\n /** as Claude Code asked for it; frozen */\n readonly model: string;\n /** frozen */\n readonly stream: boolean;\n /** system prompt flattened to text, after earlier steps */\n readonly systemText: string;\n /** read-only view after earlier steps; change it through actions */\n readonly messages: ReadonlyArray<ClaudeMessage>;\n /**\n * read-only view after earlier steps; `description` includes earlier description actions as\n * stage B will apply them to the Claude-format tool (the provider copy may be summarised)\n */\n readonly tools: ReadonlyArray<ClaudeTool>;\n }\n /** Which session a proxy event belongs to, when claudish knows. */\n export interface ProxySessionRef {\n readonly kind: SessionKind;\n readonly id: string;\n readonly role: "slot" | "judge" | null;\n }\n /** One action an earlier step of this hook chain applied or handed on. */\n export interface PriorAction {\n readonly hookId: string;\n readonly action: HookAction;\n }\n interface BaseContext {\n readonly hookId: string;\n /** "warn" or "fix" (an "off" hook is never called) */\n readonly severity: Severity;\n /** writes to claudish\'s debug log; never to the terminal */\n log(message: string): void;\n /**\n * this step\'s own signal: aborted when its step timeout elapses (its own timeout, or the\n * event budget left, whichever is shorter) or when the dispatch is aborted. Never shared\n * with another hook\'s step.\n */\n readonly signal: AbortSignal;\n /**\n * actions earlier steps of this hook chain applied (or, for responseEnd/sessionStart/\n * sessionIdle, handed on), in order. Empty for the first step and in claims()/the toolCall\n * predicate. Never lists warn actions or anything a warn-severity hook returned.\n */\n readonly prior: ReadonlyArray<PriorAction>;\n }\n export interface ProxyContext extends BaseContext {\n readonly host: {\n mode: HostMode;\n };\n readonly route: RouteInfo;\n readonly request: RequestFacts;\n readonly harness: HarnessFacts;\n readonly session: ProxySessionRef | null;\n }\n export interface RequestContext extends ProxyContext {\n readonly event: "request";\n }\n export interface ToolCallContext extends ProxyContext {\n readonly event: "toolCall";\n readonly tool: {\n id: string;\n name: string;\n /** the arguments after every repair earlier hooks in the chain applied */\n args: Readonly<Record<string, unknown>>;\n /** the argument JSON exactly as the model produced it; never rewritten */\n rawArgs: string;\n };\n }\n export type ResponseBlock = {\n type: "text";\n text: string;\n } | {\n type: "thinking";\n thinking: string;\n } | {\n type: "tool_use";\n id: string;\n name: string;\n input: unknown;\n } | {\n type: "other";\n blockType: string;\n };\n export interface ResponseView {\n blocks: ReadonlyArray<ResponseBlock>;\n /** every text block, joined with "\\n\\n" */\n text: string;\n /** every thinking block, joined with "\\n\\n" */\n reasoning: string;\n toolNames: ReadonlyArray<string>;\n /** "tool_use" = an intermediate step of a tool loop; the turn continues after the tool runs */\n stopReason: string | null;\n }\n /** response = the held response after every text action earlier hooks in the chain applied */\n export interface ResponseRewriteContext extends ProxyContext {\n readonly event: "responseRewrite";\n readonly response: ResponseView;\n }\n /** response = the final bytes the client received: after any rewrite AND any raw `response` replacement */\n export interface ResponseEndContext extends ProxyContext {\n readonly event: "responseEnd";\n readonly response: ResponseView;\n }\n export type SessionKind = "interactive" | "channel" | "team";\n export interface SessionInfo {\n kind: SessionKind;\n /** team only; null otherwise */\n role: "slot" | "judge" | null;\n /** channel: the 8-hex session_id \xB7 team: "<run_id>:<slot id>" \xB7 interactive: the Claude Code session id */\n id: string;\n claudeSessionId: string | null;\n /** as the caller asked for it */\n model: string;\n cwd: string;\n /** a one-shot session stays "one-shot" through a hook-extended turn chain */\n shape: "interactive" | "one-shot";\n injection: "available" | "unavailable";\n }\n export interface SessionStartContext extends BaseContext {\n readonly event: "sessionStart";\n readonly session: SessionInfo;\n }\n export interface TurnAnnotation {\n hookId: string;\n key: string;\n value: JsonValue;\n }\n export interface SessionIdleContext extends BaseContext {\n readonly event: "sessionIdle";\n readonly session: SessionInfo;\n readonly turn: {\n /** 1-based within the session; a re-woken turn keeps its index */\n index: number;\n /** this turn\'s assistant text */\n answer: string;\n stopReason: string | null;\n apiError: boolean;\n /** this turn was started by an injection */\n hookCaused: boolean;\n /** annotateTurn actions from this turn\'s responses, in arrival order */\n annotations: ReadonlyArray<TurnAnnotation>;\n };\n readonly consecutiveHookTurns: number;\n /** caller/human input is queued; an injection returned now will be dropped as stale */\n readonly callerInputPending: boolean;\n }\n export interface SessionBlockedContext extends BaseContext {\n readonly event: "sessionBlocked";\n readonly session: SessionInfo;\n readonly block: {\n kind: "question" | "permission";\n text: string;\n };\n }\n export interface SessionEndContext extends BaseContext {\n readonly event: "sessionEnd";\n readonly session: SessionInfo;\n readonly outcome: {\n state: string;\n reason: string | null;\n exitCode: number | null;\n };\n }\n type TextMatch = {\n find: string;\n regex?: boolean;\n flags?: string;\n };\n /** default ["user"] */\n type MessageRoles = {\n roles?: ReadonlyArray<"user" | "assistant">;\n };\n export type InjectSystemNote = {\n type: "injectSystemNote";\n text: string;\n };\n export type AppendUserText = {\n type: "appendUserText";\n text: string;\n };\n export type ReplaceMessageText = {\n type: "replaceMessageText";\n replace: string;\n } & TextMatch & MessageRoles;\n export type RemoveMessageText = {\n type: "removeMessageText";\n } & TextMatch & MessageRoles;\n export type RewriteToolDescription = {\n type: "rewriteToolDescription";\n tool: string;\n append: string;\n };\n export type ReplaceToolDescription = {\n type: "replaceToolDescription";\n tool: string;\n description: string;\n };\n export type ReplaceToolSchema = {\n type: "replaceToolSchema";\n tool: string;\n inputSchema: {\n type: "object";\n [k: string]: unknown;\n };\n };\n export type RemoveTool = {\n type: "removeTool";\n tool: string;\n };\n export type RepairToolArgs = {\n type: "repairToolArgs";\n args: Record<string, unknown>;\n reason: string;\n };\n export type AppendText = {\n type: "appendText";\n text: string;\n };\n export type PrependText = {\n type: "prependText";\n text: string;\n };\n export type ReplaceText = {\n type: "replaceText";\n replace: string;\n } & TextMatch;\n export type RemoveText = {\n type: "removeText";\n } & TextMatch;\n export type InjectUserTurn = {\n type: "injectUserTurn";\n text: string;\n };\n export type AnnotateTurn = {\n type: "annotateTurn";\n key: string;\n value: JsonValue;\n };\n export type Warn = {\n type: "warn";\n message: string;\n };\n export type RequestAction = InjectSystemNote | AppendUserText | ReplaceMessageText | RemoveMessageText | RewriteToolDescription | ReplaceToolDescription | ReplaceToolSchema | RemoveTool | Warn;\n export type ToolCallAction = RepairToolArgs | Warn;\n export type RewriteAction = AppendText | PrependText | ReplaceText | RemoveText | Warn;\n export type ResponseEndAction = InjectSystemNote | InjectUserTurn | AnnotateTurn | Warn;\n export type SessionAction = InjectUserTurn | Warn;\n export type ObserveAction = Warn;\n export type HookAction = RequestAction | ToolCallAction | RewriteAction | ResponseEndAction | SessionAction;\n export type HookResult<A> = A[] | void | Promise<A[] | void>;\n export interface HookHandlers {\n request?(ctx: RequestContext): HookResult<RequestAction>;\n toolCall?: {\n /** tool names whose completed arguments this hook sees; "*" = every tool (costs streaming of all tool input) */\n tools: ReadonlyArray<string>;\n /** synchronous, per request; default true. false = not armed for this request */\n armed?(ctx: RequestContext): boolean;\n /** true = see the call after it was forwarded; can only warn; never holds the stream */\n observe?: boolean;\n handle(ctx: ToolCallContext): HookResult<ToolCallAction>;\n };\n responseRewrite?: {\n /** synchronous, per request, evaluated before the response starts; default true */\n claims?(ctx: RequestContext): boolean;\n handle(ctx: ResponseRewriteContext): HookResult<RewriteAction>;\n };\n responseEnd?(ctx: ResponseEndContext): HookResult<ResponseEndAction>;\n sessionStart?(ctx: SessionStartContext): HookResult<SessionAction>;\n sessionIdle?(ctx: SessionIdleContext): HookResult<SessionAction>;\n sessionBlocked?(ctx: SessionBlockedContext): HookResult<ObserveAction>;\n sessionEnd?(ctx: SessionEndContext): HookResult<ObserveAction>;\n }\n export interface RawProviderRequestContext {\n readonly hookId: string;\n readonly route: RouteInfo;\n claudeRequest: any;\n messages: any[];\n tools: any[];\n }\n export interface RawProviderChunkContext {\n readonly hookId: string;\n readonly route: RouteInfo;\n /** A clone of the parsed provider event. Whatever this field holds when the call returns is\n * what the parser reads from then on, so it may be edited in place or replaced. */\n chunk: any;\n /** The delta object inside `chunk` at call time (Responses wire: `chunk` itself). Edit it in\n * place; assigning a new object to this field has no effect. */\n delta: any;\n /** per-stream, shared across this hook\'s chunk calls; never cloned */\n metadata: Map<string, unknown>;\n }\n export interface RawProviderStreamEndContext {\n readonly hookId: string;\n readonly route: RouteInfo;\n metadata: Map<string, unknown>;\n }\n export interface RawResponseContext {\n readonly hookId: string;\n readonly route: RouteInfo;\n readonly request: RequestFacts;\n /** A replay of the current Claude-format response (SSE, or JSON for stream:false), read at the\n * hook\'s own pace. claudish drains the original itself, so leaving this unread delays nothing. */\n response: Response;\n }\n export interface RawMiddleware {\n /**\n * Receives clones. They replace the live request only when this call returns (or its promise\n * resolves) within its timeout. A throw, a rejection or a timeout discards every change.\n */\n providerRequest?(ctx: RawProviderRequestContext): void | Promise<void>;\n /**\n * MUST be synchronous. Called on the parser\'s loop, on a clone of the chunk. On a normal return\n * of anything but a thenable, the clone (whatever `ctx.chunk` holds then) is committed: it\n * becomes the object the parser reads, deletions included. On a throw nothing is committed.\n * A declared `async` function is rejected at load. Any other thenable return is an invalid\n * invocation: the clone is discarded even if the hook mutated it before returning, the call is\n * journaled `invalid` (`async_return`) and counts toward the circuit breaker, and a rejection\n * handler is attached, so a rejection is journaled `error` and never becomes an\n * unhandledRejection.\n */\n providerChunk?(ctx: RawProviderChunkContext): void;\n providerStreamEnd?(ctx: RawProviderStreamEndContext): void | Promise<void>;\n /**\n * Return a replacement Response, or nothing to keep the current one. A replacement is read\n * whole and forwarded only when it completes cleanly; on any failure the original is forwarded.\n * The client never sees a partial replacement. A replacement must close within this hook\'s\n * timeout after the later of this call\'s return and the end of the original; the original\'s end\n * never depends on whether `ctx.response` is read.\n */\n response?(ctx: RawResponseContext): Response | void | Promise<Response | void>;\n }\n interface HookBase {\n apiVersion: 1;\n id: string;\n description?: string;\n /** default "fix" for user hooks */\n defaultSeverity?: Severity;\n /** default "normal" */\n order?: HookOrder;\n /** globs on RouteInfo.modelId; default "*"; proxy events only */\n models?: string | ReadonlyArray<string>;\n /** default "all"; proxy events only */\n routes?: RouteScope;\n /** per call; clamped to the event\'s maximum and to the event budget left when the hook\'s turn comes */\n timeoutMs?: number;\n on?: HookHandlers;\n }\n export interface SafeHook extends HookBase {\n unsafe?: never;\n raw?: never;\n }\n export interface UnsafeHook extends HookBase {\n unsafe: true;\n raw: RawMiddleware;\n }\n /**\n * One hook. Module-level state is per process: in `create_session` and team\n * children, proxy events run in the pane child and session events in the MCP\n * server or CLI process. Pass per-turn data from proxy events to `sessionIdle`\n * with `annotateTurn`, never with module variables.\n */\n export type HookDefinition = SafeHook | UnsafeHook;\n /** Identity function: gives editor type-checking and inference. */\n export function defineHook<const H extends HookDefinition>(hook: H): H;\n /** Action constructors (plain data; equivalent to writing the object literal). */\n export const act: {\n injectSystemNote(text: string): InjectSystemNote;\n appendUserText(text: string): AppendUserText;\n replaceMessageText(find: string, replace: string, opts?: {\n regex?: boolean;\n flags?: string;\n roles?: ReadonlyArray<"user" | "assistant">;\n }): ReplaceMessageText;\n removeMessageText(find: string, opts?: {\n regex?: boolean;\n flags?: string;\n roles?: ReadonlyArray<"user" | "assistant">;\n }): RemoveMessageText;\n rewriteToolDescription(tool: string, append: string): RewriteToolDescription;\n replaceToolDescription(tool: string, description: string): ReplaceToolDescription;\n replaceToolSchema(tool: string, inputSchema: {\n type: "object";\n [k: string]: unknown;\n }): ReplaceToolSchema;\n removeTool(tool: string): RemoveTool;\n repairToolArgs(args: Record<string, unknown>, reason: string): RepairToolArgs;\n appendText(text: string): AppendText;\n prependText(text: string): PrependText;\n replaceText(find: string, replace: string, opts?: {\n regex?: boolean;\n flags?: string;\n }): ReplaceText;\n removeText(find: string, opts?: {\n regex?: boolean;\n flags?: string;\n }): RemoveText;\n injectUserTurn(text: string): InjectUserTurn;\n annotateTurn(key: string, value: JsonValue): AnnotateTurn;\n warn(message: string): Warn;\n };\n}\n';
79788
79904
 
79789
79905
  // src/hooks/observer/corpus.ts
79790
- import { appendFileSync as appendFileSync8, readFileSync as readFileSync36, readdirSync as readdirSync10, statSync as statSync14 } from "fs";
79906
+ import { appendFileSync as appendFileSync8, readFileSync as readFileSync37, readdirSync as readdirSync10, statSync as statSync15 } from "fs";
79791
79907
  import { homedir as homedir36 } from "os";
79792
- import { join as join54 } from "path";
79908
+ import { join as join55 } from "path";
79793
79909
  function directoryOf2(filePath) {
79794
79910
  const slash = filePath.lastIndexOf("/");
79795
79911
  return slash > 0 ? filePath.slice(0, slash) : undefined;
@@ -79811,7 +79927,7 @@ function writeTargetsOf(row) {
79811
79927
  function replayTranscript(file) {
79812
79928
  let text;
79813
79929
  try {
79814
- text = readFileSync36(file, "utf8");
79930
+ text = readFileSync37(file, "utf8");
79815
79931
  } catch {
79816
79932
  return [];
79817
79933
  }
@@ -79868,26 +79984,26 @@ function listTranscripts(root) {
79868
79984
  return files;
79869
79985
  }
79870
79986
  for (const project of projects) {
79871
- const dir = join54(root, project);
79987
+ const dir = join55(root, project);
79872
79988
  try {
79873
- if (!statSync14(dir).isDirectory())
79989
+ if (!statSync15(dir).isDirectory())
79874
79990
  continue;
79875
79991
  for (const f of readdirSync10(dir)) {
79876
79992
  if (f.endsWith(".jsonl"))
79877
- files.push(join54(dir, f));
79993
+ files.push(join55(dir, f));
79878
79994
  }
79879
79995
  } catch {}
79880
79996
  }
79881
79997
  return files;
79882
79998
  }
79883
79999
  function buildCorpus(options = {}) {
79884
- const root = options.projectsRoot ?? join54(homedir36(), ".claude", "projects");
80000
+ const root = options.projectsRoot ?? join55(homedir36(), ".claude", "projects");
79885
80001
  const files = listTranscripts(root);
79886
80002
  const records = [];
79887
80003
  for (const f of files)
79888
80004
  records.push(...replayTranscript(f));
79889
80005
  if (options.write && records.length > 0) {
79890
- const outputPath = options.outputPath ?? join54(homedir36(), ".claudish", "behavior-divergences.jsonl");
80006
+ const outputPath = options.outputPath ?? join55(homedir36(), ".claudish", "behavior-divergences.jsonl");
79891
80007
  try {
79892
80008
  appendFileSync8(outputPath, `${records.map((r) => JSON.stringify(r)).join(`
79893
80009
  `)}
@@ -79903,9 +80019,9 @@ var init_corpus = __esm(() => {
79903
80019
  });
79904
80020
 
79905
80021
  // src/hooks-command.ts
79906
- import { existsSync as existsSync37, mkdirSync as mkdirSync25, readFileSync as readFileSync37, writeFileSync as writeFileSync26 } from "fs";
80022
+ import { existsSync as existsSync38, mkdirSync as mkdirSync25, readFileSync as readFileSync38, writeFileSync as writeFileSync26 } from "fs";
79907
80023
  import { homedir as homedir37 } from "os";
79908
- import { join as join55, resolve as resolve8 } from "path";
80024
+ import { join as join56, resolve as resolve9 } from "path";
79909
80025
  function severityColor(sev) {
79910
80026
  if (sev === "fix")
79911
80027
  return green(sev);
@@ -79995,7 +80111,7 @@ async function check(file, json) {
79995
80111
  console.error("Usage: claudish hooks check <file> [--json]");
79996
80112
  return 1;
79997
80113
  }
79998
- const path = resolve8(process.cwd(), file);
80114
+ const path = resolve9(process.cwd(), file);
79999
80115
  const notes = [];
80000
80116
  const loaded = await loadUserHooks({
80001
80117
  modules: [path],
@@ -80028,12 +80144,12 @@ async function check(file, json) {
80028
80144
  return valid ? 0 : 1;
80029
80145
  }
80030
80146
  function init(dirArg) {
80031
- const dir = dirArg ? resolve8(process.cwd(), dirArg) : join55(homedir37(), ".claudish", "hooks");
80147
+ const dir = dirArg ? resolve9(process.cwd(), dirArg) : join56(homedir37(), ".claudish", "hooks");
80032
80148
  const files = [
80033
- [join55(dir, "example-hook.ts"), EXAMPLE_HOOK],
80034
- [join55(dir, "claudish-hooks.d.ts"), HOOKS_AMBIENT_DTS]
80149
+ [join56(dir, "example-hook.ts"), EXAMPLE_HOOK],
80150
+ [join56(dir, "claudish-hooks.d.ts"), HOOKS_AMBIENT_DTS]
80035
80151
  ];
80036
- const existing = files.filter(([path]) => existsSync37(path)).map(([path]) => path);
80152
+ const existing = files.filter(([path]) => existsSync38(path)).map(([path]) => path);
80037
80153
  if (existing.length > 0) {
80038
80154
  for (const path of existing)
80039
80155
  console.error(`${path} already exists; not overwriting it.`);
@@ -80106,8 +80222,8 @@ function setTelemetryEnabled(value) {
80106
80222
  const path = activeConfigFile();
80107
80223
  let cfg = {};
80108
80224
  try {
80109
- if (existsSync37(path)) {
80110
- const parsed = JSON.parse(readFileSync37(path, "utf-8"));
80225
+ if (existsSync38(path)) {
80226
+ const parsed = JSON.parse(readFileSync38(path, "utf-8"));
80111
80227
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
80112
80228
  cfg = parsed;
80113
80229
  }
@@ -80126,8 +80242,8 @@ function telemetry(action, json) {
80126
80242
  let pending = 0;
80127
80243
  try {
80128
80244
  const path = outboxPath();
80129
- if (existsSync37(path))
80130
- pending = readFileSync37(path, "utf8").split(`
80245
+ if (existsSync38(path))
80246
+ pending = readFileSync38(path, "utf8").split(`
80131
80247
  `).filter(Boolean).length;
80132
80248
  } catch {}
80133
80249
  if (json) {
@@ -80234,9 +80350,9 @@ var init_hooks_command = __esm(() => {
80234
80350
 
80235
80351
  // src/team-grid.ts
80236
80352
  import { spawn as spawn3 } from "child_process";
80237
- import { existsSync as existsSync38, readFileSync as readFileSync38, writeFileSync as writeFileSync27 } from "fs";
80353
+ import { existsSync as existsSync39, readFileSync as readFileSync39, writeFileSync as writeFileSync27 } from "fs";
80238
80354
  import { connect as netConnect2 } from "net";
80239
- import { join as join56 } from "path";
80355
+ import { join as join57 } from "path";
80240
80356
  import { setTimeout as wait } from "timers/promises";
80241
80357
  function paneRouteLine(explanation) {
80242
80358
  const origin = describeRouteExplanation(explanation);
@@ -80291,7 +80407,7 @@ function withoutControlPanes(evt) {
80291
80407
  async function subscribeToMagmux(sockPath, onEvent) {
80292
80408
  let client = null;
80293
80409
  for (let attempt = 0;attempt < 40; attempt++) {
80294
- if (existsSync38(sockPath)) {
80410
+ if (existsSync39(sockPath)) {
80295
80411
  try {
80296
80412
  client = await new Promise((resolve, reject) => {
80297
80413
  const s = netConnect2(sockPath);
@@ -80386,9 +80502,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
80386
80502
  const keep = opts?.keep ?? false;
80387
80503
  const manifest = setupSession(sessionPath, models, input);
80388
80504
  const startedAt = new Date().toISOString();
80389
- const gridfilePath = join56(sessionPath, "gridfile.txt");
80390
- const prompt = readFileSync38(join56(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
80391
- const rawPrompt = readFileSync38(join56(sessionPath, "input.md"), "utf-8");
80505
+ const gridfilePath = join57(sessionPath, "gridfile.txt");
80506
+ const prompt = readFileSync39(join57(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
80507
+ const rawPrompt = readFileSync39(join57(sessionPath, "input.md"), "utf-8");
80392
80508
  const usedBannerColors = new Set;
80393
80509
  const routeLines = mode === "interactive" ? new Map : await resolvePaneRouteLines(Object.values(manifest.models).map((entry) => entry.model));
80394
80510
  const gridLines = Object.entries(manifest.models).map(([anonId]) => {
@@ -80420,7 +80536,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
80420
80536
  });
80421
80537
  const [{ results }] = await Promise.all([subscription, procExit]);
80422
80538
  const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
80423
- const statusPath = join56(sessionPath, "status.json");
80539
+ const statusPath = join57(sessionPath, "status.json");
80424
80540
  writeFileSync27(statusPath, JSON.stringify(status, null, 2), "utf-8");
80425
80541
  return status;
80426
80542
  }
@@ -80440,8 +80556,8 @@ var init_team_grid = __esm(() => {
80440
80556
  });
80441
80557
 
80442
80558
  // src/team-cli.ts
80443
- import { readFileSync as readFileSync39 } from "fs";
80444
- import { join as join57 } from "path";
80559
+ import { readFileSync as readFileSync40 } from "fs";
80560
+ import { join as join58 } from "path";
80445
80561
  async function runPaneTeam(sessionPath, models, input, opts) {
80446
80562
  installPaneShutdownHooks({ exitAfter: true });
80447
80563
  try {
@@ -80586,7 +80702,7 @@ async function teamCommand(args) {
80586
80702
  }
80587
80703
  case "judge": {
80588
80704
  await judgeResponses(sessionPath, { judges });
80589
- console.log(readFileSync39(join57(sessionPath, "verdict.md"), "utf-8"));
80705
+ console.log(readFileSync40(join58(sessionPath, "verdict.md"), "utf-8"));
80590
80706
  break;
80591
80707
  }
80592
80708
  case "run-and-judge": {
@@ -80602,7 +80718,7 @@ async function teamCommand(args) {
80602
80718
  });
80603
80719
  printStatus(status);
80604
80720
  await judgeResponses(sessionPath, { judges });
80605
- console.log(readFileSync39(join57(sessionPath, "verdict.md"), "utf-8"));
80721
+ console.log(readFileSync40(join58(sessionPath, "verdict.md"), "utf-8"));
80606
80722
  break;
80607
80723
  }
80608
80724
  case "status": {
@@ -81557,9 +81673,9 @@ var init_subscription_models_command = __esm(() => {
81557
81673
 
81558
81674
  // src/auth/antigravity-oauth.ts
81559
81675
  import { spawnSync as spawnSync2 } from "child_process";
81560
- import { existsSync as existsSync39, unlinkSync as unlinkSync9 } from "fs";
81676
+ import { existsSync as existsSync40, unlinkSync as unlinkSync9 } from "fs";
81561
81677
  import { homedir as homedir38 } from "os";
81562
- import { join as join58 } from "path";
81678
+ import { join as join59 } from "path";
81563
81679
  async function defaultSuggestModel() {
81564
81680
  try {
81565
81681
  const token = await getValidAntigravityAccessToken();
@@ -81678,8 +81794,8 @@ No session detected yet. Starting the Antigravity CLI interactively \u2014
81678
81794
  async logout(deps) {
81679
81795
  deleteSharedAntigravityToken(deps);
81680
81796
  try {
81681
- const tokenFile = join58(homedir38(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
81682
- if (existsSync39(tokenFile))
81797
+ const tokenFile = join59(homedir38(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
81798
+ if (existsSync40(tokenFile))
81683
81799
  unlinkSync9(tokenFile);
81684
81800
  } catch {}
81685
81801
  log("[AntigravityOAuth] Antigravity session cleared (keychain + agy token file)");
@@ -89825,8 +89941,8 @@ var init_own_pane = __esm(() => {
89825
89941
  });
89826
89942
 
89827
89943
  // src/hooks/session/interactive-driver.ts
89828
- import { existsSync as existsSync40, statSync as statSync15 } from "fs";
89829
- import { join as join59 } from "path";
89944
+ import { existsSync as existsSync41, statSync as statSync16 } from "fs";
89945
+ import { join as join60 } from "path";
89830
89946
  function nextDriverPhase(phase, ev) {
89831
89947
  const row = EDGES[phase];
89832
89948
  return row[ev] ?? null;
@@ -90044,7 +90160,7 @@ class InteractiveDriver {
90044
90160
  }
90045
90161
  follow(sid, offset) {
90046
90162
  const path = transcriptPathFor(this.o.cwd, sid, this.o.projectsRoot);
90047
- this.follower = new TranscriptFollower(path, join59(path.replace(/\.jsonl$/, ""), "subagents"));
90163
+ this.follower = new TranscriptFollower(path, join60(path.replace(/\.jsonl$/, ""), "subagents"));
90048
90164
  this.sessionId = sid;
90049
90165
  this.settledTurn = null;
90050
90166
  this.lastPollAt = Date.now();
@@ -90065,7 +90181,7 @@ class InteractiveDriver {
90065
90181
  if (!p)
90066
90182
  return;
90067
90183
  const path = transcriptPathFor(this.o.cwd, p.id, this.o.projectsRoot);
90068
- if (!existsSync40(path)) {
90184
+ if (!existsSync41(path)) {
90069
90185
  if (Date.now() - p.since > RETARGET_WAIT_MS) {
90070
90186
  log(`[hooks] interactive driver: no transcript for session ${p.id}; not following it`);
90071
90187
  this.pendingSid = null;
@@ -90589,7 +90705,7 @@ function assertNeverPhase(p) {
90589
90705
  }
90590
90706
  function fileSizeOf(path) {
90591
90707
  try {
90592
- return statSync15(path).size;
90708
+ return statSync16(path).size;
90593
90709
  } catch {
90594
90710
  return 0;
90595
90711
  }
@@ -90734,14 +90850,14 @@ var init_no_surface = __esm(() => {
90734
90850
  var UI_LEASE_MS = 1e4, FRAME_TICK_MS = 1000;
90735
90851
 
90736
90852
  // src/recovery/magmux-ui.ts
90737
- import { existsSync as existsSync41 } from "fs";
90853
+ import { existsSync as existsSync42 } from "fs";
90738
90854
  import { connect as netConnect3 } from "net";
90739
90855
  function resolveControlEndpoint() {
90740
- if (explicitControlSock && existsSync41(explicitControlSock)) {
90856
+ if (explicitControlSock && existsSync42(explicitControlSock)) {
90741
90857
  return { sock: explicitControlSock, wrapped: true };
90742
90858
  }
90743
90859
  const ambient = process.env.MAGMUX_SOCK;
90744
- if (ambient && existsSync41(ambient))
90860
+ if (ambient && existsSync42(ambient))
90745
90861
  return { sock: ambient, wrapped: false };
90746
90862
  return null;
90747
90863
  }
@@ -91147,19 +91263,19 @@ import { randomUUID as randomUUID8 } from "crypto";
91147
91263
  import {
91148
91264
  chmodSync as chmodSync4,
91149
91265
  closeSync as closeSync12,
91150
- existsSync as existsSync42,
91266
+ existsSync as existsSync43,
91151
91267
  mkdirSync as mkdirSync26,
91152
91268
  mkdtempSync as mkdtempSync4,
91153
91269
  openSync as openSync12,
91154
- readFileSync as readFileSync40,
91270
+ readFileSync as readFileSync41,
91155
91271
  readdirSync as readdirSync11,
91156
91272
  rmSync as rmSync11,
91157
- statSync as statSync16,
91273
+ statSync as statSync17,
91158
91274
  unlinkSync as unlinkSync10,
91159
91275
  writeFileSync as writeFileSync28
91160
91276
  } from "fs";
91161
91277
  import { homedir as homedir39, tmpdir as tmpdir3 } from "os";
91162
- import { dirname as dirname18, join as join60 } from "path";
91278
+ import { dirname as dirname18, join as join61 } from "path";
91163
91279
  import { isatty } from "tty";
91164
91280
  function releaseTerminalIsolation() {
91165
91281
  if (!restoreTerminal)
@@ -91226,12 +91342,12 @@ function isRealAnthropicEnvCredential(env, name) {
91226
91342
  }
91227
91343
  function hasResolvableAnthropicAuth(deps = {}) {
91228
91344
  const env = deps.env ?? process.env;
91229
- const fileExists = deps.fileExists ?? existsSync42;
91345
+ const fileExists = deps.fileExists ?? existsSync43;
91230
91346
  const keychainProbe = deps.keychainProbe ?? defaultKeychainAnthropicProbe;
91231
91347
  if (isRealAnthropicEnvCredential(env, "ANTHROPIC_API_KEY") || isRealAnthropicEnvCredential(env, "ANTHROPIC_AUTH_TOKEN")) {
91232
91348
  return true;
91233
91349
  }
91234
- if (fileExists(join60(homedir39(), ".claude", ".credentials.json")))
91350
+ if (fileExists(join61(homedir39(), ".claude", ".credentials.json")))
91235
91351
  return true;
91236
91352
  return keychainProbe();
91237
91353
  }
@@ -91246,14 +91362,14 @@ function isProxyAuthMode(config) {
91246
91362
  }
91247
91363
  function managedSettingsPath() {
91248
91364
  if (isWindows2()) {
91249
- return join60(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
91365
+ return join61(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
91250
91366
  }
91251
91367
  if (process.platform === "darwin") {
91252
91368
  return "/Library/Application Support/ClaudeCode/managed-settings.json";
91253
91369
  }
91254
91370
  return "/etc/claude-code/managed-settings.json";
91255
91371
  }
91256
- function managedSettingsForcesClaudeAi(readFile = readFileSync40) {
91372
+ function managedSettingsForcesClaudeAi(readFile = readFileSync41) {
91257
91373
  try {
91258
91374
  const raw = readFile(managedSettingsPath(), "utf-8");
91259
91375
  const parsed = JSON.parse(raw);
@@ -91267,9 +91383,9 @@ function isWindows2() {
91267
91383
  }
91268
91384
  function createStatusLineScript(tokenFilePath) {
91269
91385
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir3();
91270
- const claudishDir = join60(homeDir, ".claudish");
91386
+ const claudishDir = join61(homeDir, ".claudish");
91271
91387
  const timestamp = Date.now();
91272
- const scriptPath = join60(claudishDir, `status-${timestamp}.js`);
91388
+ const scriptPath = join61(claudishDir, `status-${timestamp}.js`);
91273
91389
  const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
91274
91390
  const light = getThemeMode() === "light";
91275
91391
  const cyanCode = light ? "38;2;14;116;144" : "96";
@@ -91439,9 +91555,9 @@ function cleanupStaleTokenFiles(dir, now = Date.now(), maxAgeMs = STALE_TOKEN_FI
91439
91555
  if (!name.startsWith("tokens-") || !name.endsWith(".json"))
91440
91556
  continue;
91441
91557
  scanned++;
91442
- const full = join60(dir, name);
91558
+ const full = join61(dir, name);
91443
91559
  try {
91444
- if (statSync16(full).mtimeMs >= cutoff)
91560
+ if (statSync17(full).mtimeMs >= cutoff)
91445
91561
  continue;
91446
91562
  unlinkSync10(full);
91447
91563
  removed++;
@@ -91456,7 +91572,7 @@ function parseSettingsArg(value) {
91456
91572
  if (value.trimStart().startsWith("{")) {
91457
91573
  return JSON.parse(value);
91458
91574
  }
91459
- return JSON.parse(readFileSync40(value, "utf-8"));
91575
+ return JSON.parse(readFileSync41(value, "utf-8"));
91460
91576
  }
91461
91577
  function parseSettingsArgSafe(value) {
91462
91578
  try {
@@ -91468,13 +91584,13 @@ function parseSettingsArgSafe(value) {
91468
91584
  }
91469
91585
  function userSettingsFileCandidates(cwd) {
91470
91586
  return [
91471
- join60(homedir39(), ".claude", "settings.json"),
91472
- join60(cwd, ".claude", "settings.json"),
91473
- join60(cwd, ".claude", "settings.local.json")
91587
+ join61(homedir39(), ".claude", "settings.json"),
91588
+ join61(cwd, ".claude", "settings.json"),
91589
+ join61(cwd, ".claude", "settings.local.json")
91474
91590
  ];
91475
91591
  }
91476
91592
  function discoverUserStatusLineCommand(claudeArgs = [], cwd = process.cwd()) {
91477
- const sources = userSettingsFileCandidates(cwd).filter((file) => existsSync42(file));
91593
+ const sources = userSettingsFileCandidates(cwd).filter((file) => existsSync43(file));
91478
91594
  const idx = claudeArgs.indexOf("--settings");
91479
91595
  const settingsArg = idx === -1 ? undefined : claudeArgs[idx + 1];
91480
91596
  if (settingsArg)
@@ -91511,12 +91627,12 @@ function buildChainedStatusCommand(userCommand, claudishBody, claudishSegment) {
91511
91627
  }
91512
91628
  function createTempSettingsFile(_modelDisplay, port, proxyAuthMode, userStatusLineCommand) {
91513
91629
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir3();
91514
- const claudishDir = join60(homeDir, ".claudish");
91630
+ const claudishDir = join61(homeDir, ".claudish");
91515
91631
  try {
91516
91632
  mkdirSync26(claudishDir, { recursive: true });
91517
91633
  } catch {}
91518
91634
  const timestamp = Date.now();
91519
- const tempPath = join60(claudishDir, `settings-${timestamp}.json`);
91635
+ const tempPath = join61(claudishDir, `settings-${timestamp}.json`);
91520
91636
  const assignedFile = assignedTokenFile(process.env) !== null;
91521
91637
  const tokenFilePath = resolveTokenFilePath(port);
91522
91638
  cleanupStaleTokenFiles(claudishDir);
@@ -91669,13 +91785,13 @@ function resolveAdvisorToolEnv(config, processEnv = process.env) {
91669
91785
  return { vars: { [ADVISOR_TOOL_ENV_VAR]: "1" }, source: "claudish" };
91670
91786
  }
91671
91787
  function discoverUserAdvisorModel(claudeArgs = [], cwd = process.cwd()) {
91672
- const sources = userSettingsFileCandidates(cwd).filter((file) => existsSync42(file));
91788
+ const sources = userSettingsFileCandidates(cwd).filter((file) => existsSync43(file));
91673
91789
  const idx = claudeArgs.indexOf("--settings");
91674
91790
  const settingsArg = idx === -1 ? undefined : claudeArgs[idx + 1];
91675
91791
  if (settingsArg)
91676
91792
  sources.push(settingsArg);
91677
91793
  const managed = managedSettingsPath();
91678
- if (existsSync42(managed))
91794
+ if (existsSync43(managed))
91679
91795
  sources.push(managed);
91680
91796
  let effective;
91681
91797
  for (const source of sources) {
@@ -91896,7 +92012,7 @@ async function runClaudeWithProxy(config, proxyUrl, onCleanup) {
91896
92012
  console.error(`
91897
92013
  Or set CLAUDE_PATH to your custom installation:`);
91898
92014
  const home = homedir39();
91899
- const localPath = isWindows2() ? join60(home, ".claude", "local", "claude.exe") : join60(home, ".claude", "local", "claude");
92015
+ const localPath = isWindows2() ? join61(home, ".claude", "local", "claude.exe") : join61(home, ".claude", "local", "claude");
91900
92016
  console.error(` export CLAUDE_PATH=${localPath}`);
91901
92017
  process.exit(1);
91902
92018
  }
@@ -91931,7 +92047,7 @@ Or set CLAUDE_PATH to your custom installation:`);
91931
92047
  let driverLaunch = null;
91932
92048
  if (surfaces.driver) {
91933
92049
  const minted = sessionFlags.sessionId || sessionFlags.resumes ? null : randomUUID8();
91934
- const turnDir = mkdtempSync4(join60(tmpdir3(), "claudish-turns-"));
92050
+ const turnDir = mkdtempSync4(join61(tmpdir3(), "claudish-turns-"));
91935
92051
  chmodSync4(turnDir, 448);
91936
92052
  claudeArgs.unshift(...driverLeadingArgs({ mintedSessionId: minted, turnDir }));
91937
92053
  const sink = new InProcessSink;
@@ -92075,23 +92191,23 @@ function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
92075
92191
  async function findClaudeBinary() {
92076
92192
  const isWindows = process.platform === "win32";
92077
92193
  if (process.env.CLAUDE_PATH) {
92078
- if (existsSync42(process.env.CLAUDE_PATH)) {
92194
+ if (existsSync43(process.env.CLAUDE_PATH)) {
92079
92195
  return process.env.CLAUDE_PATH;
92080
92196
  }
92081
92197
  }
92082
92198
  const home = homedir39();
92083
- const localPath = isWindows ? join60(home, ".claude", "local", "claude.exe") : join60(home, ".claude", "local", "claude");
92084
- if (existsSync42(localPath)) {
92199
+ const localPath = isWindows ? join61(home, ".claude", "local", "claude.exe") : join61(home, ".claude", "local", "claude");
92200
+ if (existsSync43(localPath)) {
92085
92201
  return localPath;
92086
92202
  }
92087
92203
  if (isWindows) {
92088
92204
  const windowsPaths = [
92089
- join60(home, "AppData", "Roaming", "npm", "claude.cmd"),
92090
- join60(home, ".npm-global", "claude.cmd"),
92091
- join60(home, "node_modules", ".bin", "claude.cmd")
92205
+ join61(home, "AppData", "Roaming", "npm", "claude.cmd"),
92206
+ join61(home, ".npm-global", "claude.cmd"),
92207
+ join61(home, "node_modules", ".bin", "claude.cmd")
92092
92208
  ];
92093
92209
  for (const path of windowsPaths) {
92094
- if (existsSync42(path)) {
92210
+ if (existsSync43(path)) {
92095
92211
  return path;
92096
92212
  }
92097
92213
  }
@@ -92099,14 +92215,14 @@ async function findClaudeBinary() {
92099
92215
  const commonPaths = [
92100
92216
  "/usr/local/bin/claude",
92101
92217
  "/opt/homebrew/bin/claude",
92102
- join60(home, ".npm-global/bin/claude"),
92103
- join60(home, ".local/bin/claude"),
92104
- join60(home, "node_modules/.bin/claude"),
92218
+ join61(home, ".npm-global/bin/claude"),
92219
+ join61(home, ".local/bin/claude"),
92220
+ join61(home, "node_modules/.bin/claude"),
92105
92221
  "/data/data/com.termux/files/usr/bin/claude",
92106
- join60(home, "../usr/bin/claude")
92222
+ join61(home, "../usr/bin/claude")
92107
92223
  ];
92108
92224
  for (const path of commonPaths) {
92109
- if (existsSync42(path)) {
92225
+ if (existsSync43(path)) {
92110
92226
  return path;
92111
92227
  }
92112
92228
  }
@@ -92196,16 +92312,16 @@ var init_claude_runner = __esm(() => {
92196
92312
  // src/diag-output.ts
92197
92313
  import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync27, unlinkSync as unlinkSync11, writeFileSync as writeFileSync29 } from "fs";
92198
92314
  import { homedir as homedir40 } from "os";
92199
- import { join as join61 } from "path";
92315
+ import { join as join62 } from "path";
92200
92316
  function getClaudishDir() {
92201
- const dir = join61(homedir40(), ".claudish");
92317
+ const dir = join62(homedir40(), ".claudish");
92202
92318
  try {
92203
92319
  mkdirSync27(dir, { recursive: true });
92204
92320
  } catch {}
92205
92321
  return dir;
92206
92322
  }
92207
92323
  function getDiagLogPath() {
92208
- return join61(getClaudishDir(), `diag-${process.pid}.log`);
92324
+ return join62(getClaudishDir(), `diag-${process.pid}.log`);
92209
92325
  }
92210
92326
 
92211
92327
  class LogFileDiagOutput {
@@ -92741,7 +92857,7 @@ var init_advisor_startup = __esm(() => {
92741
92857
  });
92742
92858
 
92743
92859
  // src/session/conversation.ts
92744
- import { closeSync as closeSync13, openSync as openSync13, readSync as readSync7, statSync as statSync17 } from "fs";
92860
+ import { closeSync as closeSync13, openSync as openSync13, readSync as readSync7, statSync as statSync18 } from "fs";
92745
92861
  import { StringDecoder } from "string_decoder";
92746
92862
  function looksLikeTurn(line) {
92747
92863
  const assistant = line.includes('"type":"assistant"');
@@ -92796,7 +92912,7 @@ function readConversation(file, opts = {}) {
92796
92912
  };
92797
92913
  let fd = null;
92798
92914
  try {
92799
- const size = statSync17(file).size;
92915
+ const size = statSync18(file).size;
92800
92916
  fd = openSync13(file, "r");
92801
92917
  const buf = Buffer.allocUnsafe(chunkBytes);
92802
92918
  const decoder = new StringDecoder("utf-8");
@@ -94455,11 +94571,11 @@ var exports_session_stats = {};
94455
94571
  __export(exports_session_stats, {
94456
94572
  readSessionStats: () => readSessionStats
94457
94573
  });
94458
- import { readFileSync as readFileSync41 } from "fs";
94574
+ import { readFileSync as readFileSync42 } from "fs";
94459
94575
  function readSessionStats(port, opts) {
94460
94576
  let raw;
94461
94577
  try {
94462
- raw = JSON.parse(readFileSync41(resolveTokenFilePath(port), "utf-8"));
94578
+ raw = JSON.parse(readFileSync42(resolveTokenFilePath(port), "utf-8"));
94463
94579
  } catch {
94464
94580
  return null;
94465
94581
  }
@@ -94837,8 +94953,8 @@ init_launch_env();
94837
94953
  init_op_source();
94838
94954
  init_startup_trace();
94839
94955
  init_picker_cancelled();
94840
- import { existsSync as existsSync43, readFileSync as readFileSync42 } from "fs";
94841
- import { join as join62, resolve as resolve9 } from "path";
94956
+ import { existsSync as existsSync44, readFileSync as readFileSync43 } from "fs";
94957
+ import { join as join63, resolve as resolve10 } from "path";
94842
94958
 
94843
94959
  // src/tui/runtime/should-open-picker.ts
94844
94960
  function noModelConfigured(gate) {
@@ -94855,7 +94971,7 @@ function requiresExplicitModel(gate, tty) {
94855
94971
  var autoloadDropped = [...droppedAtLaunch, ...takeLauncherDropped(process.env)];
94856
94972
  var dotenvText;
94857
94973
  try {
94858
- dotenvText = readFileSync42(join62(process.cwd(), ".env"));
94974
+ dotenvText = readFileSync43(join63(process.cwd(), ".env"));
94859
94975
  } catch {}
94860
94976
  if (dotenvText !== undefined) {
94861
94977
  await Promise.resolve().then(() => init_dotenv_allowlist());
@@ -94970,8 +95086,8 @@ async function applyOpImport() {
94970
95086
  async function applyConfigOverride() {
94971
95087
  await Promise.resolve();
94972
95088
  const plan = planConfigOverride(process.argv.slice(2), process.env, {
94973
- resolve: resolve9,
94974
- exists: existsSync43
95089
+ resolve: resolve10,
95090
+ exists: existsSync44
94975
95091
  });
94976
95092
  if (plan.kind === "none")
94977
95093
  return;
@@ -95176,14 +95292,14 @@ async function runCli() {
95176
95292
  if (cliConfig.team && cliConfig.team.length > 0) {
95177
95293
  let prompt = cliConfig.claudeArgs.join(" ");
95178
95294
  if (cliConfig.inputFile) {
95179
- prompt = readFileSync42(cliConfig.inputFile, "utf-8");
95295
+ prompt = readFileSync43(cliConfig.inputFile, "utf-8");
95180
95296
  }
95181
95297
  if (!prompt.trim()) {
95182
95298
  console.error("Error: --team requires a prompt (positional args or -f <file>)");
95183
95299
  process.exit(1);
95184
95300
  }
95185
95301
  const mode = cliConfig.teamMode ?? "default";
95186
- const sessionPath = join62(process.cwd(), `.claudish-team-${Date.now()}`);
95302
+ const sessionPath = join63(process.cwd(), `.claudish-team-${Date.now()}`);
95187
95303
  if (mode === "json") {
95188
95304
  await Promise.resolve().then(() => init_pane());
95189
95305
  await Promise.resolve().then(() => init_team_orchestrator());
@@ -95203,9 +95319,9 @@ async function runCli() {
95203
95319
  const status = await runModels(sessionPath);
95204
95320
  const result = { ...status, responses: {} };
95205
95321
  for (const anonId of Object.keys(status.models)) {
95206
- const responsePath = join62(sessionPath, `response-${anonId}.md`);
95322
+ const responsePath = join63(sessionPath, `response-${anonId}.md`);
95207
95323
  try {
95208
- const raw = readFileSync42(responsePath, "utf-8").trim();
95324
+ const raw = readFileSync43(responsePath, "utf-8").trim();
95209
95325
  try {
95210
95326
  result.responses[anonId] = JSON.parse(raw);
95211
95327
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "13.3.0",
3
+ "version": "13.4.0",
4
4
  "description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -69,10 +69,10 @@
69
69
  "ai"
70
70
  ],
71
71
  "optionalDependencies": {
72
- "@claudish/magmux-darwin-arm64": "13.3.0",
73
- "@claudish/magmux-darwin-x64": "13.3.0",
74
- "@claudish/magmux-linux-arm64": "13.3.0",
75
- "@claudish/magmux-linux-x64": "13.3.0"
72
+ "@claudish/magmux-darwin-arm64": "13.4.0",
73
+ "@claudish/magmux-darwin-x64": "13.4.0",
74
+ "@claudish/magmux-linux-arm64": "13.4.0",
75
+ "@claudish/magmux-linux-x64": "13.4.0"
76
76
  },
77
77
  "author": "Jack Rudenko <i@madappgang.com>",
78
78
  "license": "MIT",