claudish 7.28.0 → 7.29.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 +990 -488
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -651,7 +651,7 @@ var init_onepassword_config = __esm(() => {
651
651
  });
652
652
 
653
653
  // src/version.ts
654
- var VERSION = "7.28.0";
654
+ var VERSION = "7.29.0";
655
655
 
656
656
  // src/logger.ts
657
657
  var exports_logger = {};
@@ -37099,13 +37099,15 @@ var init_config = __esm(() => {
37099
37099
  SeveritySchema = exports_external.enum(["off", "warn", "fix"]);
37100
37100
  BehaviorConfigSchema = exports_external.object({
37101
37101
  preset: exports_external.string().optional(),
37102
+ telemetry: exports_external.object({ enabled: exports_external.boolean().optional() }).optional(),
37102
37103
  rules: exports_external.record(exports_external.string(), SeveritySchema).optional(),
37103
37104
  hooks: exports_external.array(exports_external.string()).optional(),
37104
37105
  observer: exports_external.object({
37105
37106
  enabled: exports_external.boolean().optional(),
37106
- mode: exports_external.enum(["off", "suggest", "enforce"]).optional(),
37107
+ mode: exports_external.enum(["off", "suggest"]).optional(),
37107
37108
  model: exports_external.string().optional(),
37108
- timeoutMs: exports_external.number().int().positive().optional()
37109
+ timeoutMs: exports_external.number().int().positive().optional(),
37110
+ watchTools: exports_external.array(exports_external.string()).optional()
37109
37111
  }).optional()
37110
37112
  });
37111
37113
  });
@@ -37172,17 +37174,274 @@ var init_harness = __esm(() => {
37172
37174
  PLAN_MODE_HINT = /plan file|create your plan at|Plan mode is active|Plan mode still active/i;
37173
37175
  });
37174
37176
 
37177
+ // src/behavior/journal.ts
37178
+ import { appendFile as appendFile2, mkdir, stat } from "fs/promises";
37179
+ import { homedir as homedir17 } from "os";
37180
+ import { dirname as dirname6, join as join17 } from "path";
37181
+ function classifyPath(observed, expected) {
37182
+ if (!observed)
37183
+ return "not_applicable";
37184
+ if (!expected)
37185
+ return "no_expectation";
37186
+ if (observed === expected)
37187
+ return "as_expected";
37188
+ const dirOf = (p) => p.slice(0, Math.max(0, p.lastIndexOf("/")));
37189
+ return dirOf(observed) === dirOf(expected) ? "same_dir_wrong_name" : "outside_expected_dir";
37190
+ }
37191
+ function journalPath() {
37192
+ return join17(homedir17(), ".claudish", "behavior-journal.jsonl");
37193
+ }
37194
+ async function recordDecision(entry, path = journalPath()) {
37195
+ try {
37196
+ const size = await stat(path).then((s) => s.size, () => 0);
37197
+ if (size > MAX_JOURNAL_BYTES) {
37198
+ if (!capWarned) {
37199
+ capWarned = true;
37200
+ log(`[behavior:journal] ${path} exceeded ${Math.round(MAX_JOURNAL_BYTES / 1e6)}MB \u2014 ` + "no longer recording. Archive or delete it to resume.");
37201
+ }
37202
+ return;
37203
+ }
37204
+ if (size === 0)
37205
+ await mkdir(dirname6(path), { recursive: true }).catch(() => {});
37206
+ await appendFile2(path, `${JSON.stringify(entry)}
37207
+ `);
37208
+ } catch (err) {
37209
+ log(`[behavior:journal] could not record: ${err}`);
37210
+ }
37211
+ }
37212
+ var MAX_JOURNAL_BYTES, capWarned = false;
37213
+ var init_journal = __esm(() => {
37214
+ init_logger();
37215
+ MAX_JOURNAL_BYTES = 32 * 1024 * 1024;
37216
+ });
37217
+
37218
+ // src/behavior/observer/digest.ts
37219
+ var exports_digest = {};
37220
+ __export(exports_digest, {
37221
+ buildDigest: () => buildDigest
37222
+ });
37223
+ function buildDigest(params) {
37224
+ const digest = {
37225
+ model: params.model,
37226
+ toolNames: params.toolNames.slice(0, MAX_TOOL_NAMES),
37227
+ harness: params.harness,
37228
+ ruleVocabulary: params.ruleVocabulary
37229
+ };
37230
+ if (params.call) {
37231
+ const paths = [];
37232
+ for (const [key, value] of Object.entries(params.call.args)) {
37233
+ if (PATH_KEYS.has(key) && typeof value === "string")
37234
+ paths.push(value);
37235
+ }
37236
+ digest.proposedCall = {
37237
+ name: params.call.name,
37238
+ argKeys: Object.keys(params.call.args),
37239
+ paths: paths.length > 0 ? paths : undefined
37240
+ };
37241
+ }
37242
+ return digest;
37243
+ }
37244
+ var MAX_TOOL_NAMES = 40, PATH_KEYS;
37245
+ var init_digest = __esm(() => {
37246
+ PATH_KEYS = new Set(["file_path", "path", "notebook_path", "filePath"]);
37247
+ });
37248
+
37249
+ // src/providers/ollama-discovery.ts
37250
+ function ollamaBaseUrl() {
37251
+ return process.env.OLLAMA_HOST || process.env.OLLAMA_BASE_URL || "http://localhost:11434";
37252
+ }
37253
+ async function fetchOllamaModels(options = {}) {
37254
+ const { enrichCapabilities = true } = options;
37255
+ const host = ollamaBaseUrl();
37256
+ try {
37257
+ const response = await fetch(`${host}/api/tags`, {
37258
+ signal: AbortSignal.timeout(3000)
37259
+ });
37260
+ if (!response.ok)
37261
+ return [];
37262
+ const data = await response.json();
37263
+ const models = data.models || [];
37264
+ const enriched = await Promise.all(models.map(async (m) => {
37265
+ let capabilities = [];
37266
+ if (enrichCapabilities) {
37267
+ try {
37268
+ const showResponse = await fetch(`${host}/api/show`, {
37269
+ method: "POST",
37270
+ headers: { "Content-Type": "application/json" },
37271
+ body: JSON.stringify({ name: m.name }),
37272
+ signal: AbortSignal.timeout(2000)
37273
+ });
37274
+ if (showResponse.ok) {
37275
+ const showData = await showResponse.json();
37276
+ capabilities = showData.capabilities || [];
37277
+ }
37278
+ } catch {}
37279
+ }
37280
+ const nameLower = String(m.name).toLowerCase();
37281
+ const supportsTools = capabilities.includes("tools");
37282
+ const isEmbeddingModel = capabilities.includes("embedding") || nameLower.includes("embed");
37283
+ const sizeInfo = m.details?.parameter_size || "unknown size";
37284
+ const toolsIndicator = supportsTools ? "\u2713 tools" : "\u2717 no tools";
37285
+ return {
37286
+ id: `ollama/${m.name}`,
37287
+ name: m.name,
37288
+ description: `Local Ollama model (${sizeInfo}, ${toolsIndicator})`,
37289
+ provider: "ollama",
37290
+ pricing: { prompt: "0", completion: "0" },
37291
+ isLocal: true,
37292
+ supportsTools,
37293
+ isEmbeddingModel,
37294
+ capabilities,
37295
+ details: m.details,
37296
+ size: m.size
37297
+ };
37298
+ }));
37299
+ return enriched.filter((m) => !m.isEmbeddingModel);
37300
+ } catch {
37301
+ return [];
37302
+ }
37303
+ }
37304
+
37305
+ // src/behavior/observer/client.ts
37306
+ var exports_client = {};
37307
+ __export(exports_client, {
37308
+ resetObserverModelCache: () => resetObserverModelCache,
37309
+ observe: () => observe
37310
+ });
37311
+ function isGenuinelyLocal(model) {
37312
+ if (/[-:]cloud$/i.test(model.name))
37313
+ return false;
37314
+ return (model.size ?? 0) >= MIN_LOCAL_MODEL_BYTES;
37315
+ }
37316
+ async function resolveObserverModel(config2) {
37317
+ if (config2.observer?.model)
37318
+ return config2.observer.model;
37319
+ if (cachedModel !== undefined)
37320
+ return cachedModel;
37321
+ try {
37322
+ const models = await fetchOllamaModels({ enrichCapabilities: false });
37323
+ const usable = models.filter((m) => !m.isEmbeddingModel && isGenuinelyLocal(m));
37324
+ if (usable.length === 0) {
37325
+ log("[behavior:observer] No local Ollama models found \u2014 observer disabled for this run");
37326
+ cachedModel = null;
37327
+ return null;
37328
+ }
37329
+ usable.sort((a, b) => (a.size ?? Number.MAX_SAFE_INTEGER) - (b.size ?? Number.MAX_SAFE_INTEGER));
37330
+ cachedModel = usable[0].name;
37331
+ log(`[behavior:observer] Using discovered local model: ${cachedModel}`);
37332
+ return cachedModel;
37333
+ } catch (err) {
37334
+ log(`[behavior:observer] Model discovery failed, observer disabled: ${err}`);
37335
+ cachedModel = null;
37336
+ return null;
37337
+ }
37338
+ }
37339
+ function resetObserverModelCache() {
37340
+ cachedModel = undefined;
37341
+ }
37342
+ async function observe(digest, config2) {
37343
+ const mode = config2.observer?.mode ?? "suggest";
37344
+ if (config2.observer?.enabled !== true || mode === "off")
37345
+ return null;
37346
+ const model = await resolveObserverModel(config2);
37347
+ if (!model)
37348
+ return null;
37349
+ const timeoutMs = config2.observer?.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
37350
+ try {
37351
+ const response = await fetch(`${ollamaBaseUrl()}/api/chat`, {
37352
+ method: "POST",
37353
+ headers: { "Content-Type": "application/json" },
37354
+ signal: AbortSignal.timeout(timeoutMs),
37355
+ body: JSON.stringify({
37356
+ model,
37357
+ stream: false,
37358
+ format: "json",
37359
+ options: { temperature: 0 },
37360
+ messages: [
37361
+ { role: "system", content: SYSTEM_PROMPT },
37362
+ { role: "user", content: JSON.stringify(digest) }
37363
+ ]
37364
+ })
37365
+ });
37366
+ if (!response.ok) {
37367
+ log(`[behavior:observer] HTTP ${response.status} \u2014 skipping`);
37368
+ return null;
37369
+ }
37370
+ const body = await response.json();
37371
+ const content = body?.message?.content;
37372
+ if (typeof content !== "string")
37373
+ return null;
37374
+ const parsed = JSON.parse(content);
37375
+ const ruleId = typeof parsed?.ruleId === "string" ? parsed.ruleId : null;
37376
+ if (ruleId && !digest.ruleVocabulary.includes(ruleId)) {
37377
+ log(`[behavior:observer] Discarding unknown ruleId "${ruleId}"`);
37378
+ return null;
37379
+ }
37380
+ return {
37381
+ ruleId,
37382
+ confidence: typeof parsed?.confidence === "number" ? parsed.confidence : 0,
37383
+ note: typeof parsed?.note === "string" ? parsed.note : undefined
37384
+ };
37385
+ } catch (err) {
37386
+ log(`[behavior:observer] Skipped: ${err instanceof Error ? err.message : err}`);
37387
+ return null;
37388
+ }
37389
+ }
37390
+ var DEFAULT_TIMEOUT_MS2 = 1500, SYSTEM_PROMPT = `You audit an AI coding agent for violations of Claude Code's conventions.
37391
+ You receive a JSON digest: the tools available, detected harness state, and the tool call the agent proposes.
37392
+ Decide whether the proposed call violates one of the rules listed in ruleVocabulary.
37393
+
37394
+ Reply with ONLY a JSON object, no prose:
37395
+ {"ruleId": "<id from ruleVocabulary, or null>", "confidence": <0-1>, "note": "<short reason>"}
37396
+
37397
+ Return ruleId null unless you are confident. A false positive is worse than a miss.`, MIN_LOCAL_MODEL_BYTES, cachedModel;
37398
+ var init_client = __esm(() => {
37399
+ init_logger();
37400
+ MIN_LOCAL_MODEL_BYTES = 50 * 1024 * 1024;
37401
+ });
37402
+
37403
+ // src/behavior/observer/live-log.ts
37404
+ var exports_live_log = {};
37405
+ __export(exports_live_log, {
37406
+ recordLiveDivergence: () => recordLiveDivergence
37407
+ });
37408
+ import { appendFile as appendFile3 } from "fs/promises";
37409
+ import { homedir as homedir18 } from "os";
37410
+ import { join as join18 } from "path";
37411
+ function defaultPath() {
37412
+ return join18(homedir18(), ".claudish", "behavior-divergences.jsonl");
37413
+ }
37414
+ async function recordLiveDivergence(entry, path = defaultPath()) {
37415
+ try {
37416
+ await appendFile3(path, `${JSON.stringify(entry)}
37417
+ `);
37418
+ } catch (err) {
37419
+ log(`[behavior:observer] could not append divergence: ${err}`);
37420
+ }
37421
+ }
37422
+ var init_live_log = __esm(() => {
37423
+ init_logger();
37424
+ });
37425
+
37175
37426
  // src/behavior/engine.ts
37176
37427
  class BehaviorSession {
37177
37428
  active;
37178
37429
  modelId;
37179
37430
  providerName;
37431
+ config;
37180
37432
  facts = { planModeActive: false };
37181
37433
  bufferedTools = new Set;
37182
- constructor(active, modelId, providerName) {
37434
+ constructor(active, modelId, providerName, config2 = {}) {
37183
37435
  this.active = active;
37184
37436
  this.modelId = modelId;
37185
37437
  this.providerName = providerName;
37438
+ this.config = config2;
37439
+ }
37440
+ get observerOn() {
37441
+ return this.config.observer?.enabled === true && (this.config.observer.mode ?? "suggest") !== "off";
37442
+ }
37443
+ observerWatchList() {
37444
+ return this.config.observer?.watchTools ?? ["Write", "Edit", "NotebookEdit", "ExitPlanMode"];
37186
37445
  }
37187
37446
  armBuffering() {
37188
37447
  const armed = new Set;
@@ -37194,6 +37453,10 @@ class BehaviorSession {
37194
37453
  for (const t of rule.interceptsTools ?? [])
37195
37454
  armed.add(t);
37196
37455
  }
37456
+ if (this.observerOn) {
37457
+ for (const t of this.observerWatchList())
37458
+ armed.add(t);
37459
+ }
37197
37460
  this.bufferedTools = armed;
37198
37461
  }
37199
37462
  get harness() {
@@ -37275,13 +37538,80 @@ class BehaviorSession {
37275
37538
  log(`[behavior] ${rule.id} (warn-only, not applied): ${action.reason}`);
37276
37539
  continue;
37277
37540
  }
37541
+ this.journal("tool_call", "repaired", {
37542
+ ruleId: rule.id,
37543
+ toolName,
37544
+ argKeys: Object.keys(args),
37545
+ observedPath: typeof args.file_path === "string" ? args.file_path : undefined,
37546
+ expectedPath: this.facts.planFilePath,
37547
+ note: action.reason
37548
+ });
37278
37549
  args = action.args;
37279
37550
  changed = true;
37280
37551
  log(`[behavior] ${rule.id} repaired ${toolName}: ${action.reason}`);
37281
37552
  }
37282
37553
  }
37554
+ if (!changed) {
37555
+ this.journal("tool_call", "ignored", {
37556
+ toolName,
37557
+ argKeys: Object.keys(args),
37558
+ observedPath: typeof args.file_path === "string" ? args.file_path : undefined,
37559
+ expectedPath: this.facts.planFilePath
37560
+ });
37561
+ }
37562
+ if (this.observerOn && !changed) {
37563
+ this.consultObserver(toolName, args);
37564
+ }
37283
37565
  return changed ? JSON.stringify(args) : null;
37284
37566
  }
