claudish 14.5.0 → 14.5.2

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 +212 -34
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -5332,7 +5332,7 @@ var init_onepassword_config = __esm(() => {
5332
5332
  });
5333
5333
 
5334
5334
  // src/version.ts
5335
- var VERSION = "14.5.0";
5335
+ var VERSION = "14.5.2";
5336
5336
 
5337
5337
  // src/redact.ts
5338
5338
  function isPlaceholder(value) {
@@ -23245,7 +23245,12 @@ function syncRun(args, stdin) {
23245
23245
  });
23246
23246
  return normalizeResult(proc.exitCode, proc.signalCode, decode2(proc.stdout), decode2(proc.stderr));
23247
23247
  } catch (err) {
23248
- return { code: 1, stdout: "", stderr: err instanceof Error ? err.message : String(err) };
23248
+ return {
23249
+ code: 1,
23250
+ stdout: "",
23251
+ stderr: err instanceof Error ? err.message : String(err),
23252
+ spawnError: true
23253
+ };
23249
23254
  }
23250
23255
  }
23251
23256
  async function asyncRun(args, stdin) {
@@ -23263,7 +23268,12 @@ async function asyncRun(args, stdin) {
23263
23268
  ]);
23264
23269
  return normalizeResult(exitCode, proc.signalCode, stdout, stderr);
23265
23270
  } catch (err) {
23266
- return { code: 1, stdout: "", stderr: err instanceof Error ? err.message : String(err) };
23271
+ return {
23272
+ code: 1,
23273
+ stdout: "",
23274
+ stderr: err instanceof Error ? err.message : String(err),
23275
+ spawnError: true
23276
+ };
23267
23277
  }
23268
23278
  }
23269
23279
  function spawnAsyncRun(args, stdin) {
@@ -23280,7 +23290,8 @@ function spawnAsyncRun(args, stdin) {
23280
23290
  ]).then(([stdout, stderr, exitCode]) => normalizeResult(exitCode, proc.signalCode, stdout, stderr), (err) => ({
23281
23291
  code: 1,
23282
23292
  stdout: "",
23283
- stderr: err instanceof Error ? err.message : String(err)
23293
+ stderr: err instanceof Error ? err.message : String(err),
23294
+ spawnError: true
23284
23295
  }));
23285
23296
  return { done, pid: proc.pid };
23286
23297
  } catch (err) {
@@ -23288,12 +23299,38 @@ function spawnAsyncRun(args, stdin) {
23288
23299
  done: Promise.resolve({
23289
23300
  code: 1,
23290
23301
  stdout: "",
23291
- stderr: err instanceof Error ? err.message : String(err)
23302
+ stderr: err instanceof Error ? err.message : String(err),
23303
+ spawnError: true
23292
23304
  }),
23293
23305
  pid: undefined
23294
23306
  };
23295
23307
  }
23296
23308
  }
23309
+ function securityErrorDetail(res) {
23310
+ if (res.spawnError) {
23311
+ return res.stderr.trim().slice(0, SECURITY_DETAIL_MAX) || `security exited ${res.code}`;
23312
+ }
23313
+ const kept = [];
23314
+ for (const raw of res.stderr.split(/\r?\n/)) {
23315
+ const line = raw.trim();
23316
+ if (!line || /unknown command/.test(line))
23317
+ continue;
23318
+ const returned = SECURITY_RETURNED_LINE.exec(line);
23319
+ if (returned) {
23320
+ if (KNOWN_SECURITY_SUBCOMMANDS.has(returned[1]))
23321
+ kept.push(line);
23322
+ continue;
23323
+ }
23324
+ if (SECURITY_FIXED_LINES.some((re) => re.test(line)))
23325
+ kept.push(line);
23326
+ }
23327
+ if (res.code === -1 && !kept.some((line) => /killed by|timed out/.test(line))) {
23328
+ kept.unshift("security killed by a signal / timed out");
23329
+ }
23330
+ const detail = kept.join(`
23331
+ `).slice(0, SECURITY_DETAIL_MAX);
23332
+ return detail || `security exited ${res.code}`;
23333
+ }
23297
23334
  function decode2(buf) {
23298
23335
  return buf ? new TextDecoder().decode(buf) : "";
23299
23336
  }
@@ -23351,7 +23388,7 @@ function interpretRead(envVar, res) {
23351
23388
  }
23352
23389
  if (res.code === EXIT_ITEM_NOT_FOUND)
23353
23390
  return null;
23354
- throw new KeychainError(`Keychain lookup for ${envVar} failed: ${res.stderr.trim() || `security exited ${res.code}`}`, res.code);
23391
+ throw new KeychainError(`Keychain lookup for ${envVar} failed: ${securityErrorDetail(res)}`, res.code);
23355
23392
  }
23356
23393
  function readKeychainSecret(envVar) {
23357
23394
  return readKeychainItem(KEYCHAIN_SERVICE, envVar);
@@ -23411,7 +23448,7 @@ function interpretGenericPassword(res, withValue) {
23411
23448
  return {
23412
23449
  kind: "failed",
23413
23450
  code: res.code,
23414
- error: res.stderr.trim() || `security exited ${res.code}`
23451
+ error: securityErrorDetail(res)
23415
23452
  };
23416
23453
  }
23417
23454
  async function findGenericPasswordPresence(query) {
@@ -23437,7 +23474,7 @@ function enumerateKeychainVars() {
23437
23474
  const value = res.code === 0 ? { names: parseDumpAccounts(res.stdout), failed: false } : {
23438
23475
  names: [],
23439
23476
  failed: true,
23440
- error: res.stderr.trim() || `security exited ${res.code}`
23477
+ error: securityErrorDetail(res)
23441
23478
  };
23442
23479
  listMemo = { at, value };
23443
23480
  return value;
@@ -23472,6 +23509,9 @@ function toHex(value) {
23472
23509
  function quoteForStdin(value) {
23473
23510
  return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
23474
23511
  }
23512
+ function valueArgs(value) {
23513
+ return PRINTABLE_ASCII.test(value) ? ["-w", quoteForStdin(value)] : ["-X", quoteForStdin(toHex(value))];
23514
+ }
23475
23515
  function writeKeychainSecret(envVar, value) {
23476
23516
  const unsupported = keychainUnavailableReason();
23477
23517
  if (unsupported)
@@ -23504,17 +23544,21 @@ function writeKeychainItem(service, account, value) {
23504
23544
  quoteForStdin("application password"),
23505
23545
  "-j",
23506
23546
  quoteForStdin("Stored by claudish"),
23507
- "-X",
23508
- quoteForStdin(toHex(value)),
23547
+ ...valueArgs(value),
23509
23548
  "-U",
23510
23549
  "-T",
23511
23550
  quoteForStdin(SECURITY_BIN),
23512
23551
  ...keychainFileArgs().map(quoteForStdin)
23513
23552
  ].join(" ");
23514
- const res = deps.run(["-i"], `${cmd}
23515
- `);
23553
+ const line = `${cmd}
23554
+ `;
23555
+ const lineBytes = Buffer.byteLength(line, "utf8");
23556
+ if (lineBytes > MAX_STDIN_LINE) {
23557
+ throw new KeychainError(`Cannot store ${account}: value is too large for the keychain write path ` + `(${lineBytes} bytes on the command line, limit ${MAX_STDIN_LINE})`);
23558
+ }
23559
+ const res = deps.run(["-i"], line);
23516
23560
  if (res.code !== 0) {
23517
- throw new KeychainError(`Failed to store ${account} in the keychain: ${res.stderr.trim() || `security exited ${res.code}`}`, res.code);
23561
+ throw new KeychainError(`Failed to store ${account} in the keychain: ${securityErrorDetail(res)}`, res.code);
23518
23562
  }
23519
23563
  invalidateKeychainCache();
23520
23564
  const readBack = readKeychainItem(service, account, { uncached: true });
@@ -23542,14 +23586,14 @@ function deleteKeychainItem(service, account) {
23542
23586
  return true;
23543
23587
  if (res.code === EXIT_ITEM_NOT_FOUND)
23544
23588
  return false;
23545
- throw new KeychainError(`Failed to delete ${account} from the keychain: ${res.stderr.trim() || `security exited ${res.code}`}`, res.code);
23589
+ throw new KeychainError(`Failed to delete ${account} from the keychain: ${securityErrorDetail(res)}`, res.code);
23546
23590
  }
23547
23591
  function valueTail2(value) {
23548
23592
  if (value.length <= 6)
23549
23593
  return "\u2022\u2022\u2022\u2022";
23550
23594
  return `\u2022\u2022\u2022\u2022${value.slice(-4)}`;
23551
23595
  }
23552
- var KEYCHAIN_SERVICE = "claudish", KEYCHAIN_ACCOUNTS_SERVICE = "claudish-accounts", SECURITY_BIN = "/usr/bin/security", EXIT_ITEM_NOT_FOUND = 44, MEMO_TTL_MS = 3000, SPAWN_TIMEOUT_MS = 1e4, KeychainError, defaultDeps2, deps, listMemo = null, valueMemo, CONTROL_CHARS2, ENV_VAR_NAME, ACCT_ATTR, SVCE_MATCH, KEYCHAIN_ACCOUNT_NAME;
23596
+ var KEYCHAIN_SERVICE = "claudish", KEYCHAIN_ACCOUNTS_SERVICE = "claudish-accounts", SECURITY_BIN = "/usr/bin/security", EXIT_ITEM_NOT_FOUND = 44, MEMO_TTL_MS = 3000, SPAWN_TIMEOUT_MS = 1e4, KeychainError, KNOWN_SECURITY_SUBCOMMANDS, SECURITY_RETURNED_LINE, SECURITY_FIXED_LINES, SECURITY_DETAIL_MAX = 300, defaultDeps2, deps, listMemo = null, valueMemo, CONTROL_CHARS2, ENV_VAR_NAME, ACCT_ATTR, SVCE_MATCH, MAX_STDIN_LINE = 4000, PRINTABLE_ASCII, KEYCHAIN_ACCOUNT_NAME;
23553
23597
  var init_keychain = __esm(() => {
23554
23598
  KeychainError = class KeychainError extends Error {
23555
23599
  exitCode;
@@ -23559,6 +23603,27 @@ var init_keychain = __esm(() => {
23559
23603
  this.name = "KeychainError";
23560
23604
  }
23561
23605
  };
23606
+ KNOWN_SECURITY_SUBCOMMANDS = new Set([
23607
+ "add-generic-password",
23608
+ "find-generic-password",
23609
+ "delete-generic-password",
23610
+ "add-internet-password",
23611
+ "find-internet-password",
23612
+ "delete-internet-password",
23613
+ "dump-keychain",
23614
+ "create-keychain",
23615
+ "delete-keychain",
23616
+ "unlock-keychain",
23617
+ "lock-keychain",
23618
+ "set-keychain-settings"
23619
+ ]);
23620
+ SECURITY_RETURNED_LINE = /^([\w-]+): returned -?\d+$/;
23621
+ SECURITY_FIXED_LINES = [
23622
+ /^security: Sec\w+( \([^)]*\))?: .+$/,
23623
+ /^security (killed by \w+|terminated without an exit code)$/,
23624
+ /^Unable to convert password data .+$/,
23625
+ /^User interaction is not allowed\.?$/
23626
+ ];
23562
23627
  defaultDeps2 = {
23563
23628
  platform: () => process.platform,
23564
23629
  run: syncRun,
@@ -23571,6 +23636,7 @@ var init_keychain = __esm(() => {
23571
23636
  ENV_VAR_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
23572
23637
  ACCT_ATTR = /"acct"<blob>=(?:0x[0-9A-Fa-f]*\s+)?"([^"]*)"/;
23573
23638
  SVCE_MATCH = `"svce"<blob>="${KEYCHAIN_SERVICE}"`;
23639
+ PRINTABLE_ASCII = /^[\x20-\x7e]*$/;
23574
23640
  KEYCHAIN_ACCOUNT_NAME = /^[A-Za-z0-9][A-Za-z0-9._:@-]{0,127}$/;
23575
23641
  });
23576
23642
 
@@ -93242,6 +93308,8 @@ function applyAssistantBlock(state, t, b, offset) {
93242
93308
  return;
93243
93309
  t.pending.set(b.id, String(b.name ?? ""));
93244
93310
  t.pendingInput.set(b.id, b.input);
93311
+ if (b.name === "Write" && typeof b.input?.file_path === "string")
93312
+ t.writes.push({ id: b.id, path: b.input.file_path, offset, ok: false });
93245
93313
  if (b.name === "Bash" && b.input?.run_in_background)
93246
93314
  t.shellToolIds.set(b.id, String(b.input?.command ?? ""));
93247
93315
  applyReadUse(state, t, b);
@@ -93253,6 +93321,7 @@ function applyToolResults(t, r, blocks, offset) {
93253
93321
  continue;
93254
93322
  t.pending.delete(b.tool_use_id);
93255
93323
  t.pendingInput.delete(b.tool_use_id);
93324
+ markWriteResult(t, b);
93256
93325
  if (tur?.isAsync === true && typeof tur.agentId === "string")
93257
93326
  t.agents.add(tur.agentId);
93258
93327
  if (typeof tur?.backgroundTaskId === "string")
@@ -93260,6 +93329,13 @@ function applyToolResults(t, r, blocks, offset) {
93260
93329
  applyReadResult(t, r, b, offset);
93261
93330
  }
93262
93331
  }
93332
+ function markWriteResult(t, b) {
93333
+ if (b.is_error === true)
93334
+ return;
93335
+ const w = t.writes.find((x) => x.id === b.tool_use_id);
93336
+ if (w)
93337
+ w.ok = true;
93338
+ }
93263
93339
  function applyLocalCommandRecord(t, text, offset) {
93264
93340
  if (t.witness.kind !== "command" || t.lastAssistant || t.localOutput)
93265
93341
  return;
@@ -93400,6 +93476,7 @@ function openTurnState(state, t) {
93400
93476
  acceptedAt: null,
93401
93477
  acceptedOffset: null,
93402
93478
  texts: [],
93479
+ writes: [],
93403
93480
  lastAssistant: null,
93404
93481
  td: null,
93405
93482
  stopHookAfterLast: false,
@@ -93424,6 +93501,7 @@ function openTurnState(state, t) {
93424
93501
  function turnView(t) {
93425
93502
  const rs = t.read;
93426
93503
  let texts = t.texts;
93504
+ let writes = t.writes;
93427
93505
  let preambleBytes = 0;
93428
93506
  if (rs) {
93429
93507
  const cut = rs.completedAtOffset ?? rs.lastReadOffset;
@@ -93431,6 +93509,7 @@ function turnView(t) {
93431
93509
  const before = texts.filter((x) => x.offset < cut);
93432
93510
  preambleBytes = before.reduce((n, x) => n + Buffer.byteLength(x.text), 0);
93433
93511
  texts = texts.filter((x) => x.offset > cut);
93512
+ writes = writes.filter((x) => x.offset > cut);
93434
93513
  }
93435
93514
  }
93436
93515
  const pendingEntry = [...t.pending.entries()].pop();
@@ -93462,6 +93541,7 @@ function turnView(t) {
93462
93541
  completedAtOffset: rs.completedAtOffset
93463
93542
  } : { linesReturned: 0, complete: true, reads: 0, completedAtOffset: null },
93464
93543
  preambleBytes,
93544
+ writtenFiles: [...new Set(writes.filter((x) => x.ok).map((x) => x.path))],
93465
93545
  lastChatOffset: t.lastChatOffset,
93466
93546
  localCommandOutput: t.localOutput?.text ?? null,
93467
93547
  recent: [...t.steps],
@@ -95202,7 +95282,8 @@ ${screenTailOf(this.screen)}`
95202
95282
  linesRead: t.delivery ? t.readCoverage.linesReturned : null,
95203
95283
  complete: t.delivery && !unverified ? t.readCoverage.complete : null,
95204
95284
  preambleBytes: t.preambleBytes
95205
- }
95285
+ },
95286
+ writtenFiles: decision.by === "local_command" ? [] : t.writtenFiles
95206
95287
  };
95207
95288
  }
95208
95289
  settle(t, decision, exitCode) {
@@ -95271,10 +95352,12 @@ ${screenTailOf(this.screen)}`
95271
95352
  this.follower.markSettled();
95272
95353
  }
95273
95354
  const last = this.chain[this.chain.length - 1];
95274
- if (last && last.index === core.index)
95355
+ const writtenFiles = core.writtenFiles ?? [];
95356
+ if (last && last.index === core.index) {
95275
95357
  last.answer = core.answer;
95276
- else
95277
- this.chain.push({ index: core.index, answer: core.answer });
95358
+ last.writtenFiles = writtenFiles;
95359
+ } else
95360
+ this.chain.push({ index: core.index, answer: core.answer, writtenFiles });
95278
95361
  if (!this.turnHookCaused)
95279
95362
  this.chainHead = core.delivery;
95280
95363
  const turn = {
@@ -95282,7 +95365,8 @@ ${screenTailOf(this.screen)}`
95282
95365
  chainAnswers: this.chain.slice(0, -1).map((c) => c.answer),
95283
95366
  chainDelivery: this.chainHead ?? core.delivery,
95284
95367
  hookTurns: this.hookTurns,
95285
- hookCaused: this.turnHookCaused
95368
+ hookCaused: this.turnHookCaused,
95369
+ writtenFiles: [...new Set(this.chain.flatMap((c) => c.writtenFiles))]
95286
95370
  };
95287
95371
  this.heldTurn = turn;
95288
95372
  try {
@@ -97141,6 +97225,9 @@ function snippetHeadAndTail(text) {
97141
97225
 
97142
97226
  ${tail}`;
97143
97227
  }
97228
+ function fileAnswerNote(path) {
97229
+ return `answer was written to ${path}, not to the reply`;
97230
+ }
97144
97231
  function classifyRunOutput(input) {
97145
97232
  const v = classifyAnswer(input);
97146
97233
  if (v && input.stopReason === "max_tokens")
@@ -97193,9 +97280,55 @@ function classifyShape(answer, requirePattern, chainAnswers) {
97193
97280
  return {
97194
97281
  state: "EMPTY",
97195
97282
  reason: "shape_mismatch",
97196
- detail: `The answer (${Buffer.byteLength(answer, "utf8")} B of assistant text after the task was ` + `read) does not match the required pattern /${requirePattern}/. Every assistant message ` + "of the turn was read from the transcript, so nothing was lost: the model did not " + "produce the shape. Re-prompt it, or relax the contract."
97283
+ detail: shapeDetail(answer, requirePattern, null)
97197
97284
  };
97198
97285
  }
97286
+ function shapeDetail(answer, requirePattern, files) {
97287
+ const reply = `reply (${Buffer.byteLength(answer, "utf8")} B of assistant text after the task was read) does not match`;
97288
+ const advice = "Re-prompt it, or relax the contract.";
97289
+ if (!files)
97290
+ return `The ${reply} the required pattern /${requirePattern}/. ${advice}`;
97291
+ const wrote = files.length ? `the turn wrote ${files.join(", ")}` : "the turn wrote no file";
97292
+ return `No reply text or written file matched /${requirePattern}/: the ${reply}, and ${wrote}. ${advice}`;
97293
+ }
97294
+ function answerFailureDetail(v, answer, requirePattern, outcomes) {
97295
+ if (v.reason === "shape_mismatch" && requirePattern) {
97296
+ const note = v.detail.endsWith(`(${TRUNCATION_NOTE})`) ? ` (${TRUNCATION_NOTE})` : "";
97297
+ return `${shapeDetail(answer, requirePattern, outcomes)}${note}`;
97298
+ }
97299
+ if (outcomes.length)
97300
+ return `${v.detail} The turn wrote ${outcomes.join(", ")}.`;
97301
+ return v.detail;
97302
+ }
97303
+ function readWrittenFile(path, root) {
97304
+ let realRoot;
97305
+ try {
97306
+ realRoot = realpathSync7(root);
97307
+ } catch {
97308
+ realRoot = resolve5(root);
97309
+ }
97310
+ let real;
97311
+ try {
97312
+ real = realpathSync7(resolve5(root, path));
97313
+ } catch {
97314
+ return { skip: "missing" };
97315
+ }
97316
+ if (real !== realRoot && !real.startsWith(realRoot + sep))
97317
+ return { skip: "outside the working directory" };
97318
+ try {
97319
+ const st = statSync17(real);
97320
+ if (!st.isFile())
97321
+ return { skip: "not a regular file" };
97322
+ if (st.size > MAX_FILE_ANSWER_BYTES)
97323
+ return { skip: "larger than 1 MiB" };
97324
+ const buf = readFileSync42(real);
97325
+ if (buf.includes(0))
97326
+ return { skip: "binary" };
97327
+ return { text: buf.toString("utf8") };
97328
+ } catch {
97329
+ return { skip: "missing" };
97330
+ }
97331
+ }
97199
97332
  function classifyAnswer(input) {
97200
97333
  const signal = classifyTurnSignals(input);
97201
97334
  if (signal)
@@ -97417,6 +97550,7 @@ async function startModelsIn(flight, sessionPath, opts) {
97417
97550
  }
97418
97551
  const minOutputBytes = opts.minOutputBytes ?? DEFAULT_MIN_OUTPUT_BYTES;
97419
97552
  const requirePattern = opts.requirePattern;
97553
+ const cwd = opts.cwd ?? process.cwd();
97420
97554
  mkdirSync24(statsDir(path), { recursive: true });
97421
97555
  const entries = new Map;
97422
97556
  let run = null;
@@ -97450,10 +97584,36 @@ async function startModelsIn(flight, sessionPath, opts) {
97450
97584
  return e.session.chainText();
97451
97585
  return e.session?.turnAnswer(index) ?? "";
97452
97586
  }
97587
+ function fileAnswerOf(turn, reason) {
97588
+ if (reason !== "shape_mismatch" && reason !== "empty_output")
97589
+ return { file: null, outcomes: [] };
97590
+ if (!requirePattern)
97591
+ return { file: null, outcomes: turn.writtenFiles ?? [] };
97592
+ const outcomes = [];
97593
+ for (const written of turn.writtenFiles ?? []) {
97594
+ const path = resolve5(cwd, written);
97595
+ const r = readWrittenFile(path, cwd);
97596
+ if ("skip" in r) {
97597
+ outcomes.push(`${path} (skipped: ${r.skip})`);
97598
+ continue;
97599
+ }
97600
+ const fv = classifyRunOutput({
97601
+ answer: r.text,
97602
+ apiError: null,
97603
+ stopReason: turn.stopReason,
97604
+ promptRead: turn.chainDelivery,
97605
+ minOutputBytes,
97606
+ requirePattern
97607
+ });
97608
+ if (!fv)
97609
+ return { file: { path, text: r.text }, outcomes };
97610
+ outcomes.push(`${path} (no match)`);
97611
+ }
97612
+ return { file: null, outcomes };
97613
+ }
97453
97614
  function teamDecide(e, turn) {
97454
97615
  e.stopReason = turn.stopReason;
97455
97616
  const answer = chainAnswerOf(turn);
97456
- writeResponse(e, answer);
97457
97617
  const v = classifyRunOutput({
97458
97618
  answer,
97459
97619
  chainAnswers: [...turn.chainAnswers, turn.answer],
@@ -97464,11 +97624,24 @@ async function startModelsIn(flight, sessionPath, opts) {
97464
97624
  requirePattern
97465
97625
  });
97466
97626
  const shells = (e.session?.snapshot().anomalies ?? []).filter((a) => a.startsWith("background_shell_open"));
97627
+ const truncated = turn.stopReason === "max_tokens" ? [TRUNCATION_NOTE] : [];
97467
97628
  if (!v) {
97468
- const notes = [...shells, ...turn.stopReason === "max_tokens" ? [TRUNCATION_NOTE] : []];
97629
+ e.answerSource = "reply";
97630
+ writeResponse(e, answer);
97631
+ const notes = [...shells, ...truncated];
97469
97632
  return notes.length ? { state: "COMPLETED", detail: notes.join(" \xB7 ") } : { state: "COMPLETED" };
97470
97633
  }
97471
- return { state: v.state, reason: v.reason, detail: [v.detail, ...shells].join(" \xB7 ") };
97634
+ const { file, outcomes } = fileAnswerOf(turn, v.reason);
97635
+ if (file) {
97636
+ e.answerSource = `file:${file.path}`;
97637
+ writeResponse(e, file.text);
97638
+ const notes = [fileAnswerNote(file.path), ...shells, ...truncated];
97639
+ return { state: "COMPLETED", detail: notes.join(" \xB7 ") };
97640
+ }
97641
+ e.answerSource = "reply";
97642
+ writeResponse(e, answer);
97643
+ const detail = answerFailureDetail(v, answer, requirePattern, outcomes);
97644
+ return { state: v.state, reason: v.reason, detail: [detail, ...shells].join(" \xB7 ") };
97472
97645
  }
97473
97646
  function teamOnBlocked(e, b) {
97474
97647
  const index = (e.session?.snapshot().turnsCompleted ?? 0) + 1;
@@ -97504,6 +97677,7 @@ async function startModelsIn(flight, sessionPath, opts) {
97504
97677
  const answer = e.answer ?? writeResponse(e, unsettledAnswer(e, index));
97505
97678
  const anomalies = [
97506
97679
  ...notableAnomalies(snap),
97680
+ ...snap.state === "COMPLETED" && e.answerSource?.startsWith("file:") ? [fileAnswerNote(e.answerSource.slice("file:".length))] : [],
97507
97681
  ...snap.state === "COMPLETED" && e.stopReason === "max_tokens" ? [TRUNCATION_NOTE] : []
97508
97682
  ];
97509
97683
  const base = {
@@ -97511,7 +97685,8 @@ async function startModelsIn(flight, sessionPath, opts) {
97511
97685
  exitCode: snap.exitCode,
97512
97686
  outputSize: Buffer.byteLength(answer, "utf8"),
97513
97687
  stopReason: e.stopReason,
97514
- anomalies
97688
+ anomalies,
97689
+ ...e.answerSource ? { answerSource: e.answerSource } : {}
97515
97690
  };
97516
97691
  if (snap.state === "COMPLETED")
97517
97692
  return { ...base, error: undefined };
@@ -97576,7 +97751,6 @@ async function startModelsIn(flight, sessionPath, opts) {
97576
97751
  });
97577
97752
  notifyStatus(e.id);
97578
97753
  }
97579
- const cwd = process.cwd();
97580
97754
  const projects = projectsDir(parentEnv);
97581
97755
  function bindingFor(e, uuid) {
97582
97756
  const session = {
@@ -98040,7 +98214,7 @@ function formatVerdict(verdict, sessionPath) {
98040
98214
  }
98041
98215
  return output;
98042
98216
  }
98043
- var startsInFlight, teamRuns, newestRunByPath, SETTLED_RUN_RETENTION_MS, MAX_SETTLED_RUNS = 20, BOOT_STAGGER_MS = 300, STDOUT_TAIL_LIMIT = 4000, SNIPPET_LIMIT = 2000, SNIPPET_HEAD = 600, DEFAULT_MIN_OUTPUT_BYTES = 0, TRUNCATION_NOTE = "the turn ended on stop_reason max_tokens, so the answer may be truncated", CANCELLED_DETAIL;
98217
+ var startsInFlight, teamRuns, newestRunByPath, SETTLED_RUN_RETENTION_MS, MAX_SETTLED_RUNS = 20, BOOT_STAGGER_MS = 300, STDOUT_TAIL_LIMIT = 4000, SNIPPET_LIMIT = 2000, SNIPPET_HEAD = 600, DEFAULT_MIN_OUTPUT_BYTES = 0, TRUNCATION_NOTE = "the turn ended on stop_reason max_tokens, so the answer may be truncated", MAX_FILE_ANSWER_BYTES, CANCELLED_DETAIL;
98044
98218
  var init_team_orchestrator = __esm(() => {
98045
98219
  init_prehydrate();
98046
98220
  init_config();
@@ -98060,6 +98234,7 @@ var init_team_orchestrator = __esm(() => {
98060
98234
  teamRuns = new Map;
98061
98235
  newestRunByPath = new Map;
98062
98236
  SETTLED_RUN_RETENTION_MS = 30 * 60000;
98237
+ MAX_FILE_ANSWER_BYTES = 1024 * 1024;
98063
98238
  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.";
98064
98239
  });
98065
98240
 
@@ -101928,7 +102103,7 @@ var init_mcp_server = __esm(() => {
101928
102103
  api_error: "retry once, or route via a different provider (or@<model>)",
101929
102104
  refused: "the model refused \u2014 rephrase or drop the model",
101930
102105
  empty_output: "retry once; if it repeats, drop the model",
101931
- 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"
102106
+ shape_mismatch: "neither the reply (assistant text after the task was read) nor any file the slot wrote " + "with Write matched \u2014 the model did not produce it. Re-prompt with the required format " + "restated; do NOT count this slot as a vote"
101932
102107
  };
101933
102108
  USER_REQUIRED_MODEL_DESCRIPTION = "True only when the USER named this exact model: it then runs even when it is not in the " + "recommended list. Never set it for a model you chose yourself.";
101934
102109
  sanitize2 = sanitizeForReport;
@@ -104019,10 +104194,12 @@ function vendorOf(provider) {
104019
104194
  function pct(fraction) {
104020
104195
  return `${Math.round(fraction * 100)}%`;
104021
104196
  }
104022
- function renderWindows(row, pool) {
104023
- const windows = row.state.usage?.windows ?? [];
104024
- if (windows.length === 0)
104025
- return dim4("usage unknown");
104197
+ function renderWindows(row, pool, now) {
104198
+ const usage = row.state.usage ?? null;
104199
+ const windows = liveWindows(usage, now);
104200
+ if (windows.length === 0) {
104201
+ return dim4(usage && usage.windows.length > 0 ? "refilled since last seen" : "usage unknown");
104202
+ }
104026
104203
  return windows.map((w) => {
104027
104204
  const threshold = pool.switchAtByWindow[w.slot] ?? pool.switchAt;
104028
104205
  const text = `${w.displayId} ${pct(w.usedFraction)}`;
@@ -104035,7 +104212,7 @@ function renderRow2(row, pool, now) {
104035
104212
  const legacy = row.record.legacy ? dim4(" (legacy file)") : "";
104036
104213
  const disabled = row.record.enabled ? "" : dim4(" disabled");
104037
104214
  const plan = row.record.identity.plan ? dim4(` ${row.record.identity.plan}`) : "";
104038
- lines.push(` ${marker} ${strong2(row.record.label)}${legacy}${plan}${disabled} ${renderWindows(row, pool)}` + (row.isActive ? dim4(" active") : ""));
104215
+ lines.push(` ${marker} ${strong2(row.record.label)}${legacy}${plan}${disabled} ${renderWindows(row, pool, now)}` + (row.isActive ? dim4(" active") : ""));
104039
104216
  if (row.stateFailed) {
104040
104217
  lines.push(` ${warn2("state unreadable \u2014 ranked last, never assumed fresh")}`);
104041
104218
  }
@@ -104118,7 +104295,7 @@ ${strong2(vendorOf(report.provider))}`);
104118
104295
  if (!any) {
104119
104296
  console.log(`
104120
104297
  No subscription accounts are configured.`);
104121
- console.log(dim4("A Codex login (`claudish login codex`) is shown here as `default (legacy file)` " + "once it exists; multi-account commands arrive with the pool."));
104298
+ console.log(dim4("A Codex login (`claudish login codex`) is shown here as `default (legacy file)` " + "once it exists; add an account with `claudish account add codex --label <label>`."));
104122
104299
  }
104123
104300
  console.log("");
104124
104301
  }
@@ -104326,6 +104503,7 @@ The allowance trajectory, alerts and sessions of a claudish provider's account p
104326
104503
  --horizon <h|d> how far ahead to project, 1h to 7d (default 7d)
104327
104504
  --provider codex the claudish provider (openai-codex); the only one with a model today`;
104328
104505
  var init_account_command = __esm(() => {
104506
+ init_policy2();
104329
104507
  init_pool();
104330
104508
  init_registry();
104331
104509
  init_state_store();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "14.5.0",
3
+ "version": "14.5.2",
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",
@@ -71,10 +71,10 @@
71
71
  "ai"
72
72
  ],
73
73
  "optionalDependencies": {
74
- "@claudish/magmux-darwin-arm64": "14.5.0",
75
- "@claudish/magmux-darwin-x64": "14.5.0",
76
- "@claudish/magmux-linux-arm64": "14.5.0",
77
- "@claudish/magmux-linux-x64": "14.5.0"
74
+ "@claudish/magmux-darwin-arm64": "14.5.2",
75
+ "@claudish/magmux-darwin-x64": "14.5.2",
76
+ "@claudish/magmux-linux-arm64": "14.5.2",
77
+ "@claudish/magmux-linux-x64": "14.5.2"
78
78
  },
79
79
  "author": "Jack Rudenko <i@madappgang.com>",
80
80
  "license": "MIT",