37567
+ journal(surface, decision, detail) {
37568
+ recordDecision({
37569
+ ts: new Date().toISOString(),
37570
+ model: this.modelId,
37571
+ provider: this.providerName,
37572
+ surface,
37573
+ decision,
37574
+ ruleId: detail.ruleId,
37575
+ toolName: detail.toolName,
37576
+ argKeys: detail.argKeys,
37577
+ pathRelation: classifyPath(detail.observedPath, detail.expectedPath),
37578
+ local: {
37579
+ observedPath: detail.observedPath,
37580
+ expectedPath: detail.expectedPath,
37581
+ note: detail.note
37582
+ }
37583
+ });
37584
+ }
37585
+ async consultObserver(toolName, args) {
37586
+ try {
37587
+ const { buildDigest: buildDigest2 } = await Promise.resolve().then(() => (init_digest(), exports_digest));
37588
+ const { observe: observe2 } = await Promise.resolve().then(() => (init_client(), exports_client));
37589
+ const { recordLiveDivergence: recordLiveDivergence2 } = await Promise.resolve().then(() => (init_live_log(), exports_live_log));
37590
+ const digest = buildDigest2({
37591
+ model: this.modelId,
37592
+ toolNames: [...this.bufferedTools],
37593
+ harness: this.facts,
37594
+ ruleVocabulary: this.active.map((a) => a.rule.id),
37595
+ call: { name: toolName, args }
37596
+ });
37597
+ const verdict = await observe2(digest, this.config);
37598
+ if (!verdict?.ruleId)
37599
+ return;
37600
+ log(`[behavior:observer] flagged ${toolName} as ${verdict.ruleId} (confidence ${verdict.confidence})${verdict.note ? `: ${verdict.note}` : ""}`);
37601
+ await recordLiveDivergence2({
37602
+ source: "observer",
37603
+ ts: new Date().toISOString(),
37604
+ model: this.modelId,
37605
+ toolName,
37606
+ ruleId: verdict.ruleId,
37607
+ confidence: verdict.confidence,
37608
+ note: verdict.note,
37609
+ paths: digest.proposedCall?.paths
37610
+ });
37611
+ } catch (err) {
37612
+ log(`[behavior:observer] consult failed: ${err}`);
37613
+ }
37614
+ }
37285
37615
  applyAction(ruleId, severity, action, ctx) {
37286
37616
  if (action.type === "warn") {
37287
37617
  log(`[behavior] ${ruleId} (warn): ${action.message}`);
@@ -37359,13 +37689,14 @@ class BehaviorEngine {
37359
37689
  if (active.length > 0) {
37360
37690
  log(`[behavior] ${active.length} rule(s) active for ${params.modelId}: ` + active.map((a) => `${a.rule.id}=${a.severity}`).join(", "));
37361
37691
  }
37362
- return new BehaviorSession(active, params.modelId, params.providerName);
37692
+ return new BehaviorSession(active, params.modelId, params.providerName, this.config);
37363
37693
  }
37364
37694
  }
37365
37695
  var init_engine = __esm(() => {
37366
37696
  init_logger();
37367
37697
  init_config();
37368
37698
  init_harness();
37699
+ init_journal();
37369
37700
  });
37370
37701
 
37371
37702
  // src/behavior/rules/plan-mode.ts
@@ -37497,75 +37828,118 @@ var init_hooks = __esm(() => {
37497
37828
  init_logger();
37498
37829
  });
37499
37830
 
37500
- // src/behavior/observer/digest.ts
37501
- var PATH_KEYS;
37502
- var init_digest = __esm(() => {
37503
- PATH_KEYS = new Set(["file_path", "path", "notebook_path", "filePath"]);
37504
- });
37505
-
37506
- // src/providers/ollama-discovery.ts
37507
- function ollamaBaseUrl() {
37508
- return process.env.OLLAMA_HOST || process.env.OLLAMA_BASE_URL || "http://localhost:11434";
37831
+ // src/behavior/observer/corpus.ts
37832
+ import { appendFileSync as appendFileSync3, readFileSync as readFileSync12, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
37833
+ import { homedir as homedir19 } from "os";
37834
+ import { join as join19 } from "path";
37835
+ function directoryOf2(filePath) {
37836
+ const slash = filePath.lastIndexOf("/");
37837
+ return slash > 0 ? filePath.slice(0, slash) : undefined;
37509
37838
  }
37510
- async function fetchOllamaModels(options = {}) {
37511
- const { enrichCapabilities = true } = options;
37512
- const host = ollamaBaseUrl();
37839
+ function writeTargetsOf(row) {
37840
+ const content = row?.message?.content;
37841
+ if (!Array.isArray(content))
37842
+ return [];
37843
+ const paths = [];
37844
+ for (const block of content) {
37845
+ if (block?.type !== "tool_use" || !WRITE_TOOLS2.has(block.name))
37846
+ continue;
37847
+ const p = block.input?.file_path;
37848
+ if (typeof p === "string")
37849
+ paths.push(p);
37850
+ }
37851
+ return paths;
37852
+ }
37853
+ function replayTranscript(file2) {
37854
+ let text;
37513
37855
  try {
37514
- const response = await fetch(`${host}/api/tags`, {
37515
- signal: AbortSignal.timeout(3000)
37516
- });
37517
- if (!response.ok)
37518
- return [];
37519
- const data = await response.json();
37520
- const models = data.models || [];
37521
- const enriched = await Promise.all(models.map(async (m) => {
37522
- let capabilities = [];
37523
- if (enrichCapabilities) {
37524
- try {
37525
- const showResponse = await fetch(`${host}/api/show`, {
37526
- method: "POST",
37527
- headers: { "Content-Type": "application/json" },
37528
- body: JSON.stringify({ name: m.name }),
37529
- signal: AbortSignal.timeout(2000)
37530
- });
37531
- if (showResponse.ok) {
37532
- const showData = await showResponse.json();
37533
- capabilities = showData.capabilities || [];
37534
- }
37535
- } catch {}
37536
- }
37537
- const nameLower = String(m.name).toLowerCase();
37538
- const supportsTools = capabilities.includes("tools");
37539
- const isEmbeddingModel = capabilities.includes("embedding") || nameLower.includes("embed");
37540
- const sizeInfo = m.details?.parameter_size || "unknown size";
37541
- const toolsIndicator = supportsTools ? "\u2713 tools" : "\u2717 no tools";
37542
- return {
37543
- id: `ollama/${m.name}`,
37544
- name: m.name,
37545
- description: `Local Ollama model (${sizeInfo}, ${toolsIndicator})`,
37546
- provider: "ollama",
37547
- pricing: { prompt: "0", completion: "0" },
37548
- isLocal: true,
37549
- supportsTools,
37550
- isEmbeddingModel,
37551
- capabilities,
37552
- details: m.details,
37553
- size: m.size
37554
- };
37555
- }));
37556
- return enriched.filter((m) => !m.isEmbeddingModel);
37856
+ text = readFileSync12(file2, "utf8");
37557
37857
  } catch {
37558
37858
  return [];
37559
37859
  }
37860
+ if (!text.includes("ExitPlanMode"))
37861
+ return [];
37862
+ const out = [];
37863
+ const planWrites = [];
37864
+ let lastModel;
37865
+ for (const line of text.split(`
37866
+ `)) {
37867
+ if (!line)
37868
+ continue;
37869
+ let row;
37870
+ try {
37871
+ row = JSON.parse(line);
37872
+ } catch {
37873
+ continue;
37874
+ }
37875
+ if (row?.message?.role === "assistant" && typeof row?.message?.model === "string") {
37876
+ lastModel = row.message.model;
37877
+ }
37878
+ planWrites.push(...writeTargetsOf(row));
37879
+ const record4 = divergenceOf(row, file2, planWrites, lastModel);
37880
+ if (record4)
37881
+ out.push(record4);
37882
+ }
37883
+ return out;
37560
37884
  }
37561
-
37562
- // src/behavior/observer/client.ts
37563
- var init_client = __esm(() => {
37564
- init_logger();
37565
- });
37566
-
37567
- // src/behavior/observer/corpus.ts
37568
- var WRITE_TOOLS2;
37885
+ function divergenceOf(row, file2, planWrites, lastModel) {
37886
+ const result = row?.toolUseResult;
37887
+ if (!result || typeof result !== "object")
37888
+ return null;
37889
+ if (!("plan" in result) || typeof result.filePath !== "string")
37890
+ return null;
37891
+ const assignedPath = result.filePath;
37892
+ const planDir = directoryOf2(assignedPath);
37893
+ const observedPaths = planDir ? [...new Set(planWrites.filter((p) => directoryOf2(p) === planDir && p !== assignedPath))] : [];
37894
+ return {
37895
+ transcript: file2,
37896
+ timestamp: row?.timestamp,
37897
+ model: row?.message?.model ?? lastModel,
37898
+ ruleId: RULE_ID,
37899
+ assignedPath,
37900
+ observedPaths,
37901
+ outcome: result.plan === null ? "degraded" : "ok"
37902
+ };
37903
+ }
37904
+ function listTranscripts(root) {
37905
+ const files = [];
37906
+ let projects;
37907
+ try {
37908
+ projects = readdirSync2(root);
37909
+ } catch {
37910
+ return files;
37911
+ }
37912
+ for (const project of projects) {
37913
+ const dir = join19(root, project);
37914
+ try {
37915
+ if (!statSync2(dir).isDirectory())
37916
+ continue;
37917
+ for (const f of readdirSync2(dir)) {
37918
+ if (f.endsWith(".jsonl"))
37919
+ files.push(join19(dir, f));
37920
+ }
37921
+ } catch {}
37922
+ }
37923
+ return files;
37924
+ }
37925
+ function buildCorpus(options = {}) {
37926
+ const root = options.projectsRoot ?? join19(homedir19(), ".claude", "projects");
37927
+ const files = listTranscripts(root);
37928
+ const records = [];
37929
+ for (const f of files)
37930
+ records.push(...replayTranscript(f));
37931
+ if (options.write && records.length > 0) {
37932
+ const outputPath = options.outputPath ?? join19(homedir19(), ".claudish", "behavior-divergences.jsonl");
37933
+ try {
37934
+ appendFileSync3(outputPath, `${records.map((r) => JSON.stringify(r)).join(`
37935
+ `)}
37936
+ `);
37937
+ return { scanned: files.length, records, outputPath };
37938
+ } catch {}
37939
+ }
37940
+ return { scanned: files.length, records };
37941
+ }
37942
+ var RULE_ID = "plan-mode/plan-file-path", WRITE_TOOLS2;
37569
37943
  var init_corpus = __esm(() => {
37570
37944
  WRITE_TOOLS2 = new Set(["Write", "Edit", "NotebookEdit"]);
37571
37945
  });
@@ -37979,7 +38353,7 @@ var init_openai = __esm(() => {
37979
38353
  });
37980
38354
 
37981
38355
  // src/providers/catalog-query.ts
37982
- import { statSync as statSync2 } from "fs";
38356
+ import { statSync as statSync3 } from "fs";
37983
38357
  function project(entry) {
37984
38358
  return {
37985
38359
  modelId: entry.modelId,
@@ -37992,7 +38366,7 @@ function project(entry) {
37992
38366
  function getCachedEntries() {
37993
38367
  let mtimeMs;
37994
38368
  try {
37995
- mtimeMs = statSync2(ALL_MODELS_CACHE_PATH).mtimeMs;
38369
+ mtimeMs = statSync3(ALL_MODELS_CACHE_PATH).mtimeMs;
37996
38370
  } catch {
37997
38371
  return null;
37998
38372
  }
@@ -38168,13 +38542,13 @@ var init_vision_proxy = __esm(() => {
38168
38542
  import {
38169
38543
  existsSync as existsSync14,
38170
38544
  mkdirSync as mkdirSync9,
38171
- readFileSync as readFileSync12,
38545
+ readFileSync as readFileSync13,
38172
38546
  renameSync,
38173
38547
  unlinkSync as unlinkSync5,
38174
38548
  writeFileSync as writeFileSync9
38175
38549
  } from "fs";
38176
- import { homedir as homedir17 } from "os";
38177
- import { join as join17 } from "path";
38550
+ import { homedir as homedir20 } from "os";
38551
+ import { join as join20 } from "path";
38178
38552
  function ensureDir() {
38179
38553
  if (!existsSync14(CLAUDISH_DIR)) {
38180
38554
  mkdirSync9(CLAUDISH_DIR, { recursive: true });
@@ -38184,7 +38558,7 @@ function readFromDisk() {
38184
38558
  try {
38185
38559
  if (!existsSync14(BUFFER_FILE))
38186
38560
  return [];
38187
- const raw2 = readFileSync12(BUFFER_FILE, "utf-8");
38561
+ const raw2 = readFileSync13(BUFFER_FILE, "utf-8");
38188
38562
  const parsed = JSON.parse(raw2);
38189
38563
  if (!Array.isArray(parsed.events))
38190
38564
  return [];
@@ -38209,7 +38583,7 @@ function writeToDisk(events) {
38209
38583
  ensureDir();
38210
38584
  const trimmed = enforceSizeCap([...events]);
38211
38585
  const payload = { version: 1, events: trimmed };
38212
- const tmpFile = join17(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
38586
+ const tmpFile = join20(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
38213
38587
  writeFileSync9(tmpFile, JSON.stringify(payload, null, 2), "utf-8");
38214
38588
  renameSync(tmpFile, BUFFER_FILE);
38215
38589
  memoryCache = trimmed;
@@ -38282,8 +38656,8 @@ function syncFlushOnExit() {
38282
38656
  var BUFFER_MAX_BYTES, CLAUDISH_DIR, BUFFER_FILE, memoryCache = null, eventsSinceLastFlush = 0, flushScheduled = false;
38283
38657
  var init_stats_buffer = __esm(() => {
38284
38658
  BUFFER_MAX_BYTES = 64 * 1024;
38285
- CLAUDISH_DIR = join17(homedir17(), ".claudish");
38286
- BUFFER_FILE = join17(CLAUDISH_DIR, "stats-buffer.json");
38659
+ CLAUDISH_DIR = join20(homedir20(), ".claudish");
38660
+ BUFFER_FILE = join20(CLAUDISH_DIR, "stats-buffer.json");
38287
38661
  process.on("exit", syncFlushOnExit);
38288
38662
  process.on("SIGTERM", () => {
38289
38663
  try {
@@ -40564,8 +40938,8 @@ var init_openai_responses_sse = __esm(() => {
40564
40938
 
40565
40939
  // src/handlers/shared/token-tracker.ts
40566
40940
  import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
40567
- import { homedir as homedir18 } from "os";
40568
- import { dirname as dirname6, join as join18 } from "path";
40941
+ import { homedir as homedir21 } from "os";
40942
+ import { dirname as dirname7, join as join21 } from "path";
40569
40943
 
40570
40944
  class TokenTracker {
40571
40945
  port;
@@ -40709,8 +41083,8 @@ class TokenTracker {
40709
41083
  data.quota_remaining = this.quotaRemaining;
40710
41084
  }
40711
41085
  const override = process.env.CLAUDISH_TOKEN_FILE;
40712
- const outPath = override || join18(homedir18(), ".claudish", `tokens-${this.port}.json`);
40713
- mkdirSync10(dirname6(outPath), { recursive: true });
41086
+ const outPath = override || join21(homedir21(), ".claudish", `tokens-${this.port}.json`);
41087
+ mkdirSync10(dirname7(outPath), { recursive: true });
40714
41088
  writeFileSync10(outPath, JSON.stringify(data), "utf-8");
40715
41089
  } catch (e) {
40716
41090
  log(`[TokenTracker] Error writing token file: ${e}`);
@@ -41556,7 +41930,7 @@ var init_fallback_handler = __esm(() => {
41556
41930
  });
41557
41931
 
41558
41932
  // src/handlers/native-handler-advisor.ts
41559
- import { appendFileSync as appendFileSync3 } from "fs";
41933
+ import { appendFileSync as appendFileSync4 } from "fs";
41560
41934
  function loadAdvisorSwapConfig(cliModels, cliCollector) {
41561
41935
  return {
41562
41936
  enabled: process.env.CLAUDISH_SWAP_ADVISOR === "1" || (cliModels?.length ?? 0) > 0,
@@ -41611,7 +41985,7 @@ function logAdvisorEvent(cfg, event) {
41611
41985
  const line = `${JSON.stringify({ ts: new Date().toISOString(), ...event })}
41612
41986
  `;
41613
41987
  try {
41614
- appendFileSync3(cfg.logPath, line);
41988
+ appendFileSync4(cfg.logPath, line);
41615
41989
  } catch {}
41616
41990
  }
41617
41991
  function recordAdvisorEventsFromChunk(cfg, chunkText) {
@@ -43214,11 +43588,11 @@ var init_ollama_api_format = __esm(() => {
43214
43588
  });
43215
43589
 
43216
43590
  // src/providers/api-key-provenance.ts
43217
- import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
43218
- import { homedir as homedir19 } from "os";
43219
- import { join as join19, resolve as resolve2 } from "path";
43591
+ import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
43592
+ import { homedir as homedir22 } from "os";
43593
+ import { join as join22, resolve as resolve2 } from "path";
43220
43594
  function activeConfigPath() {
43221
- return activeGlobalConfigFile(join19(homedir19(), ".claudish", "config.json"));
43595
+ return activeGlobalConfigFile(join22(homedir22(), ".claudish", "config.json"));
43222
43596
  }
43223
43597
  function configLayerLabel() {
43224
43598
  return getConfigFileOverride() ? activeConfigPath() : "~/.claudish/config.json";
@@ -43297,7 +43671,7 @@ function readDotenvKey(envVars) {
43297
43671
  const dotenvPath = resolve2(".env");
43298
43672
  if (!existsSync15(dotenvPath))
43299
43673
  return null;
43300
- const parsed = import_dotenv.parse(readFileSync13(dotenvPath, "utf-8"));
43674
+ const parsed = import_dotenv.parse(readFileSync14(dotenvPath, "utf-8"));
43301
43675
  for (const v of envVars) {
43302
43676
  if (parsed[v])
43303
43677
  return parsed[v];
@@ -43312,7 +43686,7 @@ function readConfigKey(envVar) {
43312
43686
  const configPath = activeConfigPath();
43313
43687
  if (!existsSync15(configPath))
43314
43688
  return null;
43315
- const cfg = JSON.parse(readFileSync13(configPath, "utf-8"));
43689
+ const cfg = JSON.parse(readFileSync14(configPath, "utf-8"));
43316
43690
  return cfg.apiKeys?.[envVar] || null;
43317
43691
  } catch {
43318
43692
  return null;
@@ -44870,9 +45244,9 @@ var init_poe = __esm(() => {
44870
45244
  });
44871
45245
 
44872
45246
  // src/services/pricing-cache.ts
44873
- import { existsSync as existsSync16, readFileSync as readFileSync14, statSync as statSync3 } from "fs";
44874
- import { homedir as homedir20 } from "os";
44875
- import { join as join20 } from "path";
45247
+ import { existsSync as existsSync16, readFileSync as readFileSync15, statSync as statSync4 } from "fs";
45248
+ import { homedir as homedir23 } from "os";
45249
+ import { join as join23 } from "path";
44876
45250
  function prefixMatch(modelName) {
44877
45251
  for (const [key, pricing] of pricingMap) {
44878
45252
  if (modelName.startsWith(key))
@@ -44912,10 +45286,10 @@ function loadDiskCache() {
44912
45286
  try {
44913
45287
  if (!existsSync16(CACHE_FILE))
44914
45288
  return false;
44915
- const stat = statSync3(CACHE_FILE);
44916
- const age = Date.now() - stat.mtimeMs;
45289
+ const stat2 = statSync4(CACHE_FILE);
45290
+ const age = Date.now() - stat2.mtimeMs;
44917
45291
  const isFresh = age < CACHE_TTL_MS2;
44918
- const raw2 = readFileSync14(CACHE_FILE, "utf-8");
45292
+ const raw2 = readFileSync15(CACHE_FILE, "utf-8");
44919
45293
  const data = JSON.parse(raw2);
44920
45294
  for (const [key, pricing] of Object.entries(data)) {
44921
45295
  pricingMap.set(key, pricing);
@@ -44931,8 +45305,8 @@ var init_pricing_cache = __esm(() => {
44931
45305
  init_logger();
44932
45306
  init_catalog_query();
44933
45307
  pricingMap = new Map;
44934
- CACHE_DIR = join20(homedir20(), ".claudish");
44935
- CACHE_FILE = join20(CACHE_DIR, "pricing-cache.json");
45308
+ CACHE_DIR = join23(homedir23(), ".claudish");
45309
+ CACHE_FILE = join23(CACHE_DIR, "pricing-cache.json");
44936
45310
  CACHE_TTL_MS2 = 24 * 60 * 60 * 1000;
44937
45311
  });
44938
45312
 
@@ -45389,20 +45763,20 @@ var init_proxy_server = __esm(() => {
45389
45763
  });
45390
45764
 
45391
45765
  // src/team-stats.ts
45392
- import { existsSync as existsSync17, readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "fs";
45393
- import { join as join21 } from "path";
45766
+ import { existsSync as existsSync17, readFileSync as readFileSync16, writeFileSync as writeFileSync11 } from "fs";
45767
+ import { join as join24 } from "path";
45394
45768
  function statsDir(sessionPath) {
45395
- return join21(sessionPath, "stats");
45769
+ return join24(sessionPath, "stats");
45396
45770
  }
45397
45771
  function tokenFileFor(sessionPath, anonId) {
45398
- return join21(statsDir(sessionPath), `${anonId}.json`);
45772
+ return join24(statsDir(sessionPath), `${anonId}.json`);
45399
45773
  }
45400
45774
  function readTokenStats(sessionPath, anonId) {
45401
45775
  const path = tokenFileFor(sessionPath, anonId);
45402
45776
  if (!existsSync17(path))
45403
45777
  return null;
45404
45778
  try {
45405
- return JSON.parse(readFileSync15(path, "utf-8"));
45779
+ return JSON.parse(readFileSync16(path, "utf-8"));
45406
45780
  } catch {
45407
45781
  return null;
45408
45782
  }
@@ -45550,7 +45924,7 @@ ${segs.join(" \xB7 ")}`;
45550
45924
  }
45551
45925
  function writeStatusFile(sessionPath, manifest, status, opts) {
45552
45926
  try {
45553
- writeFileSync11(join21(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
45927
+ writeFileSync11(join24(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
45554
45928
  `, "utf-8");
45555
45929
  } catch {}
45556
45930
  }
@@ -45578,11 +45952,11 @@ import {
45578
45952
  createWriteStream as createWriteStream2,
45579
45953
  existsSync as existsSync18,
45580
45954
  mkdirSync as mkdirSync11,
45581
- readFileSync as readFileSync16,
45582
- readdirSync as readdirSync2,
45955
+ readFileSync as readFileSync17,
45956
+ readdirSync as readdirSync3,
45583
45957
  writeFileSync as writeFileSync12
45584
45958
  } from "fs";
45585
- import { join as join22, resolve as resolve3 } from "path";
45959
+ import { join as join25, resolve as resolve3 } from "path";
45586
45960
  function classifyRunOutput(opts) {
45587
45961
  const { outputSize, stdoutTail, stderr, minOutputBytes } = opts;
45588
45962
  const apiError = API_ERROR_RE.exec(stdoutTail);
@@ -45643,18 +46017,18 @@ function setupSession(sessionPath, models, input) {
45643
46017
  if (models.length === 0) {
45644
46018
  throw new Error("At least one model is required");
45645
46019
  }
45646
- if (existsSync18(join22(sessionPath, "manifest.json"))) {
46020
+ if (existsSync18(join25(sessionPath, "manifest.json"))) {
45647
46021
  throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
45648
46022
  }
45649
46023
  const sentinels = models.filter(isSentinelModel);
45650
46024
  if (sentinels.length > 0) {
45651
46025
  throw new Error(`Invalid model(s) for team run: ${sentinels.join(", ")}. These are Claude Code agent selectors, not external model IDs. Use real external models (e.g., "gemini-2.0-flash", "gpt-4o", "or@deepseek/deepseek-r1"). For Claude models, use a Task agent instead of the team tool.`);
45652
46026
  }
45653
- mkdirSync11(join22(sessionPath, "work"), { recursive: true });
45654
- mkdirSync11(join22(sessionPath, "errors"), { recursive: true });
46027
+ mkdirSync11(join25(sessionPath, "work"), { recursive: true });
46028
+ mkdirSync11(join25(sessionPath, "errors"), { recursive: true });
45655
46029
  if (input !== undefined) {
45656
- writeFileSync12(join22(sessionPath, "input.md"), input, "utf-8");
45657
- } else if (!existsSync18(join22(sessionPath, "input.md"))) {
46030
+ writeFileSync12(join25(sessionPath, "input.md"), input, "utf-8");
46031
+ } else if (!existsSync18(join25(sessionPath, "input.md"))) {
45658
46032
  throw new Error(`No input.md found at ${sessionPath} and no input provided`);
45659
46033
  }
45660
46034
  const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
@@ -45671,9 +46045,9 @@ function setupSession(sessionPath, models, input) {
45671
46045
  model: models[i],
45672
46046
  assignedAt: now
45673
46047
  };
45674
- mkdirSync11(join22(sessionPath, "work", anonId), { recursive: true });
46048
+ mkdirSync11(join25(sessionPath, "work", anonId), { recursive: true });
45675
46049
  }
45676
- writeFileSync12(join22(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
46050
+ writeFileSync12(join25(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
45677
46051
  const status = {
45678
46052
  startedAt: now,
45679
46053
  models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
@@ -45687,17 +46061,17 @@ function setupSession(sessionPath, models, input) {
45687
46061
  }
45688
46062
  ]))
45689
46063
  };
45690
- writeFileSync12(join22(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
46064
+ writeFileSync12(join25(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
45691
46065
  return manifest;
45692
46066
  }
45693
46067
  async function runModels(sessionPath, opts = {}) {
45694
46068
  const timeoutMs = (opts.timeout ?? 300) * 1000;
45695
- const manifest = JSON.parse(readFileSync16(join22(sessionPath, "manifest.json"), "utf-8"));
45696
- const statusPath = join22(sessionPath, "status.json");
45697
- const inputPath = join22(sessionPath, "input.md");
45698
- const inputContent = readFileSync16(inputPath, "utf-8");
46069
+ const manifest = JSON.parse(readFileSync17(join25(sessionPath, "manifest.json"), "utf-8"));
46070
+ const statusPath = join25(sessionPath, "status.json");
46071
+ const inputPath = join25(sessionPath, "input.md");
46072
+ const inputContent = readFileSync17(inputPath, "utf-8");
45699
46073
  await prehydrateCredentialsForSpawn(Object.values(manifest.models).map((m) => m.model));
45700
- const statusCache = JSON.parse(readFileSync16(statusPath, "utf-8"));
46074
+ const statusCache = JSON.parse(readFileSync17(statusPath, "utf-8"));
45701
46075
  function updateModelStatus(id, update) {
45702
46076
  statusCache.models[id] = { ...statusCache.models[id], ...update };
45703
46077
  writeFileSync12(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
@@ -45716,8 +46090,8 @@ async function runModels(sessionPath, opts = {}) {
45716
46090
  process.on("SIGINT", sigintHandler);
45717
46091
  const completionPromises = [];
45718
46092
  for (const [anonId, entry] of Object.entries(manifest.models)) {
45719
- const outputPath = join22(sessionPath, `response-${anonId}.md`);
45720
- const errorLogPath = join22(sessionPath, "errors", `${anonId}.log`);
46093
+ const outputPath = join25(sessionPath, `response-${anonId}.md`);
46094
+ const errorLogPath = join25(sessionPath, "errors", `${anonId}.log`);
45721
46095
  const args = ["--model", entry.model, "-y", "--stdin", "--quiet", ...opts.claudeFlags ?? []];
45722
46096
  updateModelStatus(anonId, {
45723
46097
  state: "RUNNING",
@@ -45899,30 +46273,30 @@ async function runModels(sessionPath, opts = {}) {
45899
46273
  return statusCache;
45900
46274
  }
45901
46275
  async function judgeResponses(sessionPath, opts = {}) {
45902
- const responseFiles = readdirSync2(sessionPath).filter((f) => f.startsWith("response-") && f.endsWith(".md")).sort();
46276
+ const responseFiles = readdirSync3(sessionPath).filter((f) => f.startsWith("response-") && f.endsWith(".md")).sort();
45903
46277
  if (responseFiles.length < 2) {
45904
46278
  throw new Error(`Need at least 2 responses to judge, found ${responseFiles.length}`);
45905
46279
  }
45906
46280
  const responses = {};
45907
46281
  for (const file2 of responseFiles) {
45908
46282
  const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
45909
- responses[id] = readFileSync16(join22(sessionPath, file2), "utf-8");
46283
+ responses[id] = readFileSync17(join25(sessionPath, file2), "utf-8");
45910
46284
  }
45911
- const input = readFileSync16(join22(sessionPath, "input.md"), "utf-8");
46285
+ const input = readFileSync17(join25(sessionPath, "input.md"), "utf-8");
45912
46286
  const judgePrompt = buildJudgePrompt(input, responses);
45913
- writeFileSync12(join22(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
46287
+ writeFileSync12(join25(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
45914
46288
  const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
45915
- const judgePath = join22(sessionPath, "judging");
46289
+ const judgePath = join25(sessionPath, "judging");
45916
46290
  mkdirSync11(judgePath, { recursive: true });
45917
46291
  setupSession(judgePath, judgeModels, judgePrompt);
45918
46292
  await runModels(judgePath, { claudeFlags: opts.claudeFlags });
45919
46293
  const votes = parseJudgeVotes(judgePath, Object.keys(responses));
45920
46294
  const verdict = aggregateVerdict(votes, Object.keys(responses));
45921
- writeFileSync12(join22(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
46295
+ writeFileSync12(join25(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
45922
46296
  return verdict;
45923
46297
  }
45924
46298
  function getStatus(sessionPath) {
45925
- return JSON.parse(readFileSync16(join22(sessionPath, "status.json"), "utf-8"));
46299
+ return JSON.parse(readFileSync17(join25(sessionPath, "status.json"), "utf-8"));
45926
46300
  }
45927
46301
  function fisherYatesShuffle(arr) {
45928
46302
  for (let i = arr.length - 1;i > 0; i--) {
@@ -45932,7 +46306,7 @@ function fisherYatesShuffle(arr) {
45932
46306
  return arr;
45933
46307
  }
45934
46308
  function getDefaultJudgeModels(sessionPath) {
45935
- const manifest = JSON.parse(readFileSync16(join22(sessionPath, "manifest.json"), "utf-8"));
46309
+ const manifest = JSON.parse(readFileSync17(join25(sessionPath, "manifest.json"), "utf-8"));
45936
46310
  return Object.values(manifest.models).map((e) => e.model);
45937
46311
  }
45938
46312
  function buildJudgePrompt(input, responses) {
@@ -45990,12 +46364,12 @@ function buildJudgePrompt(input, responses) {
45990
46364
  }
45991
46365
  function parseJudgeVotes(judgePath, responseIds) {
45992
46366
  const votes = [];
45993
- const responseFiles = readdirSync2(judgePath).filter((f) => f.startsWith("response-") && f.endsWith(".md")).sort();
46367
+ const responseFiles = readdirSync3(judgePath).filter((f) => f.startsWith("response-") && f.endsWith(".md")).sort();
45994
46368
  for (const file2 of responseFiles) {
45995
46369
  const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
45996
46370
  let content;
45997
46371
  try {
45998
- content = readFileSync16(join22(judgePath, file2), "utf-8");
46372
+ content = readFileSync17(join25(judgePath, file2), "utf-8");
45999
46373
  } catch {
46000
46374
  continue;
46001
46375
  }
@@ -46047,7 +46421,7 @@ function aggregateVerdict(votes, responseIds) {
46047
46421
  function formatVerdict(verdict, sessionPath) {
46048
46422
  let manifest = null;
46049
46423
  try {
46050
- manifest = JSON.parse(readFileSync16(join22(sessionPath, "manifest.json"), "utf-8"));
46424
+ manifest = JSON.parse(readFileSync17(join25(sessionPath, "manifest.json"), "utf-8"));
46051
46425
  } catch {}
46052
46426
  let output = `# Team Verdict
46053
46427
 
@@ -46102,14 +46476,14 @@ __export(exports_mcp_server, {
46102
46476
  parseAnthropicSse: () => parseAnthropicSse,
46103
46477
  formatTeamResult: () => formatTeamResult
46104
46478
  });
46105
- import { existsSync as existsSync19, mkdirSync as mkdirSync12, readFileSync as readFileSync17, readdirSync as readdirSync3, writeFileSync as writeFileSync13 } from "fs";
46106
- import { homedir as homedir21 } from "os";
46107
- import { dirname as dirname7, join as join23 } from "path";
46479
+ import { existsSync as existsSync19, mkdirSync as mkdirSync12, readFileSync as readFileSync18, readdirSync as readdirSync4, writeFileSync as writeFileSync13 } from "fs";
46480
+ import { homedir as homedir24 } from "os";
46481
+ import { dirname as dirname8, join as join26 } from "path";
46108
46482
  import { fileURLToPath } from "url";
46109
46483
  async function loadAllModels(forceRefresh = false) {
46110
46484
  if (!forceRefresh && existsSync19(ALL_MODELS_CACHE_PATH2)) {
46111
46485
  try {
46112
- const cacheData = JSON.parse(readFileSync17(ALL_MODELS_CACHE_PATH2, "utf-8"));
46486
+ const cacheData = JSON.parse(readFileSync18(ALL_MODELS_CACHE_PATH2, "utf-8"));
46113
46487
  const lastUpdated = new Date(cacheData.lastUpdated);
46114
46488
  const ageInDays = (Date.now() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
46115
46489
  if (ageInDays <= CACHE_MAX_AGE_DAYS) {
@@ -46128,7 +46502,7 @@ async function loadAllModels(forceRefresh = false) {
46128
46502
  return models;
46129
46503
  } catch {
46130
46504
  if (existsSync19(ALL_MODELS_CACHE_PATH2)) {
46131
- const cacheData = JSON.parse(readFileSync17(ALL_MODELS_CACHE_PATH2, "utf-8"));
46505
+ const cacheData = JSON.parse(readFileSync18(ALL_MODELS_CACHE_PATH2, "utf-8"));
46132
46506
  return cacheData.models || [];
46133
46507
  }
46134
46508
  return [];
@@ -46695,7 +47069,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
46695
47069
  let stderrFull = stderr_snippet || "";
46696
47070
  if (error_log_path) {
46697
47071
  try {
46698
- stderrFull = readFileSync17(error_log_path, "utf-8");
47072
+ stderrFull = readFileSync18(error_log_path, "utf-8");
46699
47073
  } catch {}
46700
47074
  }
46701
47075
  const sessionData = {};
@@ -46703,26 +47077,26 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
46703
47077
  const sp = session_path;
46704
47078
  for (const file2 of ["status.json", "manifest.json", "input.md"]) {
46705
47079
  try {
46706
- sessionData[file2] = readFileSync17(join23(sp, file2), "utf-8");
47080
+ sessionData[file2] = readFileSync18(join26(sp, file2), "utf-8");
46707
47081
  } catch {}
46708
47082
  }
46709
47083
  try {
46710
- const errorDir = join23(sp, "errors");
47084
+ const errorDir = join26(sp, "errors");
46711
47085
  if (existsSync19(errorDir)) {
46712
- for (const f of readdirSync3(errorDir)) {
47086
+ for (const f of readdirSync4(errorDir)) {
46713
47087
  if (f.endsWith(".log")) {
46714
47088
  try {
46715
- sessionData[`errors/${f}`] = readFileSync17(join23(errorDir, f), "utf-8");
47089
+ sessionData[`errors/${f}`] = readFileSync18(join26(errorDir, f), "utf-8");
46716
47090
  } catch {}
46717
47091
  }
46718
47092
  }
46719
47093
  }
46720
47094
  } catch {}
46721
47095
  try {
46722
- for (const f of readdirSync3(sp)) {
47096
+ for (const f of readdirSync4(sp)) {
46723
47097
  if (f.startsWith("response-") && f.endsWith(".md")) {
46724
47098
  try {
46725
- const content = readFileSync17(join23(sp, f), "utf-8");
47099
+ const content = readFileSync18(join26(sp, f), "utf-8");
46726
47100
  sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
46727
47101
  } catch {}
46728
47102
  }
@@ -46731,9 +47105,9 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
46731
47105
  }
46732
47106
  let version2 = "unknown";
46733
47107
  try {
46734
- const pkgPath = join23(__dirname2, "../package.json");
47108
+ const pkgPath = join26(__dirname2, "../package.json");
46735
47109
  if (existsSync19(pkgPath)) {
46736
- version2 = JSON.parse(readFileSync17(pkgPath, "utf-8")).version;
47110
+ version2 = JSON.parse(readFileSync18(pkgPath, "utf-8")).version;
46737
47111
  }
46738
47112
  } catch {}
46739
47113
  const report = {
@@ -47130,9 +47504,9 @@ var init_mcp_server = __esm(() => {
47130
47504
  import_dotenv2 = __toESM(require_main(), 1);
47131
47505
  import_dotenv2.config({ quiet: true });
47132
47506
  __filename2 = fileURLToPath(import.meta.url);
47133
- __dirname2 = dirname7(__filename2);
47134
- CLAUDISH_CACHE_DIR = join23(homedir21(), ".claudish");
47135
- ALL_MODELS_CACHE_PATH2 = join23(CLAUDISH_CACHE_DIR, "all-models.json");
47507
+ __dirname2 = dirname8(__filename2);
47508
+ CLAUDISH_CACHE_DIR = join26(homedir24(), ".claudish");
47509
+ ALL_MODELS_CACHE_PATH2 = join26(CLAUDISH_CACHE_DIR, "all-models.json");
47136
47510
  NEXT_STEP = {
47137
47511
  nonzero_exit: "read the evidence log, then retry or drop the model",
47138
47512
  timeout: "raise `timeout`, or pick a faster model",
@@ -47157,7 +47531,7 @@ var exports_serve_command = {};
47157
47531
  __export(exports_serve_command, {
47158
47532
  serveCommand: () => serveCommand
47159
47533
  });
47160
- import { existsSync as existsSync20, readFileSync as readFileSync18 } from "fs";
47534
+ import { existsSync as existsSync20, readFileSync as readFileSync19 } from "fs";
47161
47535
  function parseServeArgs(args) {
47162
47536
  const out = {};
47163
47537
  for (let i = 0;i < args.length; i++) {
@@ -47181,7 +47555,7 @@ function loadModelMap(path) {
47181
47555
  }
47182
47556
  let raw2;
47183
47557
  try {
47184
- raw2 = readFileSync18(path, "utf-8");
47558
+ raw2 = readFileSync19(path, "utf-8");
47185
47559
  } catch (e) {
47186
47560
  throw new Error(`failed to read --models file ${path}: ${e instanceof Error ? e.message : String(e)}`);
47187
47561
  }
@@ -47253,6 +47627,127 @@ var init_serve_command = __esm(() => {
47253
47627
  init_proxy_server();
47254
47628
  });
47255
47629
 
47630
+ // src/behavior-command.ts
47631
+ var exports_behavior_command = {};
47632
+ __export(exports_behavior_command, {
47633
+ behaviorCommand: () => behaviorCommand
47634
+ });
47635
+ function severityColor(sev) {
47636
+ if (sev === "fix")
47637
+ return green(sev);
47638
+ if (sev === "warn")
47639
+ return yellow(sev);
47640
+ return dim2(sev);
47641
+ }
47642
+ function showRules(json2) {
47643
+ const config3 = parseBehaviorConfig(loadConfig().behavior);
47644
+ const rows = BUILTIN_RULES.map((rule) => ({
47645
+ id: rule.id,
47646
+ severity: resolveSeverity(rule.id, rule.defaultSeverity, config3),
47647
+ defaultSeverity: rule.defaultSeverity,
47648
+ intercepts: rule.interceptsTools ?? [],
47649
+ description: rule.description
47650
+ }));
47651
+ if (json2) {
47652
+ console.log(JSON.stringify({ rules: rows, observer: config3.observer ?? null }, null, 2));
47653
+ return;
47654
+ }
47655
+ console.log(bold2(`
47656
+ Behavior rules
47657
+ `));
47658
+ for (const r of rows) {
47659
+ const overridden = r.severity !== r.defaultSeverity ? dim2(` (default ${r.defaultSeverity})`) : "";
47660
+ console.log(` ${severityColor(r.severity).padEnd(18)} ${r.id}${overridden}`);
47661
+ console.log(` ${dim2(r.description)}`);
47662
+ if (r.intercepts.length > 0) {
47663
+ console.log(` ${dim2(`repairs: ${r.intercepts.join(", ")}`)}`);
47664
+ }
47665
+ console.log();
47666
+ }
47667
+ console.log(dim2(` Rules are inactive for native Claude models by design.
47668
+ `));
47669
+ const obs = config3.observer;
47670
+ const obsState = obs?.enabled ? obs.mode ?? "suggest" : "off";
47671
+ console.log(` observer: ${obsState === "off" ? dim2("off") : green(obsState)}`);
47672
+ if (obs?.model)
47673
+ console.log(` ${dim2(`observer model: ${obs.model}`)}`);
47674
+ console.log();
47675
+ }
47676
+ function showCorpus(write, json2) {
47677
+ const result = buildCorpus({ write });
47678
+ if (json2) {
47679
+ console.log(JSON.stringify(result, null, 2));
47680
+ return;
47681
+ }
47682
+ const degraded = result.records.filter((r) => r.outcome === "degraded");
47683
+ const ok = result.records.filter((r) => r.outcome === "ok");
47684
+ const catchable = degraded.filter((r) => r.observedPaths.length > 0);
47685
+ console.log(bold2(`
47686
+ Behavior divergence corpus
47687
+ `));
47688
+ console.log(` transcripts scanned : ${result.scanned}`);
47689
+ console.log(` plan-exit records : ${result.records.length}`);
47690
+ console.log(` ${green("plan found")} : ${ok.length}`);
47691
+ console.log(` ${yellow("degraded (no plan)")} : ${degraded.length}`);
47692
+ console.log(` of those, a rule would have fired on ${catchable.length}
47693
+ `);
47694
+ const byModel = new Map;
47695
+ for (const r of result.records) {
47696
+ const m = r.model ?? "unknown";
47697
+ const e = byModel.get(m) ?? { ok: 0, degraded: 0 };
47698
+ if (r.outcome === "degraded")
47699
+ e.degraded++;
47700
+ else
47701
+ e.ok++;
47702
+ byModel.set(m, e);
47703
+ }
47704
+ if (byModel.size > 0) {
47705
+ console.log(bold2(` by model (degraded / ok)
47706
+ `));
47707
+ for (const [model, v] of [...byModel.entries()].sort((a, b) => b[1].degraded - a[1].degraded || b[1].ok - a[1].ok)) {
47708
+ const flag = v.degraded > 0 ? yellow(String(v.degraded)) : dim2("0");
47709
+ console.log(` ${model.padEnd(26)} ${flag} / ${v.ok}`);
47710
+ }
47711
+ console.log();
47712
+ }
47713
+ if (result.outputPath) {
47714
+ console.log(dim2(` appended to ${result.outputPath}
47715
+ `));
47716
+ } else if (write) {
47717
+ console.log(dim2(` nothing to write (no records found)
47718
+ `));
47719
+ } else {
47720
+ console.log(dim2(` pass --write to append these records to the divergence log
47721
+ `));
47722
+ }
47723
+ }
47724
+ async function behaviorCommand(argv) {
47725
+ const json2 = argv.includes("--json");
47726
+ const write = argv.includes("--write");
47727
+ const action = argv.find((a) => !a.startsWith("-")) ?? "rules";
47728
+ switch (action) {
47729
+ case "rules":
47730
+ showRules(json2);
47731
+ return;
47732
+ case "corpus":
47733
+ showCorpus(write, json2);
47734
+ return;
47735
+ default:
47736
+ console.error(`Unknown action "${action}".
47737
+
47738
+ ` + `Usage:
47739
+ ` + ` claudish behavior rules [--json]
47740
+ ` + ` claudish behavior corpus [--write] [--json]
47741
+ `);
47742
+ process.exit(1);
47743
+ }
47744
+ }
47745
+ var green = (s) => `\x1B[32m${s}\x1B[0m`, yellow = (s) => `\x1B[33m${s}\x1B[0m`, dim2 = (s) => `\x1B[2m${s}\x1B[0m`, bold2 = (s) => `\x1B[1m${s}\x1B[0m`;
47746
+ var init_behavior_command = __esm(() => {
47747
+ init_behavior();
47748
+ init_profile_config();
47749
+ });
47750
+
47256
47751
  // src/auth/credentials/source.ts
47257
47752
  function describeSourceSync(p, config3) {
47258
47753
  if (p.isLocal)
@@ -48169,8 +48664,8 @@ function assembleStyles() {
48169
48664
  styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
48170
48665
  Object.defineProperties(styles, {
48171
48666
  rgbToAnsi256: {
48172
- value(red, green, blue) {
48173
- if (red === green && green === blue) {
48667
+ value(red, green2, blue) {
48668
+ if (red === green2 && green2 === blue) {
48174
48669
  if (red < 8) {
48175
48670
  return 16;
48176
48671
  }
@@ -48179,7 +48674,7 @@ function assembleStyles() {
48179
48674
  }
48180
48675
  return Math.round((red - 8) / 247 * 24) + 232;
48181
48676
  }
48182
- return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
48677
+ return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green2 / 255 * 5) + Math.round(blue / 255 * 5);
48183
48678
  },
48184
48679
  enumerable: false
48185
48680
  },
@@ -48215,24 +48710,24 @@ function assembleStyles() {
48215
48710
  return 90 + (code - 8);
48216
48711
  }
48217
48712
  let red;
48218
- let green;
48713
+ let green2;
48219
48714
  let blue;
48220
48715
  if (code >= 232) {
48221
48716
  red = ((code - 232) * 10 + 8) / 255;
48222
- green = red;
48717
+ green2 = red;
48223
48718
  blue = red;
48224
48719
  } else {
48225
48720
  code -= 16;
48226
48721
  const remainder = code % 36;
48227
48722
  red = Math.floor(code / 36) / 5;
48228
- green = Math.floor(remainder / 6) / 5;
48723
+ green2 = Math.floor(remainder / 6) / 5;
48229
48724
  blue = remainder % 6 / 5;
48230
48725
  }
48231
- const value = Math.max(red, green, blue) * 2;
48726
+ const value = Math.max(red, green2, blue) * 2;
48232
48727
  if (value === 0) {
48233
48728
  return 30;
48234
48729
  }
48235
- let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
48730
+ let result = 30 + (Math.round(blue) << 2 | Math.round(green2) << 1 | Math.round(red));
48236
48731
  if (value === 2) {
48237
48732
  result += 60;
48238
48733
  }
@@ -48241,7 +48736,7 @@ function assembleStyles() {
48241
48736
  enumerable: false
48242
48737
  },
48243
48738
  rgbToAnsi: {
48244
- value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
48739
+ value: (red, green2, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green2, blue)),
48245
48740
  enumerable: false
48246
48741
  },
48247
48742
  hexToAnsi: {
@@ -48251,7 +48746,7 @@ function assembleStyles() {
48251
48746
  });
48252
48747
  return styles;
48253
48748
  }
48254
- var ANSI_BACKGROUND_OFFSET = 10, wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`, wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`, styles, modifierNames, foregroundColorNames, backgroundColorNames, colorNames, ansiStyles, ansi_styles_default;
48749
+ var ANSI_BACKGROUND_OFFSET = 10, wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`, wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, wrapAnsi16m = (offset = 0) => (red, green2, blue) => `\x1B[${38 + offset};2;${red};${green2};${blue}m`, styles, modifierNames, foregroundColorNames, backgroundColorNames, colorNames, ansiStyles, ansi_styles_default;
48255
48750
  var init_ansi_styles = __esm(() => {
48256
48751
  styles = {
48257
48752
  modifier: {
@@ -58653,7 +59148,7 @@ var init_RemoveFileError = __esm(() => {
58653
59148
 
58654
59149
  // ../../node_modules/.bun/@inquirer+external-editor@2.0.1+04f2146be16c61ef/node_modules/@inquirer/external-editor/dist/index.js
58655
59150
  import { spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
58656
- import { readFileSync as readFileSync19, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "fs";
59151
+ import { readFileSync as readFileSync20, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "fs";
58657
59152
  import path from "path";
58658
59153
  import os from "os";
58659
59154
  import { randomUUID as randomUUID4 } from "crypto";
@@ -58769,7 +59264,7 @@ class ExternalEditor {
58769
59264
  }
58770
59265
  readTemporaryFile() {
58771
59266
  try {
58772
- const tempFileBuffer = readFileSync19(this.tempFile);
59267
+ const tempFileBuffer = readFileSync20(this.tempFile);
58773
59268
  if (tempFileBuffer.length === 0) {
58774
59269
  this.text = "";
58775
59270
  } else {
@@ -59964,15 +60459,15 @@ async function geminiQuotaHandler() {
59964
60459
  }
59965
60460
  }
59966
60461
  async function codexQuotaHandler() {
59967
- const { readFileSync: readFileSync20, existsSync: existsSync21 } = await import("fs");
59968
- const { join: join24 } = await import("path");
59969
- const { homedir: homedir22 } = await import("os");
59970
- const credPath = join24(homedir22(), ".claudish", "codex-oauth.json");
60462
+ const { readFileSync: readFileSync21, existsSync: existsSync21 } = await import("fs");
60463
+ const { join: join27 } = await import("path");
60464
+ const { homedir: homedir25 } = await import("os");
60465
+ const credPath = join27(homedir25(), ".claudish", "codex-oauth.json");
59971
60466
  if (!existsSync21(credPath)) {
59972
60467
  console.error(`${RED}No Codex credentials found.${R} Run: ${B}claudish login codex${R}`);
59973
60468
  process.exit(1);
59974
60469
  }
59975
- const creds = JSON.parse(readFileSync20(credPath, "utf-8"));
60470
+ const creds = JSON.parse(readFileSync21(credPath, "utf-8"));
59976
60471
  let email3 = "";
59977
60472
  try {
59978
60473
  const parts = creds.access_token.split(".");
@@ -60024,9 +60519,9 @@ async function codexQuotaHandler() {
60024
60519
  }
60025
60520
  let modelSlugs = [];
60026
60521
  try {
60027
- const modelsPath = join24(homedir22(), ".codex", "models_cache.json");
60522
+ const modelsPath = join27(homedir25(), ".codex", "models_cache.json");
60028
60523
  if (existsSync21(modelsPath)) {
60029
- const cache2 = JSON.parse(readFileSync20(modelsPath, "utf-8"));
60524
+ const cache2 = JSON.parse(readFileSync21(modelsPath, "utf-8"));
60030
60525
  modelSlugs = (cache2.models || []).map((m) => m.slug || m.id).filter(Boolean);
60031
60526
  }
60032
60527
  } catch {}
@@ -61819,7 +62314,7 @@ function tokBarCells(tokensPerSec, maxTokPerSec, tokWidth) {
61819
62314
  const raw2 = Math.round(tokWidth * Math.max(0, tokensPerSec) / denom);
61820
62315
  return Math.min(tokWidth, Math.max(0, raw2));
61821
62316
  }
61822
- var C, bold2, A, LATENCY_BUCKETS, latencyFg = "#ffffff", LATENCY_FG_ANSI = "\x1B[38;2;255;255;255m", ANSI_RESET = "\x1B[0m", STAGE_BG, STAGE_FG, STAGE_BG_ANSI;
62317
+ var C, bold3, A, LATENCY_BUCKETS, latencyFg = "#ffffff", LATENCY_FG_ANSI = "\x1B[38;2;255;255;255m", ANSI_RESET = "\x1B[0m", STAGE_BG, STAGE_FG, STAGE_BG_ANSI;
61823
62318
  var init_theme2 = __esm(() => {
61824
62319
  C = {
61825
62320
  bg: "#000000",
@@ -61850,10 +62345,10 @@ var init_theme2 = __esm(() => {
61850
62345
  chipKeyBg: "#3a3a3a",
61851
62346
  chipLabelBg: "#222222"
61852
62347
  };
61853
- bold2 = createTextAttributes({ bold: true });
62348
+ bold3 = createTextAttributes({ bold: true });
61854
62349
  A = {
61855
- bold: bold2,
61856
- boldIf: (enabled) => enabled ? bold2 : undefined
62350
+ bold: bold3,
62351
+ boldIf: (enabled) => enabled ? bold3 : undefined
61857
62352
  };
61858
62353
  LATENCY_BUCKETS = [
61859
62354
  { maxMs: 500, hex: "#1f8f3b" },
@@ -63991,28 +64486,28 @@ import {
63991
64486
  copyFileSync as copyFileSync2,
63992
64487
  existsSync as existsSync21,
63993
64488
  mkdirSync as mkdirSync13,
63994
- readFileSync as readFileSync20,
63995
- readdirSync as readdirSync4,
64489
+ readFileSync as readFileSync21,
64490
+ readdirSync as readdirSync5,
63996
64491
  unlinkSync as unlinkSync7,
63997
64492
  writeFileSync as writeFileSync15
63998
64493
  } from "fs";
63999
- import { homedir as homedir22 } from "os";
64000
- import { dirname as dirname8, join as join24 } from "path";
64494
+ import { homedir as homedir25 } from "os";
64495
+ import { dirname as dirname9, join as join27 } from "path";
64001
64496
  import { fileURLToPath as fileURLToPath2 } from "url";
64002
64497
  function getVersion3() {
64003
64498
  return VERSION;
64004
64499
  }
64005
64500
  function clearAllModelCaches() {
64006
- const cacheDir = join24(homedir22(), ".claudish");
64501
+ const cacheDir = join27(homedir25(), ".claudish");
64007
64502
  if (!existsSync21(cacheDir))
64008
64503
  return;
64009
64504
  const cachePatterns = ["pricing-cache.json", "recommended-models-cache.json"];
64010
64505
  let cleared = 0;
64011
64506
  try {
64012
- const files = readdirSync4(cacheDir);
64507
+ const files = readdirSync5(cacheDir);
64013
64508
  for (const file2 of files) {
64014
64509
  if (cachePatterns.includes(file2)) {
64015
- unlinkSync7(join24(cacheDir, file2));
64510
+ unlinkSync7(join27(cacheDir, file2));
64016
64511
  cleared++;
64017
64512
  }
64018
64513
  }
@@ -64422,14 +64917,14 @@ Usage: claudish --models --provider <slug>`);
64422
64917
  });
64423
64918
  config3.resolvedDefaultProvider = resolved;
64424
64919
  if (resolved.legacyAutoPromoted && !config3.quiet) {
64425
- const markerFile = join24(homedir22(), ".claudish", ".legacy-litellm-hint-shown");
64920
+ const markerFile = join27(homedir25(), ".claudish", ".legacy-litellm-hint-shown");
64426
64921
  if (!existsSync21(markerFile)) {
64427
64922
  const hint = buildLegacyHint(resolved);
64428
64923
  if (hint) {
64429
64924
  console.error(hint);
64430
64925
  }
64431
64926
  try {
64432
- mkdirSync13(dirname8(markerFile), { recursive: true });
64927
+ mkdirSync13(dirname9(markerFile), { recursive: true });
64433
64928
  writeFileSync15(markerFile, new Date().toISOString(), "utf-8");
64434
64929
  } catch {}
64435
64930
  }
@@ -65189,261 +65684,261 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
65189
65684
  function printHelp() {
65190
65685
  const useColor = !!process.stdout.isTTY && !process.env.NO_COLOR;
65191
65686
  const c = (code) => (s) => useColor ? `\x1B[${code}m${s}\x1B[0m` : s;
65192
- const bold3 = c("1");
65193
- const dim2 = c("2");
65687
+ const bold4 = c("1");
65688
+ const dim3 = c("2");
65194
65689
  const cyan = c("36");
65195
- const green = c("32");
65196
- const yellow = c("33");
65690
+ const green2 = c("32");
65691
+ const yellow2 = c("33");
65197
65692
  const magenta = c("35");
65198
65693
  const blue = c("34");
65199
- const h = (title) => bold3(cyan(`\u258C ${title}`));
65694
+ const h = (title) => bold4(cyan(`\u258C ${title}`));
65200
65695
  console.log(`
65201
- ${bold3("claudish")} ${dim2("\xB7")} Run Claude Code with any AI model
65202
- ${dim2("OpenRouter \xB7 Gemini \xB7 OpenAI \xB7 xAI \xB7 MiniMax \xB7 Kimi \xB7 GLM \xB7 Z.AI \xB7 Sakana \xB7 Poe \xB7 LiteLLM \xB7 Local")}
65696
+ ${bold4("claudish")} ${dim3("\xB7")} Run Claude Code with any AI model
65697
+ ${dim3("OpenRouter \xB7 Gemini \xB7 OpenAI \xB7 xAI \xB7 MiniMax \xB7 Kimi \xB7 GLM \xB7 Z.AI \xB7 Sakana \xB7 Poe \xB7 LiteLLM \xB7 Local")}
65203
65698
 
65204
65699
  ${h("USAGE")}
65205
- ${green("claudish")} ${dim2("# Interactive mode (default, model selector)")}
65206
- ${green("claudish")} ${yellow("[OPTIONS] <claude-args...>")} ${dim2("# Single-shot mode (requires --model)")}
65207
- ${green("claudish")} ${green("--team")} ${yellow("a,b,c")} ${yellow('"prompt"')} ${dim2("# Run models in parallel (magmux grid)")}
65208
- ${green("claudish")} ${green("--team")} ${yellow("a,b,c")} ${green("-f")} ${yellow("input.md")} ${dim2("# Team mode with file input")}
65700
+ ${green2("claudish")} ${dim3("# Interactive mode (default, model selector)")}
65701
+ ${green2("claudish")} ${yellow2("[OPTIONS] <claude-args...>")} ${dim3("# Single-shot mode (requires --model)")}
65702
+ ${green2("claudish")} ${green2("--team")} ${yellow2("a,b,c")} ${yellow2('"prompt"')} ${dim3("# Run models in parallel (magmux grid)")}
65703
+ ${green2("claudish")} ${green2("--team")} ${yellow2("a,b,c")} ${green2("-f")} ${yellow2("input.md")} ${dim3("# Team mode with file input")}
65209
65704
 
65210
65705
  ${h("MODEL ROUTING")}
65211
- ${bold3("New syntax:")} ${yellow("provider@model[:concurrency]")}
65212
- ${magenta("google@gemini-3-pro")} ${dim2("Direct Google API (explicit)")}
65213
- ${magenta("openrouter@google/gemini-3-pro")} ${dim2("OpenRouter (explicit)")}
65214
- ${magenta("oai@gpt-5.3")} ${dim2("Direct OpenAI API (shortcut)")}
65215
- ${magenta("ollama@llama3.2:3")} ${dim2("Local Ollama, 3 concurrent requests")}
65216
- ${magenta("ollama@llama3.2:0")} ${dim2("Local Ollama, no limits")}
65217
-
65218
- ${bold3("Provider shortcuts:")}
65219
- ${magenta("g, gemini")} ${dim2("->")} Google Gemini ${dim2("google@gemini-3-pro")}
65220
- ${magenta("oai")} ${dim2("->")} OpenAI Direct ${dim2("oai@gpt-5.3")}
65221
- ${magenta("cx, codex")} ${dim2("->")} OpenAI Codex ${dim2("cx@gpt-5.3 (Responses API)")}
65222
- ${magenta("or")} ${dim2("->")} OpenRouter ${dim2("or@openai/gpt-5.3")}
65223
- ${magenta("x-ai, xai, grok")} ${dim2("->")} xAI / Grok ${dim2("x-ai@grok-3")}
65224
- ${magenta("mm, mmax")} ${dim2("->")} MiniMax Direct ${dim2("mm@MiniMax-M2.1")}
65225
- ${magenta("mmc")} ${dim2("->")} MiniMax Coding ${dim2("mmc@MiniMax-M2.1")}
65226
- ${magenta("kimi, moon")} ${dim2("->")} Kimi Direct ${dim2("kimi@kimi-k2-thinking-turbo")}
65227
- ${magenta("kc")} ${dim2("->")} Kimi Coding ${dim2("kc@kimi-k2-thinking-turbo")}
65228
- ${magenta("glm, zhipu")} ${dim2("->")} GLM Direct ${dim2("glm@glm-4.7")}
65229
- ${magenta("gc")} ${dim2("->")} GLM Coding ${dim2("gc@glm-4.7")}
65230
- ${magenta("z-ai, zai")} ${dim2("->")} Z.AI Direct ${dim2("z-ai@glm-4.7")}
65231
- ${magenta("oc, llama, lc, meta")} ${dim2("->")} OllamaCloud ${dim2("oc@llama-3.1")}
65232
- ${magenta("zen")} ${dim2("->")} OpenCode Zen ${dim2("zen@grok-code")}
65233
- ${magenta("zengo, zgo")} ${dim2("->")} OpenCode Zen Go ${dim2("zengo@grok-code")}
65234
- ${magenta("v, vertex")} ${dim2("->")} Vertex AI ${dim2("v@gemini-2.5-flash")}
65235
- ${magenta("go")} ${dim2("->")} Gemini Code Assist ${dim2("go@gemini-2.5-flash")}
65236
- ${magenta("poe")} ${dim2("->")} Poe ${dim2("poe@GPT-4o")}
65237
- ${magenta("litellm, ll")} ${dim2("->")} LiteLLM ${dim2("ll@gpt-4o (needs LITELLM_BASE_URL)")}
65238
- ${magenta("ds")} ${dim2("->")} DeepSeek ${dim2("ds@deepseek-chat")}
65239
- ${magenta("sakana, fugu")} ${dim2("->")} Sakana Fugu ${dim2("fugu@fugu-ultra")}
65240
- ${magenta("sc")} ${dim2("->")} Sakana Subscription ${dim2("sc@fugu-ultra")}
65241
- ${magenta("ollama")} ${dim2("->")} Ollama (local) ${dim2("ollama@llama3.2")}
65242
- ${magenta("lms, lmstudio")} ${dim2("->")} LM Studio (local) ${dim2("lms@qwen")}
65243
- ${magenta("vllm")} ${dim2("->")} vLLM (local) ${dim2("vllm@model")}
65244
- ${magenta("mlx")} ${dim2("->")} MLX (local) ${dim2("mlx@model")}
65245
-
65246
- ${bold3("Native auto-detection")} ${dim2("(when no provider specified):")}
65247
- ${yellow("google/*, gemini-*")} ${dim2("->")} Google API
65248
- ${yellow("openai/*, gpt-*, o1-*")} ${dim2("->")} OpenAI API
65249
- ${yellow("x-ai/*, grok-*")} ${dim2("->")} xAI
65250
- ${yellow("meta-llama/*, llama-*")} ${dim2("->")} OllamaCloud
65251
- ${yellow("minimax/*, abab-*")} ${dim2("->")} MiniMax API
65252
- ${yellow("moonshot/*, kimi-*")} ${dim2("->")} Kimi API
65253
- ${yellow("zhipu/*, glm-*")} ${dim2("->")} GLM API
65254
- ${yellow("sakana/*, fugu-*")} ${dim2("->")} Sakana Fugu
65255
- ${yellow("poe:*")} ${dim2("->")} Poe
65256
- ${yellow("anthropic/*, claude-*")} ${dim2("->")} Native Anthropic
65257
- ${yellow("(unknown vendor/)")} ${dim2("->")} Error (use openrouter@vendor/model)
65258
-
65259
- ${dim2("A defaultProvider (config / --default-provider) catches bare names that match no rule.")}
65706
+ ${bold4("New syntax:")} ${yellow2("provider@model[:concurrency]")}
65707
+ ${magenta("google@gemini-3-pro")} ${dim3("Direct Google API (explicit)")}
65708
+ ${magenta("openrouter@google/gemini-3-pro")} ${dim3("OpenRouter (explicit)")}
65709
+ ${magenta("oai@gpt-5.3")} ${dim3("Direct OpenAI API (shortcut)")}
65710
+ ${magenta("ollama@llama3.2:3")} ${dim3("Local Ollama, 3 concurrent requests")}
65711
+ ${magenta("ollama@llama3.2:0")} ${dim3("Local Ollama, no limits")}
65712
+
65713
+ ${bold4("Provider shortcuts:")}
65714
+ ${magenta("g, gemini")} ${dim3("->")} Google Gemini ${dim3("google@gemini-3-pro")}
65715
+ ${magenta("oai")} ${dim3("->")} OpenAI Direct ${dim3("oai@gpt-5.3")}
65716
+ ${magenta("cx, codex")} ${dim3("->")} OpenAI Codex ${dim3("cx@gpt-5.3 (Responses API)")}
65717
+ ${magenta("or")} ${dim3("->")} OpenRouter ${dim3("or@openai/gpt-5.3")}
65718
+ ${magenta("x-ai, xai, grok")} ${dim3("->")} xAI / Grok ${dim3("x-ai@grok-3")}
65719
+ ${magenta("mm, mmax")} ${dim3("->")} MiniMax Direct ${dim3("mm@MiniMax-M2.1")}
65720
+ ${magenta("mmc")} ${dim3("->")} MiniMax Coding ${dim3("mmc@MiniMax-M2.1")}
65721
+ ${magenta("kimi, moon")} ${dim3("->")} Kimi Direct ${dim3("kimi@kimi-k2-thinking-turbo")}
65722
+ ${magenta("kc")} ${dim3("->")} Kimi Coding ${dim3("kc@kimi-k2-thinking-turbo")}
65723
+ ${magenta("glm, zhipu")} ${dim3("->")} GLM Direct ${dim3("glm@glm-4.7")}
65724
+ ${magenta("gc")} ${dim3("->")} GLM Coding ${dim3("gc@glm-4.7")}
65725
+ ${magenta("z-ai, zai")} ${dim3("->")} Z.AI Direct ${dim3("z-ai@glm-4.7")}
65726
+ ${magenta("oc, llama, lc, meta")} ${dim3("->")} OllamaCloud ${dim3("oc@llama-3.1")}
65727
+ ${magenta("zen")} ${dim3("->")} OpenCode Zen ${dim3("zen@grok-code")}
65728
+ ${magenta("zengo, zgo")} ${dim3("->")} OpenCode Zen Go ${dim3("zengo@grok-code")}
65729
+ ${magenta("v, vertex")} ${dim3("->")} Vertex AI ${dim3("v@gemini-2.5-flash")}
65730
+ ${magenta("go")} ${dim3("->")} Gemini Code Assist ${dim3("go@gemini-2.5-flash")}
65731
+ ${magenta("poe")} ${dim3("->")} Poe ${dim3("poe@GPT-4o")}
65732
+ ${magenta("litellm, ll")} ${dim3("->")} LiteLLM ${dim3("ll@gpt-4o (needs LITELLM_BASE_URL)")}
65733
+ ${magenta("ds")} ${dim3("->")} DeepSeek ${dim3("ds@deepseek-chat")}
65734
+ ${magenta("sakana, fugu")} ${dim3("->")} Sakana Fugu ${dim3("fugu@fugu-ultra")}
65735
+ ${magenta("sc")} ${dim3("->")} Sakana Subscription ${dim3("sc@fugu-ultra")}
65736
+ ${magenta("ollama")} ${dim3("->")} Ollama (local) ${dim3("ollama@llama3.2")}
65737
+ ${magenta("lms, lmstudio")} ${dim3("->")} LM Studio (local) ${dim3("lms@qwen")}
65738
+ ${magenta("vllm")} ${dim3("->")} vLLM (local) ${dim3("vllm@model")}
65739
+ ${magenta("mlx")} ${dim3("->")} MLX (local) ${dim3("mlx@model")}
65740
+
65741
+ ${bold4("Native auto-detection")} ${dim3("(when no provider specified):")}
65742
+ ${yellow2("google/*, gemini-*")} ${dim3("->")} Google API
65743
+ ${yellow2("openai/*, gpt-*, o1-*")} ${dim3("->")} OpenAI API
65744
+ ${yellow2("x-ai/*, grok-*")} ${dim3("->")} xAI
65745
+ ${yellow2("meta-llama/*, llama-*")} ${dim3("->")} OllamaCloud
65746
+ ${yellow2("minimax/*, abab-*")} ${dim3("->")} MiniMax API
65747
+ ${yellow2("moonshot/*, kimi-*")} ${dim3("->")} Kimi API
65748
+ ${yellow2("zhipu/*, glm-*")} ${dim3("->")} GLM API
65749
+ ${yellow2("sakana/*, fugu-*")} ${dim3("->")} Sakana Fugu
65750
+ ${yellow2("poe:*")} ${dim3("->")} Poe
65751
+ ${yellow2("anthropic/*, claude-*")} ${dim3("->")} Native Anthropic
65752
+ ${yellow2("(unknown vendor/)")} ${dim3("->")} Error (use openrouter@vendor/model)
65753
+
65754
+ ${dim3("A defaultProvider (config / --default-provider) catches bare names that match no rule.")}
65260
65755
 
65261
65756
  ${h("OPTIONS")}
65262
- ${green("-i, --interactive")} Run in interactive mode (default when no prompt given)
65263
- ${green("-m, --model")} ${yellow("<model>")} Model to use (required for single-shot mode)
65264
- ${green("--profile")} ${yellow("<name>")} Use named profile for model mapping (default profile if omitted)
65265
- ${green("--default-provider")} ${yellow("<name>")} Fallback provider for bare model names (builtin or customEndpoints key)
65266
- ${dim2("Precedence: this flag > CLAUDISH_DEFAULT_PROVIDER env > config.json")}
65267
- ${green("--anthropic-api-billing")} Use your real ANTHROPIC_API_KEY for native Claude models
65268
- ${dim2("(metered API billing). Default: the key is hidden so Claude Code")}
65269
- ${dim2("uses your claude.ai subscription. Env: CLAUDISH_ANTHROPIC_API_BILLING")}
65270
- ${dim2("Config: anthropicApiBilling: true")}
65271
- ${green("--config")} ${yellow("<file>")} Use THIS config file for the run, fully replacing the machine
65272
- ${dim2("global (~/.claudish/config.json) AND project (.claudish.json).")}
65273
- ${dim2("A file naming no op:// source never touches 1Password (no prompt).")}
65274
- ${dim2("Env vars still resolve first. Env: CLAUDISH_CONFIG")}
65275
- ${green("--op")} ${yellow("<op://glob>")} Load API keys from a 1Password item glob (SDK-based, no op CLI)
65276
- ${green("--op")} ${yellow("<glob>")} ${green("--list")} Preview which fields the glob would import (names only, no values)
65277
- ${green("--op-env")} ${yellow("<id>")} Load env vars from a 1Password Environment (highest priority)
65278
- ${green("--port")} ${yellow("<port>")} Proxy server port (default: random)
65279
- ${green("-d, --debug-claudish")} Enable claudish debug logging to file (logs/claudish_*.log)
65280
- ${dim2('Always-on: CLAUDISH_DEBUG=1 env var or "debug": true in config.json')}
65281
- ${green("--no-debug-claudish")} Force debug logging off for this run (when globally enabled)
65282
- ${green("--log-off")} Disable always-on structural logging (~/.claudish/logs/)
65283
- ${green("--log-diag")} ${yellow("<mode>")} Diagnostic output: auto (default), logfile, off
65284
- ${dim2('Also: CLAUDISH_DIAG_MODE env var or "diagMode" in config.json')}
65285
- ${green("--log-level")} ${yellow("<level>")} Log verbosity: debug (full), info (truncated), minimal (labels)
65286
- ${green("-q, --quiet")} Suppress [claudish] log messages (default in single-shot mode)
65287
- ${green("-v, --verbose")} Show [claudish] log messages (default in interactive mode)
65288
- ${green("--json")} Output JSON for tool integration (implies --quiet)
65289
- ${green("--stdin")} Read prompt from stdin (large prompts / piping)
65290
- ${green("--free")} Show only FREE models in the interactive selector
65291
- ${green("--monitor")} Monitor mode - proxy to REAL Anthropic API and log traffic
65292
- ${green("--advisor")} ${yellow('"m1,m2[:collector]"')} Multi-model advisor replacement (implies --monitor)
65293
- ${green("-y, --auto-approve")} Skip permission prompts (--dangerously-skip-permissions)
65294
- ${green("--no-auto-approve")} Explicitly enable permission prompts (default)
65295
- ${green("--dangerous")} Pass --dangerouslyDisableSandbox to Claude Code
65296
- ${green("--cost-track")} Enable cost tracking for API usage
65297
- ${green("--cost-audit")} Show cost analysis report
65298
- ${green("--cost-reset")} Reset accumulated cost statistics
65299
- ${green("--version")} Show version information
65300
- ${green("-h, --help")} Show this help message
65301
- ${green("--help-ai")} Show AI agent usage guide (file-based patterns, sub-agents)
65302
- ${green("--init")} Install Claudish skill in current project (.claude/skills/)
65303
- ${green("--")} Separator: everything after passes directly to Claude Code
65757
+ ${green2("-i, --interactive")} Run in interactive mode (default when no prompt given)
65758
+ ${green2("-m, --model")} ${yellow2("<model>")} Model to use (required for single-shot mode)
65759
+ ${green2("--profile")} ${yellow2("<name>")} Use named profile for model mapping (default profile if omitted)
65760
+ ${green2("--default-provider")} ${yellow2("<name>")} Fallback provider for bare model names (builtin or customEndpoints key)
65761
+ ${dim3("Precedence: this flag > CLAUDISH_DEFAULT_PROVIDER env > config.json")}
65762
+ ${green2("--anthropic-api-billing")} Use your real ANTHROPIC_API_KEY for native Claude models
65763
+ ${dim3("(metered API billing). Default: the key is hidden so Claude Code")}
65764
+ ${dim3("uses your claude.ai subscription. Env: CLAUDISH_ANTHROPIC_API_BILLING")}
65765
+ ${dim3("Config: anthropicApiBilling: true")}
65766
+ ${green2("--config")} ${yellow2("<file>")} Use THIS config file for the run, fully replacing the machine
65767
+ ${dim3("global (~/.claudish/config.json) AND project (.claudish.json).")}
65768
+ ${dim3("A file naming no op:// source never touches 1Password (no prompt).")}
65769
+ ${dim3("Env vars still resolve first. Env: CLAUDISH_CONFIG")}
65770
+ ${green2("--op")} ${yellow2("<op://glob>")} Load API keys from a 1Password item glob (SDK-based, no op CLI)
65771
+ ${green2("--op")} ${yellow2("<glob>")} ${green2("--list")} Preview which fields the glob would import (names only, no values)
65772
+ ${green2("--op-env")} ${yellow2("<id>")} Load env vars from a 1Password Environment (highest priority)
65773
+ ${green2("--port")} ${yellow2("<port>")} Proxy server port (default: random)
65774
+ ${green2("-d, --debug-claudish")} Enable claudish debug logging to file (logs/claudish_*.log)
65775
+ ${dim3('Always-on: CLAUDISH_DEBUG=1 env var or "debug": true in config.json')}
65776
+ ${green2("--no-debug-claudish")} Force debug logging off for this run (when globally enabled)
65777
+ ${green2("--log-off")} Disable always-on structural logging (~/.claudish/logs/)
65778
+ ${green2("--log-diag")} ${yellow2("<mode>")} Diagnostic output: auto (default), logfile, off
65779
+ ${dim3('Also: CLAUDISH_DIAG_MODE env var or "diagMode" in config.json')}
65780
+ ${green2("--log-level")} ${yellow2("<level>")} Log verbosity: debug (full), info (truncated), minimal (labels)
65781
+ ${green2("-q, --quiet")} Suppress [claudish] log messages (default in single-shot mode)
65782
+ ${green2("-v, --verbose")} Show [claudish] log messages (default in interactive mode)
65783
+ ${green2("--json")} Output JSON for tool integration (implies --quiet)
65784
+ ${green2("--stdin")} Read prompt from stdin (large prompts / piping)
65785
+ ${green2("--free")} Show only FREE models in the interactive selector
65786
+ ${green2("--monitor")} Monitor mode - proxy to REAL Anthropic API and log traffic
65787
+ ${green2("--advisor")} ${yellow2('"m1,m2[:collector]"')} Multi-model advisor replacement (implies --monitor)
65788
+ ${green2("-y, --auto-approve")} Skip permission prompts (--dangerously-skip-permissions)
65789
+ ${green2("--no-auto-approve")} Explicitly enable permission prompts (default)
65790
+ ${green2("--dangerous")} Pass --dangerouslyDisableSandbox to Claude Code
65791
+ ${green2("--cost-track")} Enable cost tracking for API usage
65792
+ ${green2("--cost-audit")} Show cost analysis report
65793
+ ${green2("--cost-reset")} Reset accumulated cost statistics
65794
+ ${green2("--version")} Show version information
65795
+ ${green2("-h, --help")} Show this help message
65796
+ ${green2("--help-ai")} Show AI agent usage guide (file-based patterns, sub-agents)
65797
+ ${green2("--init")} Install Claudish skill in current project (.claude/skills/)
65798
+ ${green2("--")} Separator: everything after passes directly to Claude Code
65304
65799
 
65305
65800
  ${h("MODEL DISCOVERY")}
65306
- ${green("--models")} Top 100 ranked (Firebase + local providers)
65307
- ${green("--models --provider")} ${yellow("<slug>")} Filter the catalog to one provider
65308
- ${dim2("e.g. --provider opencode-zen, anthropic, openai")}
65309
- ${green("--providers")} Every provider + active-model count
65310
- ${green("-s, --models-search")} ${yellow("<query>")} Fuzzy search: id, brand synonyms (chatgpt,
65311
- ${dim2("claude, grok), gateways (zen, oc, codex), caps")}
65312
- ${green("--models-top")} Curated recommended models (flagship + fast)
65313
- ${green("--probe")} ${yellow("<models...>")} Probe each provider in the fallback chain with
65314
- ${dim2("a real 1-token request (may incur tiny cost)")}
65315
- ${green("--no-probe")} Skip live requests, show static chain only
65316
- ${green("--probe-timeout")} ${yellow("<secs>")} Per-link timeout for live probes (default: 40)
65317
- ${green("--models-refresh")} Force refresh the slim model catalog from Firebase
65318
- ${green("--models-skip-update")} Skip the launcher catalog warm step (offline)
65319
- ${green("--json")} JSON output (with --models / --models-top / --probe)
65801
+ ${green2("--models")} Top 100 ranked (Firebase + local providers)
65802
+ ${green2("--models --provider")} ${yellow2("<slug>")} Filter the catalog to one provider
65803
+ ${dim3("e.g. --provider opencode-zen, anthropic, openai")}
65804
+ ${green2("--providers")} Every provider + active-model count
65805
+ ${green2("-s, --models-search")} ${yellow2("<query>")} Fuzzy search: id, brand synonyms (chatgpt,
65806
+ ${dim3("claude, grok), gateways (zen, oc, codex), caps")}
65807
+ ${green2("--models-top")} Curated recommended models (flagship + fast)
65808
+ ${green2("--probe")} ${yellow2("<models...>")} Probe each provider in the fallback chain with
65809
+ ${dim3("a real 1-token request (may incur tiny cost)")}
65810
+ ${green2("--no-probe")} Skip live requests, show static chain only
65811
+ ${green2("--probe-timeout")} ${yellow2("<secs>")} Per-link timeout for live probes (default: 40)
65812
+ ${green2("--models-refresh")} Force refresh the slim model catalog from Firebase
65813
+ ${green2("--models-skip-update")} Skip the launcher catalog warm step (offline)
65814
+ ${green2("--json")} JSON output (with --models / --models-top / --probe)
65320
65815
 
65321
65816
  ${h("TEAM MODE")}
65322
- ${green("--team")} ${yellow("<models>")} Run multiple models in parallel (comma-separated)
65323
- ${dim2('Example: --team minimax-m2.5,kimi-k2.5 "prompt"')}
65324
- ${green("--mode")} ${yellow("<mode>")} Team mode: default (grid), interactive, json
65325
- ${green("-f, --file")} ${yellow("<path>")} Read prompt from file (use with --team or single-shot)
65817
+ ${green2("--team")} ${yellow2("<models>")} Run multiple models in parallel (comma-separated)
65818
+ ${dim3('Example: --team minimax-m2.5,kimi-k2.5 "prompt"')}
65819
+ ${green2("--mode")} ${yellow2("<mode>")} Team mode: default (grid), interactive, json
65820
+ ${green2("-f, --file")} ${yellow2("<path>")} Read prompt from file (use with --team or single-shot)
65326
65821
 
65327
- ${h("MODEL MAPPING")} ${dim2("(per-role override)")}
65328
- ${green("--model-opus")} ${yellow("<model>")} Model for Opus role (planning, complex tasks)
65329
- ${green("--model-sonnet")} ${yellow("<model>")} Model for Sonnet role (default coding)
65330
- ${green("--model-haiku")} ${yellow("<model>")} Model for Haiku role (fast tasks, background)
65331
- ${green("--model-subagent")} ${yellow("<model>")} Model for sub-agents (Task tool)
65822
+ ${h("MODEL MAPPING")} ${dim3("(per-role override)")}
65823
+ ${green2("--model-opus")} ${yellow2("<model>")} Model for Opus role (planning, complex tasks)
65824
+ ${green2("--model-sonnet")} ${yellow2("<model>")} Model for Sonnet role (default coding)
65825
+ ${green2("--model-haiku")} ${yellow2("<model>")} Model for Haiku role (fast tasks, background)
65826
+ ${green2("--model-subagent")} ${yellow2("<model>")} Model for sub-agents (Task tool)
65332
65827
 
65333
65828
  ${h("SUBCOMMANDS")}
65334
- ${green("claudish config")} Open the interactive config TUI (profiles,
65335
- ${dim2("providers, routing, 1Password)")}
65336
- ${green("claudish providers")} ${yellow("[--json]")} Show provider credential status (no key material)
65337
- ${green("claudish quota")} ${yellow("[provider]")} Show remaining quota/usage (alias: usage)
65338
- ${green("claudish serve")} ${yellow("--port <n> --models <p>")} Run the Claude Desktop redirect gateway
65339
- ${green("claudish update")} Check for updates and install the latest version
65340
-
65341
- ${bold3("Profiles:")}
65342
- ${green("claudish init")} ${yellow("[--local|--global]")} Setup wizard - create config + first profile
65343
- ${green("claudish profile list")} ${yellow("[scope]")} List all profiles (both scopes by default)
65344
- ${green("claudish profile add")} ${yellow("[scope]")} Add a new profile
65345
- ${green("claudish profile remove")} ${yellow("[name] [scope]")} Remove a profile
65346
- ${green("claudish profile use")} ${yellow("[name] [scope]")} Set default profile
65347
- ${green("claudish profile show")} ${yellow("[name] [scope]")} Show profile details
65348
- ${green("claudish profile edit")} ${yellow("[name] [scope]")} Edit a profile
65349
- ${dim2("scope = --local (.claudish.json) | --global (~/.claudish/config.json) | (prompted)")}
65350
-
65351
- ${bold3("Authentication:")}
65352
- ${green("claudish login")} ${yellow("[provider]")} Login to an OAuth provider (interactive if omitted)
65353
- ${green("claudish logout")} ${yellow("[provider]")} Clear OAuth credentials
65354
- ${dim2("Providers: gemini, kimi")}
65355
-
65356
- ${h("1PASSWORD")} ${dim2("(SDK-based \u2014 no op CLI needed for secrets)")}
65357
- ${dim2("Auth via OP_SERVICE_ACCOUNT_TOKEN, or OP_ACCOUNT / onepasswordAccount config (DesktopAuth).")}
65358
- ${green("--op")} ${yellow("<glob> --list")} Preview which fields a glob would import (names only)
65359
- ${green("--op")} ${yellow("<glob>")} ${yellow("[...args]")} Resolve a glob into env vars, then run a session
65360
- ${dim2("Inline op import requires a GLOB (self-names via field labels)")}
65361
- ${dim2('Example: claudish --op "op://Jack/Keys/**" --model gpt-4o "task"')}
65362
- ${green("--op-env")} ${yellow("<id>")} Load a 1Password Environment (highest-priority source)
65363
- ${dim2("Persistent setup (single refs, sets, environments, account): claudish config -> 1Password tab")}
65829
+ ${green2("claudish config")} Open the interactive config TUI (profiles,
65830
+ ${dim3("providers, routing, 1Password)")}
65831
+ ${green2("claudish providers")} ${yellow2("[--json]")} Show provider credential status (no key material)
65832
+ ${green2("claudish quota")} ${yellow2("[provider]")} Show remaining quota/usage (alias: usage)
65833
+ ${green2("claudish serve")} ${yellow2("--port <n> --models <p>")} Run the Claude Desktop redirect gateway
65834
+ ${green2("claudish update")} Check for updates and install the latest version
65835
+
65836
+ ${bold4("Profiles:")}
65837
+ ${green2("claudish init")} ${yellow2("[--local|--global]")} Setup wizard - create config + first profile
65838
+ ${green2("claudish profile list")} ${yellow2("[scope]")} List all profiles (both scopes by default)
65839
+ ${green2("claudish profile add")} ${yellow2("[scope]")} Add a new profile
65840
+ ${green2("claudish profile remove")} ${yellow2("[name] [scope]")} Remove a profile
65841
+ ${green2("claudish profile use")} ${yellow2("[name] [scope]")} Set default profile
65842
+ ${green2("claudish profile show")} ${yellow2("[name] [scope]")} Show profile details
65843
+ ${green2("claudish profile edit")} ${yellow2("[name] [scope]")} Edit a profile
65844
+ ${dim3("scope = --local (.claudish.json) | --global (~/.claudish/config.json) | (prompted)")}
65845
+
65846
+ ${bold4("Authentication:")}
65847
+ ${green2("claudish login")} ${yellow2("[provider]")} Login to an OAuth provider (interactive if omitted)
65848
+ ${green2("claudish logout")} ${yellow2("[provider]")} Clear OAuth credentials
65849
+ ${dim3("Providers: gemini, kimi")}
65850
+
65851
+ ${h("1PASSWORD")} ${dim3("(SDK-based \u2014 no op CLI needed for secrets)")}
65852
+ ${dim3("Auth via OP_SERVICE_ACCOUNT_TOKEN, or OP_ACCOUNT / onepasswordAccount config (DesktopAuth).")}
65853
+ ${green2("--op")} ${yellow2("<glob> --list")} Preview which fields a glob would import (names only)
65854
+ ${green2("--op")} ${yellow2("<glob>")} ${yellow2("[...args]")} Resolve a glob into env vars, then run a session
65855
+ ${dim3("Inline op import requires a GLOB (self-names via field labels)")}
65856
+ ${dim3('Example: claudish --op "op://Jack/Keys/**" --model gpt-4o "task"')}
65857
+ ${green2("--op-env")} ${yellow2("<id>")} Load a 1Password Environment (highest-priority source)
65858
+ ${dim3("Persistent setup (single refs, sets, environments, account): claudish config -> 1Password tab")}
65364
65859
 
65365
65860
  ${h("CLAUDE CODE FLAG PASSTHROUGH")}
65366
- ${dim2("Any unrecognized flag is forwarded to Claude Code. Claudish flags can appear in any order.")}
65367
- ${green("claudish")} --model grok ${yellow("--agent test")} ${yellow('"task"')} ${dim2("# --agent passes through")}
65368
- ${green("claudish")} --model grok ${yellow("--effort high")} --stdin ${yellow('"task"')} ${dim2("# --effort passes, --stdin stays")}
65369
- ${green("claudish")} --model grok ${yellow("--permission-mode plan")} -i ${dim2("# works in interactive too")}
65370
- ${dim2("Use -- when a Claude Code flag value starts with '-':")}
65371
- ${green("claudish")} --model grok ${green("--")} ${yellow('--system-prompt "-verbose mode" "task"')}
65861
+ ${dim3("Any unrecognized flag is forwarded to Claude Code. Claudish flags can appear in any order.")}
65862
+ ${green2("claudish")} --model grok ${yellow2("--agent test")} ${yellow2('"task"')} ${dim3("# --agent passes through")}
65863
+ ${green2("claudish")} --model grok ${yellow2("--effort high")} --stdin ${yellow2('"task"')} ${dim3("# --effort passes, --stdin stays")}
65864
+ ${green2("claudish")} --model grok ${yellow2("--permission-mode plan")} -i ${dim3("# works in interactive too")}
65865
+ ${dim3("Use -- when a Claude Code flag value starts with '-':")}
65866
+ ${green2("claudish")} --model grok ${green2("--")} ${yellow2('--system-prompt "-verbose mode" "task"')}
65372
65867
 
65373
65868
  ${h("CUSTOM MODELS & ENDPOINTS")}
65374
- ${dim2("Claudish accepts ANY valid model ID from the Firebase catalog, even if not in --models:")}
65375
- ${green("claudish")} --model ${yellow("openrouter@your_provider/custom-model-123")} ${yellow('"task"')}
65376
- ${dim2("Named custom endpoints live in ~/.claudish/config.json under 'customEndpoints' and route via @:")}
65377
- ${green("claudish")} --model ${yellow("my-vllm@llama3.1-70b")} ${yellow('"task"')}
65869
+ ${dim3("Claudish accepts ANY valid model ID from the Firebase catalog, even if not in --models:")}
65870
+ ${green2("claudish")} --model ${yellow2("openrouter@your_provider/custom-model-123")} ${yellow2('"task"')}
65871
+ ${dim3("Named custom endpoints live in ~/.claudish/config.json under 'customEndpoints' and route via @:")}
65872
+ ${green2("claudish")} --model ${yellow2("my-vllm@llama3.1-70b")} ${yellow2('"task"')}
65378
65873
 
65379
65874
  ${h("MODES")}
65380
- ${green("\u2022")} ${bold3("Interactive")} ${dim2("(default):")} shows model selector, starts a persistent session
65381
- ${green("\u2022")} ${bold3("Single-shot")} ${dim2("(--model):")} runs one task headless and exits
65875
+ ${green2("\u2022")} ${bold4("Interactive")} ${dim3("(default):")} shows model selector, starts a persistent session
65876
+ ${green2("\u2022")} ${bold4("Single-shot")} ${dim3("(--model):")} runs one task headless and exits
65382
65877
 
65383
65878
  ${h("NOTES")}
65384
- ${yellow("\u2022")} Permission prompts are ${bold3("ENABLED")} by default (normal Claude Code behavior)
65385
- ${yellow("\u2022")} Use ${green("-y")} / ${green("--auto-approve")} to skip permission prompts
65386
- ${yellow("\u2022")} Model selector appears ONLY in interactive mode when ${green("--model")} not specified
65387
- ${yellow("\u2022")} ${green("--dangerous")} disables the sandbox \u2014 use with extreme caution
65879
+ ${yellow2("\u2022")} Permission prompts are ${bold4("ENABLED")} by default (normal Claude Code behavior)
65880
+ ${yellow2("\u2022")} Use ${green2("-y")} / ${green2("--auto-approve")} to skip permission prompts
65881
+ ${yellow2("\u2022")} Model selector appears ONLY in interactive mode when ${green2("--model")} not specified
65882
+ ${yellow2("\u2022")} ${green2("--dangerous")} disables the sandbox \u2014 use with extreme caution
65388
65883
 
65389
65884
  ${h("ENVIRONMENT VARIABLES")}
65390
- ${dim2("Claudish auto-loads a .env file from the current directory.")}
65885
+ ${dim3("Claudish auto-loads a .env file from the current directory.")}
65391
65886
 
65392
- ${bold3("Claude Code installation:")}
65887
+ ${bold4("Claude Code installation:")}
65393
65888
  ${blue("CLAUDE_PATH")} Custom path to Claude Code binary
65394
- ${dim2("Search: CLAUDE_PATH -> ~/.claude/local/claude -> PATH")}
65889
+ ${dim3("Search: CLAUDE_PATH -> ~/.claude/local/claude -> PATH")}
65395
65890
 
65396
- ${bold3("API keys")} ${dim2("(at least one required for cloud models):")}
65891
+ ${bold4("API keys")} ${dim3("(at least one required for cloud models):")}
65397
65892
  ${blue("OPENROUTER_API_KEY")} OpenRouter (default backend)
65398
- ${blue("GEMINI_API_KEY")} Google Gemini ${dim2("(g@, gemini@; alias GOOGLE_API_KEY)")}
65399
- ${blue("OPENAI_API_KEY")} OpenAI ${dim2("(oai@)")}
65400
- ${blue("OPENAI_CODEX_API_KEY")} OpenAI Codex / Responses API ${dim2("(cx@, codex@)")}
65401
- ${blue("XAI_API_KEY")} xAI / Grok ${dim2("(x-ai@, grok@)")}
65402
- ${blue("MINIMAX_API_KEY")} MiniMax ${dim2("(mm@, mmax@)")}
65403
- ${blue("MINIMAX_CODING_API_KEY")} MiniMax Coding Plan ${dim2("(mmc@)")}
65404
- ${blue("MOONSHOT_API_KEY")} Kimi / Moonshot ${dim2("(kimi@, moon@; alias KIMI_API_KEY)")}
65405
- ${blue("KIMI_CODING_API_KEY")} Kimi Coding Plan ${dim2("(kc@)")}
65406
- ${blue("ZHIPU_API_KEY")} GLM / Zhipu ${dim2("(glm@, zhipu@; alias GLM_API_KEY)")}
65407
- ${blue("GLM_CODING_API_KEY")} GLM Coding Plan ${dim2("(gc@; alias ZAI_CODING_API_KEY)")}
65408
- ${blue("ZAI_API_KEY")} Z.AI ${dim2("(z-ai@, zai@)")}
65409
- ${blue("DEEPSEEK_API_KEY")} DeepSeek ${dim2("(ds@)")}
65410
- ${blue("SAKANA_API_KEY")} Sakana Fugu ${dim2("(sakana@, fugu@)")}
65411
- ${blue("SAKANA_SUBSCRIPTION_API_KEY")} Sakana Fugu Subscription ${dim2("(sc@; separate subscription key)")}
65412
- ${blue("OLLAMA_API_KEY")} OllamaCloud ${dim2("(oc@, llama@)")}
65413
- ${blue("OPENCODE_API_KEY")} OpenCode Zen ${dim2("(zen@; optional - free models work without it)")}
65414
- ${blue("POE_API_KEY")} Poe ${dim2("(poe@)")}
65415
- ${blue("LITELLM_API_KEY")} LiteLLM ${dim2("(litellm@, ll@; needs LITELLM_BASE_URL)")}
65416
- ${blue("VERTEX_API_KEY")} Vertex AI Express ${dim2("(v@)")}
65417
- ${blue("VERTEX_PROJECT")} Vertex AI project ID ${dim2("(OAuth mode, v@)")}
65418
- ${blue("VERTEX_LOCATION")} Vertex AI region ${dim2("(default: us-central1)")}
65893
+ ${blue("GEMINI_API_KEY")} Google Gemini ${dim3("(g@, gemini@; alias GOOGLE_API_KEY)")}
65894
+ ${blue("OPENAI_API_KEY")} OpenAI ${dim3("(oai@)")}
65895
+ ${blue("OPENAI_CODEX_API_KEY")} OpenAI Codex / Responses API ${dim3("(cx@, codex@)")}
65896
+ ${blue("XAI_API_KEY")} xAI / Grok ${dim3("(x-ai@, grok@)")}
65897
+ ${blue("MINIMAX_API_KEY")} MiniMax ${dim3("(mm@, mmax@)")}
65898
+ ${blue("MINIMAX_CODING_API_KEY")} MiniMax Coding Plan ${dim3("(mmc@)")}
65899
+ ${blue("MOONSHOT_API_KEY")} Kimi / Moonshot ${dim3("(kimi@, moon@; alias KIMI_API_KEY)")}
65900
+ ${blue("KIMI_CODING_API_KEY")} Kimi Coding Plan ${dim3("(kc@)")}
65901
+ ${blue("ZHIPU_API_KEY")} GLM / Zhipu ${dim3("(glm@, zhipu@; alias GLM_API_KEY)")}
65902
+ ${blue("GLM_CODING_API_KEY")} GLM Coding Plan ${dim3("(gc@; alias ZAI_CODING_API_KEY)")}
65903
+ ${blue("ZAI_API_KEY")} Z.AI ${dim3("(z-ai@, zai@)")}
65904
+ ${blue("DEEPSEEK_API_KEY")} DeepSeek ${dim3("(ds@)")}
65905
+ ${blue("SAKANA_API_KEY")} Sakana Fugu ${dim3("(sakana@, fugu@)")}
65906
+ ${blue("SAKANA_SUBSCRIPTION_API_KEY")} Sakana Fugu Subscription ${dim3("(sc@; separate subscription key)")}
65907
+ ${blue("OLLAMA_API_KEY")} OllamaCloud ${dim3("(oc@, llama@)")}
65908
+ ${blue("OPENCODE_API_KEY")} OpenCode Zen ${dim3("(zen@; optional - free models work without it)")}
65909
+ ${blue("POE_API_KEY")} Poe ${dim3("(poe@)")}
65910
+ ${blue("LITELLM_API_KEY")} LiteLLM ${dim3("(litellm@, ll@; needs LITELLM_BASE_URL)")}
65911
+ ${blue("VERTEX_API_KEY")} Vertex AI Express ${dim3("(v@)")}
65912
+ ${blue("VERTEX_PROJECT")} Vertex AI project ID ${dim3("(OAuth mode, v@)")}
65913
+ ${blue("VERTEX_LOCATION")} Vertex AI region ${dim3("(default: us-central1)")}
65419
65914
  ${blue("ANTHROPIC_API_KEY")} Placeholder (prevents Claude Code dialog)
65420
65915
  ${blue("ANTHROPIC_AUTH_TOKEN")} Placeholder (prevents Claude Code login screen)
65421
65916
 
65422
- ${bold3("Custom / base-URL overrides:")}
65917
+ ${bold4("Custom / base-URL overrides:")}
65423
65918
  ${blue("GEMINI_BASE_URL")} Custom Gemini endpoint
65424
65919
  ${blue("OPENAI_BASE_URL")} Custom OpenAI / Azure endpoint
65425
65920
  ${blue("MINIMAX_BASE_URL")} Custom MiniMax endpoint
65426
- ${blue("MOONSHOT_BASE_URL")} Custom Kimi / Moonshot endpoint ${dim2("(alias KIMI_BASE_URL)")}
65427
- ${blue("ZHIPU_BASE_URL")} Custom GLM / Zhipu endpoint ${dim2("(alias GLM_BASE_URL)")}
65428
- ${blue("SAKANA_BASE_URL")} Custom Sakana endpoint ${dim2("(default: https://api.sakana.ai)")}
65429
- ${blue("LITELLM_BASE_URL")} LiteLLM gateway base URL ${dim2("(required for ll@)")}
65430
- ${blue("OLLAMACLOUD_BASE_URL")} OllamaCloud ${dim2("(default: https://ollama.com)")}
65431
- ${blue("OPENCODE_BASE_URL")} OpenCode Zen ${dim2("(default: https://opencode.ai/zen)")}
65432
-
65433
- ${bold3("Local providers:")}
65434
- ${blue("OLLAMA_BASE_URL")} Ollama server ${dim2("(default: http://localhost:11434; alias OLLAMA_HOST)")}
65435
- ${blue("LMSTUDIO_BASE_URL")} LM Studio server ${dim2("(default: http://localhost:1234)")}
65436
- ${blue("VLLM_BASE_URL")} vLLM server ${dim2("(default: http://localhost:8000)")}
65437
- ${blue("MLX_BASE_URL")} MLX server ${dim2("(default: http://127.0.0.1:8080)")}
65438
-
65439
- ${bold3("Claudish settings:")}
65440
- ${blue("CLAUDISH_MODEL")} Default model ${dim2("(default: openai/gpt-5.3)")}
65441
- ${blue("CLAUDISH_DEFAULT_PROVIDER")} Fallback provider for bare names ${dim2("(see --default-provider)")}
65921
+ ${blue("MOONSHOT_BASE_URL")} Custom Kimi / Moonshot endpoint ${dim3("(alias KIMI_BASE_URL)")}
65922
+ ${blue("ZHIPU_BASE_URL")} Custom GLM / Zhipu endpoint ${dim3("(alias GLM_BASE_URL)")}
65923
+ ${blue("SAKANA_BASE_URL")} Custom Sakana endpoint ${dim3("(default: https://api.sakana.ai)")}
65924
+ ${blue("LITELLM_BASE_URL")} LiteLLM gateway base URL ${dim3("(required for ll@)")}
65925
+ ${blue("OLLAMACLOUD_BASE_URL")} OllamaCloud ${dim3("(default: https://ollama.com)")}
65926
+ ${blue("OPENCODE_BASE_URL")} OpenCode Zen ${dim3("(default: https://opencode.ai/zen)")}
65927
+
65928
+ ${bold4("Local providers:")}
65929
+ ${blue("OLLAMA_BASE_URL")} Ollama server ${dim3("(default: http://localhost:11434; alias OLLAMA_HOST)")}
65930
+ ${blue("LMSTUDIO_BASE_URL")} LM Studio server ${dim3("(default: http://localhost:1234)")}
65931
+ ${blue("VLLM_BASE_URL")} vLLM server ${dim3("(default: http://localhost:8000)")}
65932
+ ${blue("MLX_BASE_URL")} MLX server ${dim3("(default: http://127.0.0.1:8080)")}
65933
+
65934
+ ${bold4("Claudish settings:")}
65935
+ ${blue("CLAUDISH_MODEL")} Default model ${dim3("(default: openai/gpt-5.3)")}
65936
+ ${blue("CLAUDISH_DEFAULT_PROVIDER")} Fallback provider for bare names ${dim3("(see --default-provider)")}
65442
65937
  ${blue("CLAUDISH_PORT")} Default proxy port
65443
65938
  ${blue("CLAUDISH_CONTEXT_WINDOW")} Override context window size
65444
65939
  ${blue("CLAUDISH_DIAG_MODE")} Diagnostic output: auto / logfile / off
65445
- ${blue("CLAUDISH_DEBUG")} Always enable debug logging: 1 / true ${dim2("(same as -d)")}
65446
- ${blue("CLAUDISH_ANTHROPIC_API_BILLING")} Bill native Claude to your API key ${dim2("(see --anthropic-api-billing)")}
65940
+ ${blue("CLAUDISH_DEBUG")} Always enable debug logging: 1 / true ${dim3("(same as -d)")}
65941
+ ${blue("CLAUDISH_ANTHROPIC_API_BILLING")} Bill native Claude to your API key ${dim3("(see --anthropic-api-billing)")}
65447
65942
  ${blue("CLAUDISH_MCP_TOOLS")} MCP tool gating: all / low-level / agentic / channel
65448
65943
  ${blue("CLAUDISH_MODEL_OPUS")} Override model for Opus role
65449
65944
  ${blue("CLAUDISH_MODEL_SONNET")} Override model for Sonnet role
@@ -65451,47 +65946,47 @@ ${h("ENVIRONMENT VARIABLES")}
65451
65946
  ${blue("CLAUDISH_MODEL_SUBAGENT")} Override model for sub-agents
65452
65947
  ${blue("NO_COLOR")} Set to disable colored output
65453
65948
 
65454
- ${bold3("1Password auth:")}
65949
+ ${bold4("1Password auth:")}
65455
65950
  ${blue("OP_SERVICE_ACCOUNT_TOKEN")} Service-account token (preferred for headless)
65456
- ${blue("OP_ACCOUNT")} Account URL for DesktopAuth ${dim2("(e.g. my-team.1password.com)")}
65951
+ ${blue("OP_ACCOUNT")} Account URL for DesktopAuth ${dim3("(e.g. my-team.1password.com)")}
65457
65952
 
65458
65953
  ${h("EXAMPLES")}
65459
- ${dim2("# Interactive (default) - model selector")}
65460
- ${green("claudish")}
65461
- ${green("claudish")} --free ${dim2("# only FREE models")}
65954
+ ${dim3("# Interactive (default) - model selector")}
65955
+ ${green2("claudish")}
65956
+ ${green2("claudish")} --free ${dim3("# only FREE models")}
65462
65957
 
65463
- ${dim2("# Explicit provider routing")}
65464
- ${green("claudish")} --model ${magenta("google@gemini-3-pro")} ${yellow('"implement auth"')}
65465
- ${green("claudish")} --model ${magenta("oai@gpt-5.3")} ${yellow('"add tests for login"')}
65466
- ${green("claudish")} --model ${magenta("openrouter@deepseek/deepseek-r1")} ${yellow('"unknown vendor"')}
65958
+ ${dim3("# Explicit provider routing")}
65959
+ ${green2("claudish")} --model ${magenta("google@gemini-3-pro")} ${yellow2('"implement auth"')}
65960
+ ${green2("claudish")} --model ${magenta("oai@gpt-5.3")} ${yellow2('"add tests for login"')}
65961
+ ${green2("claudish")} --model ${magenta("openrouter@deepseek/deepseek-r1")} ${yellow2('"unknown vendor"')}
65467
65962
 
65468
- ${dim2("# Native auto-detection (provider inferred from model name)")}
65469
- ${green("claudish")} --model ${yellow("gpt-4o")} ${yellow('"routes to OpenAI"')}
65470
- ${green("claudish")} --model ${yellow("gemini-2.5-pro")} ${yellow('"routes to Google"')}
65963
+ ${dim3("# Native auto-detection (provider inferred from model name)")}
65964
+ ${green2("claudish")} --model ${yellow2("gpt-4o")} ${yellow2('"routes to OpenAI"')}
65965
+ ${green2("claudish")} --model ${yellow2("gemini-2.5-pro")} ${yellow2('"routes to Google"')}
65471
65966
 
65472
- ${dim2("# Per-role model mapping")}
65473
- ${green("claudish")} --model-opus ${magenta("oai@gpt-5.3")} --model-sonnet ${magenta("google@gemini-3-pro")}
65967
+ ${dim3("# Per-role model mapping")}
65968
+ ${green2("claudish")} --model-opus ${magenta("oai@gpt-5.3")} --model-sonnet ${magenta("google@gemini-3-pro")}
65474
65969
 
65475
- ${dim2("# stdin for large prompts (diffs, code review)")}
65476
- ${dim2("git diff |")} ${green("claudish")} --stdin --model ${magenta("oai@gpt-5.3")} ${yellow('"Review these changes"')}
65970
+ ${dim3("# stdin for large prompts (diffs, code review)")}
65971
+ ${dim3("git diff |")} ${green2("claudish")} --stdin --model ${magenta("oai@gpt-5.3")} ${yellow2('"Review these changes"')}
65477
65972
 
65478
- ${dim2("# Local models with concurrency control")}
65479
- ${green("claudish")} --model ${magenta("ollama@llama3.2:3")} ${yellow('"3 concurrent requests"')}
65480
- ${green("claudish")} --model ${magenta("lms@qwen2.5-coder")} ${yellow('"LM Studio shortcut"')}
65481
- ${green("claudish")} --model ${yellow('"http://localhost:8000/mistral"')} ${yellow('"any OpenAI-compatible URL"')}
65973
+ ${dim3("# Local models with concurrency control")}
65974
+ ${green2("claudish")} --model ${magenta("ollama@llama3.2:3")} ${yellow2('"3 concurrent requests"')}
65975
+ ${green2("claudish")} --model ${magenta("lms@qwen2.5-coder")} ${yellow2('"LM Studio shortcut"')}
65976
+ ${green2("claudish")} --model ${yellow2('"http://localhost:8000/mistral"')} ${yellow2('"any OpenAI-compatible URL"')}
65482
65977
 
65483
- ${dim2("# Autonomous (no prompts, no sandbox) \u2014 use with caution")}
65484
- ${green("claudish")} -y --dangerous ${yellow('"refactor entire codebase"')}
65978
+ ${dim3("# Autonomous (no prompts, no sandbox) \u2014 use with caution")}
65979
+ ${green2("claudish")} -y --dangerous ${yellow2('"refactor entire codebase"')}
65485
65980
 
65486
65981
  ${h("MORE INFO")}
65487
- ${dim2("GitHub:")} ${blue("https://github.com/MadAppGang/claude-code")}
65488
- ${dim2("OpenRouter:")} ${blue("https://openrouter.ai")}
65982
+ ${dim3("GitHub:")} ${blue("https://github.com/MadAppGang/claude-code")}
65983
+ ${dim3("OpenRouter:")} ${blue("https://openrouter.ai")}
65489
65984
  `);
65490
65985
  }
65491
65986
  function printAIAgentGuide() {
65492
65987
  try {
65493
- const guidePath = join24(__dirname3, "../AI_AGENT_GUIDE.md");
65494
- const guideContent = readFileSync20(guidePath, "utf-8");
65988
+ const guidePath = join27(__dirname3, "../AI_AGENT_GUIDE.md");
65989
+ const guideContent = readFileSync21(guidePath, "utf-8");
65495
65990
  console.log(guideContent);
65496
65991
  } catch (error46) {
65497
65992
  console.error("Error reading AI Agent Guide:");
@@ -65507,10 +66002,10 @@ async function initializeClaudishSkill() {
65507
66002
  console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
65508
66003
  `);
65509
66004
  const cwd = process.cwd();
65510
- const claudeDir = join24(cwd, ".claude");
65511
- const skillsDir = join24(claudeDir, "skills");
65512
- const claudishSkillDir = join24(skillsDir, "claudish-usage");
65513
- const skillFile = join24(claudishSkillDir, "SKILL.md");
66005
+ const claudeDir = join27(cwd, ".claude");
66006
+ const skillsDir = join27(claudeDir, "skills");
66007
+ const claudishSkillDir = join27(skillsDir, "claudish-usage");
66008
+ const skillFile = join27(claudishSkillDir, "SKILL.md");
65514
66009
  if (existsSync21(skillFile)) {
65515
66010
  console.log("\u2705 Claudish skill already installed at:");
65516
66011
  console.log(` ${skillFile}
@@ -65518,7 +66013,7 @@ async function initializeClaudishSkill() {
65518
66013
  console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
65519
66014
  return;
65520
66015
  }
65521
- const sourceSkillPath = join24(__dirname3, "../skills/claudish-usage/SKILL.md");
66016
+ const sourceSkillPath = join27(__dirname3, "../skills/claudish-usage/SKILL.md");
65522
66017
  if (!existsSync21(sourceSkillPath)) {
65523
66018
  console.error("\u274C Error: Claudish skill file not found in installation.");
65524
66019
  console.error(` Expected at: ${sourceSkillPath}`);
@@ -65609,7 +66104,7 @@ var init_cli = __esm(() => {
65609
66104
  init_routing_rules();
65610
66105
  init_provider_resolver();
65611
66106
  __filename3 = fileURLToPath2(import.meta.url);
65612
- __dirname3 = dirname8(__filename3);
66107
+ __dirname3 = dirname9(__filename3);
65613
66108
  });
65614
66109
 
65615
66110
  // src/update-checker.ts
@@ -65621,24 +66116,24 @@ __export(exports_update_checker, {
65621
66116
  clearCache: () => clearCache,
65622
66117
  checkForUpdates: () => checkForUpdates
65623
66118
  });
65624
- import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync21, unlinkSync as unlinkSync8, writeFileSync as writeFileSync16 } from "fs";
65625
- import { homedir as homedir23, platform as platform2, tmpdir } from "os";
65626
- import { join as join25 } from "path";
66119
+ import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync22, unlinkSync as unlinkSync8, writeFileSync as writeFileSync16 } from "fs";
66120
+ import { homedir as homedir26, platform as platform2, tmpdir } from "os";
66121
+ import { join as join28 } from "path";
65627
66122
  function getCacheFilePath() {
65628
66123
  let cacheDir;
65629
66124
  if (isWindows) {
65630
- const localAppData = process.env.LOCALAPPDATA || join25(homedir23(), "AppData", "Local");
65631
- cacheDir = join25(localAppData, "claudish");
66125
+ const localAppData = process.env.LOCALAPPDATA || join28(homedir26(), "AppData", "Local");
66126
+ cacheDir = join28(localAppData, "claudish");
65632
66127
  } else {
65633
- cacheDir = join25(homedir23(), ".cache", "claudish");
66128
+ cacheDir = join28(homedir26(), ".cache", "claudish");
65634
66129
  }
65635
66130
  try {
65636
66131
  if (!existsSync22(cacheDir)) {
65637
66132
  mkdirSync14(cacheDir, { recursive: true });
65638
66133
  }
65639
- return join25(cacheDir, "update-check.json");
66134
+ return join28(cacheDir, "update-check.json");
65640
66135
  } catch {
65641
- return join25(tmpdir(), "claudish-update-check.json");
66136
+ return join28(tmpdir(), "claudish-update-check.json");
65642
66137
  }
65643
66138
  }
65644
66139
  function readCache() {
@@ -65647,7 +66142,7 @@ function readCache() {
65647
66142
  if (!existsSync22(cachePath)) {
65648
66143
  return null;
65649
66144
  }
65650
- const data = JSON.parse(readFileSync21(cachePath, "utf-8"));
66145
+ const data = JSON.parse(readFileSync22(cachePath, "utf-8"));
65651
66146
  return data;
65652
66147
  } catch {
65653
66148
  return null;
@@ -66549,15 +67044,15 @@ var init_local_liveness = __esm(() => {
66549
67044
  });
66550
67045
 
66551
67046
  // src/providers/probe-catalog.ts
66552
- import { existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as readFileSync22, writeFileSync as writeFileSync17 } from "fs";
66553
- import { homedir as homedir24 } from "os";
66554
- import { dirname as dirname9, join as join26 } from "path";
67047
+ import { existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as readFileSync23, writeFileSync as writeFileSync17 } from "fs";
67048
+ import { homedir as homedir27 } from "os";
67049
+ import { dirname as dirname10, join as join29 } from "path";
66555
67050
  function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
66556
67051
  if (!existsSync23(path2))
66557
67052
  return null;
66558
67053
  let raw2;
66559
67054
  try {
66560
- raw2 = JSON.parse(readFileSync22(path2, "utf-8"));
67055
+ raw2 = JSON.parse(readFileSync23(path2, "utf-8"));
66561
67056
  } catch {
66562
67057
  return null;
66563
67058
  }
@@ -66566,7 +67061,7 @@ function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
66566
67061
  return raw2;
66567
67062
  }
66568
67063
  function writeProbeModelsCache(data, path2 = PROBE_MODELS_CACHE_PATH) {
66569
- mkdirSync15(dirname9(path2), { recursive: true });
67064
+ mkdirSync15(dirname10(path2), { recursive: true });
66570
67065
  writeFileSync17(path2, JSON.stringify(data), "utf-8");
66571
67066
  }
66572
67067
  function isCacheFresh(data, ttlMs = CACHE_TTL_MS4) {
@@ -66686,7 +67181,7 @@ function isValidResponse(raw2) {
66686
67181
  var PROBE_MODELS_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/probeModels", CACHE_TTL_MS4, FETCH_TIMEOUT_MS3 = 15000, PROBE_MODELS_CACHE_PATH, _inFlight = null;
66687
67182
  var init_probe_catalog = __esm(() => {
66688
67183
  CACHE_TTL_MS4 = 60 * 60 * 1000;
66689
- PROBE_MODELS_CACHE_PATH = join26(homedir24(), ".claudish", "probe-models.json");
67184
+ PROBE_MODELS_CACHE_PATH = join29(homedir27(), ".claudish", "probe-models.json");
66690
67185
  });
66691
67186
 
66692
67187
  // src/tui/constants.ts
@@ -73026,12 +73521,12 @@ import {
73026
73521
  existsSync as existsSync24,
73027
73522
  mkdirSync as mkdirSync16,
73028
73523
  openSync as openSync5,
73029
- readFileSync as readFileSync23,
73524
+ readFileSync as readFileSync24,
73030
73525
  unlinkSync as unlinkSync9,
73031
73526
  writeFileSync as writeFileSync18
73032
73527
  } from "fs";
73033
- import { homedir as homedir25, tmpdir as tmpdir2 } from "os";
73034
- import { join as join27 } from "path";
73528
+ import { homedir as homedir28, tmpdir as tmpdir2 } from "os";
73529
+ import { join as join30 } from "path";
73035
73530
  import { isatty } from "tty";
73036
73531
  function releaseTerminalIsolation() {
73037
73532
  if (!restoreTerminal)
@@ -73066,14 +73561,14 @@ function isProxyAuthMode(config3) {
73066
73561
  }
73067
73562
  function managedSettingsPath() {
73068
73563
  if (isWindows2()) {
73069
- return join27(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
73564
+ return join30(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
73070
73565
  }
73071
73566
  if (process.platform === "darwin") {
73072
73567
  return "/Library/Application Support/ClaudeCode/managed-settings.json";
73073
73568
  }
73074
73569
  return "/etc/claude-code/managed-settings.json";
73075
73570
  }
73076
- function managedSettingsForcesClaudeAi(readFile = readFileSync23) {
73571
+ function managedSettingsForcesClaudeAi(readFile = readFileSync24) {
73077
73572
  try {
73078
73573
  const raw2 = readFile(managedSettingsPath(), "utf-8");
73079
73574
  const parsed = JSON.parse(raw2);
@@ -73087,9 +73582,9 @@ function isWindows2() {
73087
73582
  }
73088
73583
  function createStatusLineScript(tokenFilePath) {
73089
73584
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
73090
- const claudishDir = join27(homeDir, ".claudish");
73585
+ const claudishDir = join30(homeDir, ".claudish");
73091
73586
  const timestamp = Date.now();
73092
- const scriptPath = join27(claudishDir, `status-${timestamp}.js`);
73587
+ const scriptPath = join30(claudishDir, `status-${timestamp}.js`);
73093
73588
  const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
73094
73589
  const script = `
73095
73590
  const fs = require('fs');
@@ -73212,13 +73707,13 @@ process.stdin.on('end', () => {
73212
73707
  }
73213
73708
  function createTempSettingsFile(_modelDisplay, port, proxyAuthMode) {
73214
73709
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
73215
- const claudishDir = join27(homeDir, ".claudish");
73710
+ const claudishDir = join30(homeDir, ".claudish");
73216
73711
  try {
73217
73712
  mkdirSync16(claudishDir, { recursive: true });
73218
73713
  } catch {}
73219
73714
  const timestamp = Date.now();
73220
- const tempPath = join27(claudishDir, `settings-${timestamp}.json`);
73221
- const tokenFilePath = join27(claudishDir, `tokens-${port}.json`);
73715
+ const tempPath = join30(claudishDir, `settings-${timestamp}.json`);
73716
+ const tokenFilePath = join30(claudishDir, `tokens-${port}.json`);
73222
73717
  let statusCommand;
73223
73718
  if (isWindows2()) {
73224
73719
  const scriptPath = createStatusLineScript(tokenFilePath);
@@ -73262,7 +73757,7 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine, proxy
73262
73757
  if (userSettingsValue.trimStart().startsWith("{")) {
73263
73758
  userSettings = JSON.parse(userSettingsValue);
73264
73759
  } else {
73265
- const rawUserSettings = readFileSync23(userSettingsValue, "utf-8");
73760
+ const rawUserSettings = readFileSync24(userSettingsValue, "utf-8");
73266
73761
  userSettings = JSON.parse(rawUserSettings);
73267
73762
  }
73268
73763
  userSettings.statusLine = statusLine;
@@ -73433,8 +73928,8 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
73433
73928
  console.error("Install it from: https://claude.com/claude-code");
73434
73929
  console.error(`
73435
73930
  Or set CLAUDE_PATH to your custom installation:`);
73436
- const home = homedir25();
73437
- const localPath = isWindows2() ? join27(home, ".claude", "local", "claude.exe") : join27(home, ".claude", "local", "claude");
73931
+ const home = homedir28();
73932
+ const localPath = isWindows2() ? join30(home, ".claude", "local", "claude.exe") : join30(home, ".claude", "local", "claude");
73438
73933
  console.error(` export CLAUDE_PATH=${localPath}`);
73439
73934
  process.exit(1);
73440
73935
  }
@@ -73518,16 +74013,16 @@ async function findClaudeBinary() {
73518
74013
  return process.env.CLAUDE_PATH;
73519
74014
  }
73520
74015
  }
73521
- const home = homedir25();
73522
- const localPath = isWindows3 ? join27(home, ".claude", "local", "claude.exe") : join27(home, ".claude", "local", "claude");
74016
+ const home = homedir28();
74017
+ const localPath = isWindows3 ? join30(home, ".claude", "local", "claude.exe") : join30(home, ".claude", "local", "claude");
73523
74018
  if (existsSync24(localPath)) {
73524
74019
  return localPath;
73525
74020
  }
73526
74021
  if (isWindows3) {
73527
74022
  const windowsPaths = [
73528
- join27(home, "AppData", "Roaming", "npm", "claude.cmd"),
73529
- join27(home, ".npm-global", "claude.cmd"),
73530
- join27(home, "node_modules", ".bin", "claude.cmd")
74023
+ join30(home, "AppData", "Roaming", "npm", "claude.cmd"),
74024
+ join30(home, ".npm-global", "claude.cmd"),
74025
+ join30(home, "node_modules", ".bin", "claude.cmd")
73531
74026
  ];
73532
74027
  for (const path2 of windowsPaths) {
73533
74028
  if (existsSync24(path2)) {
@@ -73538,11 +74033,11 @@ async function findClaudeBinary() {
73538
74033
  const commonPaths = [
73539
74034
  "/usr/local/bin/claude",
73540
74035
  "/opt/homebrew/bin/claude",
73541
- join27(home, ".npm-global/bin/claude"),
73542
- join27(home, ".local/bin/claude"),
73543
- join27(home, "node_modules/.bin/claude"),
74036
+ join30(home, ".npm-global/bin/claude"),
74037
+ join30(home, ".local/bin/claude"),
74038
+ join30(home, "node_modules/.bin/claude"),
73544
74039
  "/data/data/com.termux/files/usr/bin/claude",
73545
- join27(home, "../usr/bin/claude")
74040
+ join30(home, "../usr/bin/claude")
73546
74041
  ];
73547
74042
  for (const path2 of commonPaths) {
73548
74043
  if (existsSync24(path2)) {
@@ -73603,17 +74098,17 @@ __export(exports_diag_output, {
73603
74098
  LogFileDiagOutput: () => LogFileDiagOutput
73604
74099
  });
73605
74100
  import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync17, unlinkSync as unlinkSync10, writeFileSync as writeFileSync19 } from "fs";
73606
- import { homedir as homedir26 } from "os";
73607
- import { join as join28 } from "path";
74101
+ import { homedir as homedir29 } from "os";
74102
+ import { join as join31 } from "path";
73608
74103
  function getClaudishDir() {
73609
- const dir = join28(homedir26(), ".claudish");
74104
+ const dir = join31(homedir29(), ".claudish");
73610
74105
  try {
73611
74106
  mkdirSync17(dir, { recursive: true });
73612
74107
  } catch {}
73613
74108
  return dir;
73614
74109
  }
73615
74110
  function getDiagLogPath() {
73616
- return join28(getClaudishDir(), `diag-${process.pid}.log`);
74111
+ return join31(getClaudishDir(), `diag-${process.pid}.log`);
73617
74112
  }
73618
74113
 
73619
74114
  class LogFileDiagOutput {
@@ -73824,9 +74319,9 @@ __export(exports_team_grid, {
73824
74319
  });
73825
74320
  import { spawn as spawn5 } from "child_process";
73826
74321
  import { execSync as execSync2 } from "child_process";
73827
- import { existsSync as existsSync25, readFileSync as readFileSync24, writeFileSync as writeFileSync20 } from "fs";
74322
+ import { existsSync as existsSync25, readFileSync as readFileSync25, writeFileSync as writeFileSync20 } from "fs";
73828
74323
  import { connect as netConnect } from "net";
73829
- import { dirname as dirname10, join as join29 } from "path";
74324
+ import { dirname as dirname11, join as join32 } from "path";
73830
74325
  import { setTimeout as wait } from "timers/promises";
73831
74326
  import { fileURLToPath as fileURLToPath3 } from "url";
73832
74327
  function resolveRouteInfo(modelId) {
@@ -73919,21 +74414,21 @@ function buildPaneHeader(model, prompt, bg) {
73919
74414
  }
73920
74415
  function findMagmuxBinary() {
73921
74416
  const thisFile = fileURLToPath3(import.meta.url);
73922
- const thisDir = dirname10(thisFile);
73923
- const pkgRoot = join29(thisDir, "..");
74417
+ const thisDir = dirname11(thisFile);
74418
+ const pkgRoot = join32(thisDir, "..");
73924
74419
  const platform3 = process.platform;
73925
74420
  const arch = process.arch;
73926
- const bundledMagmux = join29(pkgRoot, "native", `magmux-${platform3}-${arch}`);
74421
+ const bundledMagmux = join32(pkgRoot, "native", `magmux-${platform3}-${arch}`);
73927
74422
  if (existsSync25(bundledMagmux))
73928
74423
  return bundledMagmux;
73929
74424
  try {
73930
74425
  const pkgName = `@claudish/magmux-${platform3}-${arch}`;
73931
74426
  let searchDir = pkgRoot;
73932
74427
  for (let i = 0;i < 5; i++) {
73933
- const candidate = join29(searchDir, "node_modules", pkgName, "bin", "magmux");
74428
+ const candidate = join32(searchDir, "node_modules", pkgName, "bin", "magmux");
73934
74429
  if (existsSync25(candidate))
73935
74430
  return candidate;
73936
- const parent = dirname10(searchDir);
74431
+ const parent = dirname11(searchDir);
73937
74432
  if (parent === searchDir)
73938
74433
  break;
73939
74434
  searchDir = parent;
@@ -74037,9 +74532,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
74037
74532
  const keep = opts?.keep ?? false;
74038
74533
  const manifest = setupSession(sessionPath, models, input);
74039
74534
  const startedAt = new Date().toISOString();
74040
- const gridfilePath = join29(sessionPath, "gridfile.txt");
74041
- const prompt = readFileSync24(join29(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
74042
- const rawPrompt = readFileSync24(join29(sessionPath, "input.md"), "utf-8");
74535
+ const gridfilePath = join32(sessionPath, "gridfile.txt");
74536
+ const prompt = readFileSync25(join32(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
74537
+ const rawPrompt = readFileSync25(join32(sessionPath, "input.md"), "utf-8");
74043
74538
  const usedBannerColors = new Set;
74044
74539
  const gridLines = Object.entries(manifest.models).map(([anonId]) => {
74045
74540
  const model = manifest.models[anonId].model;
@@ -74070,7 +74565,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
74070
74565
  });
74071
74566
  const [{ results }] = await Promise.all([subscription, procExit]);
74072
74567
  const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
74073
- const statusPath = join29(sessionPath, "status.json");
74568
+ const statusPath = join32(sessionPath, "status.json");
74074
74569
  writeFileSync20(statusPath, JSON.stringify(status, null, 2), "utf-8");
74075
74570
  return status;
74076
74571
  }
@@ -74094,8 +74589,8 @@ var init_team_grid = __esm(() => {
74094
74589
  init_op_source();
74095
74590
  init_startup_trace();
74096
74591
  var import_dotenv3 = __toESM(require_main(), 1);
74097
- import { existsSync as existsSync26, readFileSync as readFileSync25 } from "fs";
74098
- import { join as join30, resolve as resolve4 } from "path";
74592
+ import { existsSync as existsSync26, readFileSync as readFileSync26 } from "fs";
74593
+ import { join as join33, resolve as resolve4 } from "path";
74099
74594
  import_dotenv3.config({ quiet: true });
74100
74595
  function classifyStartupKind() {
74101
74596
  const argv = process.argv.slice(2);
@@ -74228,6 +74723,7 @@ var isStatsCommand = firstPositional === "stats";
74228
74723
  var isConfigCommand = firstPositional === "config";
74229
74724
  var isServeCommand = firstPositional === "serve";
74230
74725
  var isProvidersCommand = firstPositional === "providers";
74726
+ var isBehaviorCommand = firstPositional === "behavior";
74231
74727
  var isLoginCommand = firstPositional === "login";
74232
74728
  var isLogoutCommand = firstPositional === "logout";
74233
74729
  var isQuotaCommand = firstPositional === "quota" || firstPositional === "usage";
@@ -74243,6 +74739,12 @@ if (isMcpMode) {
74243
74739
  console.error(`[claudish serve] ${e instanceof Error ? e.message : String(e)}`);
74244
74740
  process.exit(1);
74245
74741
  }));
74742
+ } else if (isBehaviorCommand) {
74743
+ const behaviorArgIndex = args.indexOf("behavior");
74744
+ Promise.resolve().then(() => (init_behavior_command(), exports_behavior_command)).then((m) => m.behaviorCommand(args.slice(behaviorArgIndex + 1)).catch((e) => {
74745
+ console.error(`[claudish behavior] ${e instanceof Error ? e.message : String(e)}`);
74746
+ process.exit(1);
74747
+ }));
74246
74748
  } else if (isProvidersCommand) {
74247
74749
  const json2 = args.includes("--json");
74248
74750
  Promise.resolve().then(() => (init_providers_command(), exports_providers_command)).then((m) => m.providersCommand({ json: json2 }).catch((e) => {
@@ -74329,14 +74831,14 @@ async function runCli() {
74329
74831
  if (cliConfig.team && cliConfig.team.length > 0) {
74330
74832
  let prompt = cliConfig.claudeArgs.join(" ");
74331
74833
  if (cliConfig.inputFile) {
74332
- prompt = readFileSync25(cliConfig.inputFile, "utf-8");
74834
+ prompt = readFileSync26(cliConfig.inputFile, "utf-8");
74333
74835
  }
74334
74836
  if (!prompt.trim()) {
74335
74837
  console.error("Error: --team requires a prompt (positional args or -f <file>)");
74336
74838
  process.exit(1);
74337
74839
  }
74338
74840
  const mode = cliConfig.teamMode ?? "default";
74339
- const sessionPath = join30(process.cwd(), `.claudish-team-${Date.now()}`);
74841
+ const sessionPath = join33(process.cwd(), `.claudish-team-${Date.now()}`);
74340
74842
  if (mode === "json") {
74341
74843
  const { setupSession: setupSession2, runModels: runModels2 } = await Promise.resolve().then(() => (init_team_orchestrator(), exports_team_orchestrator));
74342
74844
  setupSession2(sessionPath, cliConfig.team, prompt);
@@ -74346,9 +74848,9 @@ async function runCli() {
74346
74848
  });
74347
74849
  const result = { ...status2, responses: {} };
74348
74850
  for (const anonId of Object.keys(status2.models)) {
74349
- const responsePath = join30(sessionPath, `response-${anonId}.md`);
74851
+ const responsePath = join33(sessionPath, `response-${anonId}.md`);
74350
74852
  try {
74351
- const raw2 = readFileSync25(responsePath, "utf-8").trim();
74853
+ const raw2 = readFileSync26(responsePath, "utf-8").trim();
74352
74854
  try {
74353
74855
  result.responses[anonId] = JSON.parse(raw2);
74354
74856
  } catch {