claudish 10.6.1 → 10.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AI_AGENT_GUIDE.md CHANGED
@@ -437,52 +437,75 @@ Claude: [calls compare_models tool with models=["openai/gpt-5.3", "google/gemini
437
437
  ### JSON Output (Recommended)
438
438
 
439
439
  ```bash
440
- claudish --models --json
440
+ claudish --models-top --json
441
441
  ```
442
442
 
443
- **Output:**
443
+ **Output** (abridged; one row shown):
444
444
  ```json
445
445
  {
446
- "version": "1.8.0",
447
- "lastUpdated": "2025-11-19",
448
- "source": "https://openrouter.ai/models",
446
+ "contractVersion": 3,
447
+ "generationId": "g-20261016120000000-abcdef12",
448
+ "version": "g-20261016120000000-abcdef12",
449
+ "lastUpdated": "2026-10-16T12:00:00.000Z",
450
+ "generatedAt": "2026-10-16T12:00:00.000Z",
451
+ "recommendationTiers": ["flagship", "cost_efficient", "lightweight", "luxury", "subscription"],
449
452
  "models": [
450
453
  {
451
- "id": "x-ai/grok-code-fast-1",
454
+ "id": "grok-code-fast-1",
452
455
  "name": "Grok Code Fast 1",
453
456
  "description": "Ultra-fast agentic coding",
454
- "provider": "xAI",
455
- "category": "coding",
457
+ "provider": "x-ai",
458
+ "recommendationTier": "flagship",
456
459
  "priority": 1,
457
460
  "pricing": {
458
- "input": "$0.20/1M",
459
- "output": "$1.50/1M",
461
+ "input": "$0.2/1M",
462
+ "output": "$1.5/1M",
460
463
  "average": "$0.85/1M"
461
464
  },
462
- "context": "256K",
463
- "supportsTools": true,
464
- "supportsReasoning": true
465
+ "context": "256000"
465
466
  }
466
467
  ]
467
468
  }
468
469
  ```
469
470
 
471
+ `recommendationTier` is one of `flagship`, `cost_efficient`, `lightweight`, `luxury` or
472
+ `subscription`; `recommendationTiers` lists the tiers this claudish version knows. `priority` is
473
+ the rank within that tier, from 1. A model listed in two tiers is two rows, so dedupe ids
474
+ yourself. Only `subscription` rows carry `subscriptions[].command`, the model spec to run.
475
+ Prices are `"N/A"` when the catalog has none.
476
+
477
+ `claudish --models --json` prints the full catalog instead; its records carry no
478
+ `recommendationTier`.
479
+
480
+ ### Filter with jq
481
+
482
+ ```bash
483
+ # Flagship model ids, in rank order
484
+ claudish --models-top --json | jq -r '.models | map(select(.recommendationTier == "flagship")) | sort_by(.priority) | .[].id'
485
+
486
+ # Runnable subscription commands
487
+ claudish --models-top --json | jq -r '.models[] | select(.recommendationTier == "subscription") | .subscriptions[]?.command'
488
+ ```
489
+
470
490
  ### Parse in TypeScript
471
491
 
472
492
  ```typescript
473
- const { stdout } = await Bash("claudish --models --json");
493
+ const { stdout } = await Bash("claudish --models-top --json");
474
494
  const data = JSON.parse(stdout);
475
495
 
476
- // Get all model IDs
477
- const modelIds = data.models.map(m => m.id);
496
+ // Every recommended model id, once (a model in two tiers is two rows)
497
+ const modelIds = [...new Set(data.models.map(m => m.id))];
478
498
 
479
- // Get coding models
480
- const codingModels = data.models.filter(m => m.category === "coding");
499
+ // Flagship models, in rank order
500
+ const flagshipModels = data.models
501
+ .filter(m => m.recommendationTier === "flagship")
502
+ .sort((a, b) => a.priority - b.priority);
481
503
 
482
- // Get cheapest model
483
- const cheapest = data.models.sort((a, b) =>
484
- parseFloat(a.pricing.average) - parseFloat(b.pricing.average)
485
- )[0];
504
+ // Cheapest model by average price ("$0.85/1M"; "N/A" when unpriced)
505
+ const price = m => Number.parseFloat(m.pricing.average.replace(/^\$/, ""));
506
+ const cheapest = data.models
507
+ .filter(m => !Number.isNaN(price(m)))
508
+ .sort((a, b) => price(a) - price(b))[0];
486
509
  ```
487
510
 
488
511
  ## JSON Output Format
package/dist/index.js CHANGED
@@ -112,9 +112,25 @@ import { realpathSync } from "fs";
112
112
  function isPaneShellManagedKey(key) {
113
113
  return key.startsWith("MAGMUX_") || PANE_SHELL_MANAGED_KEYS.includes(key);
114
114
  }
115
- function isPaneChild(env = process.env) {
115
+ function inMcpSession(env = process.env) {
116
116
  return env[ENV.CLAUDISH_PANE_CHILD] === "1";
117
117
  }
118
+ function isPaneChild(env = process.env) {
119
+ return inMcpSession(env) && Boolean(env[ENV.CLAUDISH_PANE_CWD]);
120
+ }
121
+ function nestedLaunchRefusal(env = process.env) {
122
+ if (!inMcpSession(env) || isPaneChild(env))
123
+ return null;
124
+ return NESTED_SESSION_REFUSAL;
125
+ }
126
+ function assertNotNested(env = process.env) {
127
+ const reason = nestedLaunchRefusal(env);
128
+ if (reason === null)
129
+ return;
130
+ process.stderr.write(`claudish: nested session refused: ${reason}
131
+ `);
132
+ process.exit(PANE_CHILD_REFUSED_EXIT);
133
+ }
118
134
  function applyPaneEnvSnapshot(env) {
119
135
  const raw = env[ENV.CLAUDISH_PANE_ENV];
120
136
  if (raw === undefined)
@@ -207,14 +223,10 @@ function assertPaneChildInteractive(config, env = process.env) {
207
223
  if (reason !== null)
208
224
  refuse(reason);
209
225
  }
210
- var PANE_CHILD_REFUSED_EXIT = 64, PANE_MARKER_VARS, PANE_SHELL_MANAGED_KEYS, processCwdOps, bootNotes, bootstrapped = false;
226
+ var PANE_CHILD_REFUSED_EXIT = 64, PANE_LAUNCH_VARS, PANE_SHELL_MANAGED_KEYS, NESTED_SESSION_REFUSAL = "already inside a session started by the claudish MCP server; one level of nesting is the limit", processCwdOps, bootNotes, bootstrapped = false;
211
227
  var init_child_env = __esm(() => {
212
228
  init_config();
213
- PANE_MARKER_VARS = [
214
- ENV.CLAUDISH_PANE_CHILD,
215
- ENV.CLAUDISH_PANE_ENV,
216
- ENV.CLAUDISH_PANE_CWD
217
- ];
229
+ PANE_LAUNCH_VARS = [ENV.CLAUDISH_PANE_ENV, ENV.CLAUDISH_PANE_CWD];
218
230
  PANE_SHELL_MANAGED_KEYS = [
219
231
  "COLUMNS",
220
232
  "LINES",
@@ -889,7 +901,7 @@ var init_onepassword_config = __esm(() => {
889
901
  });
890
902
 
891
903
  // src/version.ts
892
- var VERSION = "10.6.1";
904
+ var VERSION = "10.6.3";
893
905
 
894
906
  // src/logger.ts
895
907
  import { appendFile, existsSync as existsSync2, mkdirSync, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
@@ -44525,6 +44537,9 @@ var init_cache_ttl = __esm(() => {
44525
44537
  import { existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
44526
44538
  import { homedir as homedir28 } from "os";
44527
44539
  import { join as join31 } from "path";
44540
+ function isRecommendationTier(value) {
44541
+ return typeof value === "string" && RECOMMENDATION_TIER_INDEX.has(value);
44542
+ }
44528
44543
  async function fetchCatalogPage(url, timeoutMs, generationId) {
44529
44544
  const requestUrl = new URL(url);
44530
44545
  if (generationId)
@@ -44546,93 +44561,262 @@ async function fetchCatalogPage(url, timeoutMs, generationId) {
44546
44561
  async function fetchCatalogData(url, timeoutMs, generationId) {
44547
44562
  return (await fetchCatalogPage(url, timeoutMs, generationId)).data;
44548
44563
  }
44549
- function recommendationProjection(recommendations, richModels = []) {
44564
+ function readWireEntry(value) {
44565
+ if (!value || typeof value !== "object")
44566
+ return null;
44567
+ const raw = value;
44568
+ if (typeof raw.modelId !== "string" || !isRecommendationTier(raw.tier))
44569
+ return null;
44570
+ const rawRoute = raw.route;
44571
+ const route = rawRoute && typeof rawRoute === "object" && typeof rawRoute.routeId === "string" && typeof rawRoute.routeProfileId === "string" ? { routeId: rawRoute.routeId, routeProfileId: rawRoute.routeProfileId } : undefined;
44572
+ return {
44573
+ modelId: raw.modelId,
44574
+ tier: raw.tier,
44575
+ ...route ? { route } : {},
44576
+ ...typeof raw.planId === "string" ? { planId: raw.planId } : {}
44577
+ };
44578
+ }
44579
+ function recommendationDedupeKey(entry) {
44580
+ return entry.tier === "subscription" ? JSON.stringify([
44581
+ entry.tier,
44582
+ entry.modelId,
44583
+ entry.route?.routeId ?? null,
44584
+ entry.route?.routeProfileId ?? null,
44585
+ entry.planId ?? null
44586
+ ]) : JSON.stringify([entry.tier, entry.modelId]);
44587
+ }
44588
+ function projectRecommendations(recommendations, catalog, richModels = [], now = new Date) {
44550
44589
  if (recommendations.contractVersion !== 3 || !Array.isArray(recommendations.entries)) {
44551
44590
  throw new Error("Model catalog recommendations do not match v3");
44552
44591
  }
44553
- const cache = readAllModelsCache();
44554
- if (!cache || cache.catalogGenerationId !== recommendations.generationId) {
44592
+ if (!catalog.catalogGenerationId || catalog.catalogGenerationId !== recommendations.generationId) {
44555
44593
  throw new Error("Recommendation and model catalog generations differ");
44556
44594
  }
44557
- const byId = new Map(cache?.entries.map((entry) => [entry.modelId, entry]) ?? []);
44558
- const richById = new Map(richModels.map((model) => [model.modelId, model]));
44595
+ const byId = new Map(catalog.entries.map((entry) => [entry.modelId, entry]));
44596
+ const richById = new Map;
44597
+ for (const model of richModels) {
44598
+ if (!richById.has(model.modelId))
44599
+ richById.set(model.modelId, model);
44600
+ }
44601
+ const seenKeys = new Set;
44602
+ const rankByTier = new Map;
44603
+ const models = [];
44604
+ for (const value of recommendations.entries) {
44605
+ const recommended = readWireEntry(value);
44606
+ if (!recommended)
44607
+ continue;
44608
+ const model = byId.get(recommended.modelId);
44609
+ if (!model)
44610
+ continue;
44611
+ const key = recommendationDedupeKey(recommended);
44612
+ if (seenKeys.has(key))
44613
+ continue;
44614
+ seenKeys.add(key);
44615
+ const priority = (rankByTier.get(recommended.tier) ?? 0) + 1;
44616
+ rankByTier.set(recommended.tier, priority);
44617
+ const rich = richById.get(recommended.modelId);
44618
+ const subscription = recommended.tier === "subscription" ? subscriptionRouteFor(recommended, model, catalog.plans) : undefined;
44619
+ models.push({
44620
+ id: recommended.modelId,
44621
+ name: rich?.displayName ?? model.displayName ?? recommended.modelId,
44622
+ description: rich?.description ?? "",
44623
+ provider: rich?.provider ?? model.provider ?? "",
44624
+ recommendationTier: recommended.tier,
44625
+ priority,
44626
+ pricing: {
44627
+ input: typeof rich?.pricing?.input === "number" ? `$${rich.pricing.input}/1M` : "N/A",
44628
+ output: typeof rich?.pricing?.output === "number" ? `$${rich.pricing.output}/1M` : "N/A",
44629
+ average: typeof rich?.pricing?.input === "number" && typeof rich?.pricing?.output === "number" ? `$${((rich.pricing.input + rich.pricing.output) / 2).toFixed(2)}/1M` : "N/A"
44630
+ },
44631
+ context: rich?.contextWindow ? String(rich.contextWindow) : model.contextWindow ? String(model.contextWindow) : "N/A",
44632
+ releaseDate: model.releaseDate,
44633
+ ...subscription ? { subscription, subscriptions: [subscription] } : {}
44634
+ });
44635
+ }
44636
+ const stamp = now.toISOString();
44559
44637
  return {
44560
44638
  contractVersion: 3,
44561
44639
  generationId: recommendations.generationId,
44562
44640
  version: recommendations.generationId,
44563
- lastUpdated: new Date().toISOString(),
44564
- generatedAt: new Date().toISOString(),
44565
- models: recommendations.entries.map((recommended, index) => {
44566
- const model = byId.get(recommended.modelId);
44567
- const rich = richById.get(recommended.modelId);
44568
- const provider = recommended.route ? providerForCatalogRoute(recommended.route) : undefined;
44569
- const connection = model?.aggregators?.find((candidate) => candidate.route?.routeId === recommended.route?.routeId && candidate.route?.routeProfileId === recommended.route?.routeProfileId);
44570
- const plan = cache?.plans.find((candidate) => candidate.id === recommended.planId);
44571
- const prefix = provider ? PROVIDER_TO_PREFIX[provider] ?? provider : undefined;
44572
- const command = prefix && connection?.externalModelId ? provider === "native-anthropic" ? connection.externalModelId : `${prefix}@${connection.externalModelId}` : undefined;
44573
- const subscription = recommended.tier === "subscription" && provider && command ? {
44574
- ...provider === "native-anthropic" ? {} : { prefix },
44575
- plan: plan?.id ?? recommended.planId ?? provider,
44576
- command,
44577
- planIds: recommended.planId ? [recommended.planId] : [],
44578
- routingProvider: provider,
44579
- tier: provider === "native-anthropic" ? "native" : "general"
44580
- } : undefined;
44581
- return {
44582
- id: recommended.modelId,
44583
- name: rich?.displayName ?? model?.displayName ?? recommended.modelId,
44584
- description: rich?.description ?? "",
44585
- provider: rich?.provider ?? model?.provider ?? "",
44586
- category: recommended.tier === "flagship" ? "programming" : recommended.tier === "lightweight" ? "fast" : "subscription",
44587
- priority: index + 1,
44588
- pricing: {
44589
- input: typeof rich?.pricing?.input === "number" ? `$${rich.pricing.input}/1M` : "N/A",
44590
- output: typeof rich?.pricing?.output === "number" ? `$${rich.pricing.output}/1M` : "N/A",
44591
- average: typeof rich?.pricing?.input === "number" && typeof rich?.pricing?.output === "number" ? `$${((rich.pricing.input + rich.pricing.output) / 2).toFixed(2)}/1M` : "N/A"
44592
- },
44593
- context: rich?.contextWindow ? String(rich.contextWindow) : model?.contextWindow ? String(model.contextWindow) : "N/A",
44594
- releaseDate: model?.releaseDate,
44595
- ...subscription ? { subscription, subscriptions: [subscription] } : {}
44596
- };
44597
- })
44641
+ lastUpdated: stamp,
44642
+ generatedAt: stamp,
44643
+ recommendationTiers: RECOMMENDATION_SECTIONS.map((section) => section.recommendationTier),
44644
+ models
44598
44645
  };
44599
44646
  }
44647
+ function subscriptionRouteFor(recommended, model, plans) {
44648
+ if (!recommended.route)
44649
+ return;
44650
+ const provider = providerForCatalogRoute(recommended.route);
44651
+ if (!provider)
44652
+ return;
44653
+ const connection = model.aggregators?.find((candidate) => candidate.route?.routeId === recommended.route?.routeId && candidate.route?.routeProfileId === recommended.route?.routeProfileId);
44654
+ const prefix = PROVIDER_TO_PREFIX[provider] ?? provider;
44655
+ if (!connection?.externalModelId)
44656
+ return;
44657
+ const command = provider === "native-anthropic" ? connection.externalModelId : `${prefix}@${connection.externalModelId}`;
44658
+ const plan = plans.find((candidate) => candidate.id === recommended.planId);
44659
+ return {
44660
+ ...provider === "native-anthropic" ? {} : { prefix },
44661
+ plan: plan?.id ?? recommended.planId ?? provider,
44662
+ command,
44663
+ planIds: recommended.planId ? [recommended.planId] : [],
44664
+ routingProvider: provider,
44665
+ tier: provider === "native-anthropic" ? "native" : "general"
44666
+ };
44667
+ }
44668
+ function recommendationProjection(recommendations, richModels = []) {
44669
+ const cache = readAllModelsCache();
44670
+ return projectRecommendations(recommendations, cache ? {
44671
+ catalogGenerationId: cache.catalogGenerationId,
44672
+ entries: cache.entries,
44673
+ plans: cache.plans
44674
+ } : { catalogGenerationId: "", entries: [], plans: [] }, richModels);
44675
+ }
44676
+ function isRecord(value) {
44677
+ return value !== null && typeof value === "object" && !Array.isArray(value);
44678
+ }
44679
+ function isStringArray(value) {
44680
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
44681
+ }
44682
+ function isRouteObject(value) {
44683
+ return isRecord(value) && typeof value.plan === "string" && typeof value.command === "string" && (value.prefix === undefined || typeof value.prefix === "string") && (value.planIds === undefined || isStringArray(value.planIds));
44684
+ }
44685
+ function isUsableRow(value) {
44686
+ if (!isRecord(value))
44687
+ return false;
44688
+ if (typeof value.id !== "string" || value.id.length === 0)
44689
+ return false;
44690
+ if (!isRecommendationTier(value.recommendationTier))
44691
+ return false;
44692
+ if (typeof value.priority !== "number" || !Number.isFinite(value.priority))
44693
+ return false;
44694
+ if (typeof value.name !== "string" || typeof value.description !== "string" || typeof value.provider !== "string" || typeof value.context !== "string") {
44695
+ return false;
44696
+ }
44697
+ const pricing = value.pricing;
44698
+ if (!isRecord(pricing) || typeof pricing.input !== "string" || typeof pricing.output !== "string" || typeof pricing.average !== "string") {
44699
+ return false;
44700
+ }
44701
+ if (value.releaseDate !== undefined && typeof value.releaseDate !== "string")
44702
+ return false;
44703
+ if (value.subscription !== undefined && !isRouteObject(value.subscription))
44704
+ return false;
44705
+ if (value.subscriptions !== undefined && !(Array.isArray(value.subscriptions) && value.subscriptions.every(isRouteObject))) {
44706
+ return false;
44707
+ }
44708
+ return true;
44709
+ }
44710
+ function readProjectedRecommendationsDoc(value) {
44711
+ if (!isRecord(value))
44712
+ return null;
44713
+ if (value.contractVersion !== 3)
44714
+ return null;
44715
+ if (typeof value.generationId !== "string" || typeof value.version !== "string" || typeof value.lastUpdated !== "string" || typeof value.generatedAt !== "string" || !Array.isArray(value.models)) {
44716
+ return null;
44717
+ }
44718
+ const writerTiers = value.recommendationTiers;
44719
+ if (!isStringArray(writerTiers))
44720
+ return null;
44721
+ if (!RECOMMENDATION_SECTIONS.every((section) => writerTiers.includes(section.recommendationTier)))
44722
+ return null;
44723
+ const models = value.models.filter(isUsableRow);
44724
+ if (models.length === 0)
44725
+ return null;
44726
+ return {
44727
+ ...value,
44728
+ recommendationTiers: RECOMMENDATION_SECTIONS.map((section) => section.recommendationTier),
44729
+ models
44730
+ };
44731
+ }
44732
+ function readRecommendedModelsCacheFile() {
44733
+ if (!existsSync21(RECOMMENDED_MODELS_CACHE_PATH))
44734
+ return null;
44735
+ let parsed;
44736
+ try {
44737
+ parsed = JSON.parse(readFileSync21(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
44738
+ } catch {
44739
+ return null;
44740
+ }
44741
+ return readProjectedRecommendationsDoc(parsed);
44742
+ }
44743
+ function sectionDefFor(tier) {
44744
+ const index = RECOMMENDATION_TIER_INDEX.get(tier);
44745
+ return index === undefined ? undefined : RECOMMENDATION_SECTIONS[index];
44746
+ }
44600
44747
  function groupRecommendedModels(entries) {
44601
- const byId = new Map;
44602
- const categoryOrder = new Map;
44748
+ const subscriptionRowsById = new Map;
44603
44749
  for (const entry of entries) {
44604
- const list = byId.get(entry.id);
44750
+ if (entry.recommendationTier !== "subscription")
44751
+ continue;
44752
+ const list = subscriptionRowsById.get(entry.id);
44605
44753
  if (list)
44606
44754
  list.push(entry);
44607
44755
  else
44608
- byId.set(entry.id, [entry]);
44609
- if (!categoryOrder.has(entry.category))
44610
- categoryOrder.set(entry.category, categoryOrder.size);
44611
- }
44612
- const flagship = [];
44613
- const fast = [];
44614
- for (const [id, members] of byId.entries()) {
44615
- const primary = members.find((m) => m.category !== "subscription") ?? members[0];
44616
- const subscriptions = members.filter((m) => m.category === "subscription");
44617
- const bucket = primary.category === "programming" || primary.category === "vision" || primary.category === "reasoning" ? "flagship" : "fast";
44618
- const group = { id, primary, subscriptions, bucket };
44619
- if (bucket === "flagship")
44620
- flagship.push(group);
44621
- else
44622
- fast.push(group);
44756
+ subscriptionRowsById.set(entry.id, [entry]);
44623
44757
  }
44624
- const byCuratedPriorityThenFreshness = (a, b) => {
44625
- const aCat = categoryOrder.get(a.primary.category) ?? Number.MAX_SAFE_INTEGER;
44626
- const bCat = categoryOrder.get(b.primary.category) ?? Number.MAX_SAFE_INTEGER;
44627
- if (aCat !== bCat)
44628
- return aCat - bCat;
44629
- if (a.primary.priority !== b.primary.priority)
44630
- return a.primary.priority - b.primary.priority;
44631
- return compareByReleaseDateDesc(a.primary, b.primary);
44632
- };
44633
- flagship.sort(byCuratedPriorityThenFreshness);
44634
- fast.sort(byCuratedPriorityThenFreshness);
44635
- return { flagship, fast };
44758
+ const sections = [];
44759
+ for (const def of RECOMMENDATION_SECTIONS) {
44760
+ const primaryById = new Map;
44761
+ for (const entry of entries) {
44762
+ if (entry.recommendationTier !== def.recommendationTier)
44763
+ continue;
44764
+ const current = primaryById.get(entry.id);
44765
+ if (!current || entry.priority < current.priority)
44766
+ primaryById.set(entry.id, entry);
44767
+ }
44768
+ if (primaryById.size === 0)
44769
+ continue;
44770
+ const groups = [...primaryById.values()].map((primary) => ({
44771
+ id: primary.id,
44772
+ primary,
44773
+ subscriptions: subscriptionRowsById.get(primary.id) ?? []
44774
+ }));
44775
+ groups.sort((a, b) => a.primary.priority - b.primary.priority || compareByReleaseDateDesc(a.primary, b.primary));
44776
+ const description = "description" in def ? def.description : undefined;
44777
+ sections.push({
44778
+ recommendationTier: def.recommendationTier,
44779
+ title: def.title,
44780
+ ...description ? { description } : {},
44781
+ groups
44782
+ });
44783
+ }
44784
+ return sections;
44785
+ }
44786
+ function quickPickCandidates(sections) {
44787
+ const excluded = new Set;
44788
+ for (const section of sections) {
44789
+ if (sectionDefFor(section.recommendationTier)?.quickPickEligible === false) {
44790
+ for (const group of section.groups)
44791
+ excluded.add(group.id);
44792
+ }
44793
+ }
44794
+ const seen = new Set;
44795
+ const candidates = [];
44796
+ for (const section of sections) {
44797
+ if (sectionDefFor(section.recommendationTier)?.quickPickEligible !== true)
44798
+ continue;
44799
+ for (const group of section.groups) {
44800
+ if (excluded.has(group.id) || seen.has(group.id))
44801
+ continue;
44802
+ seen.add(group.id);
44803
+ candidates.push(group.primary);
44804
+ }
44805
+ }
44806
+ return candidates;
44807
+ }
44808
+ function uniqueRecommendedModels(entries) {
44809
+ const sectionIndex = (entry) => RECOMMENDATION_TIER_INDEX.get(entry.recommendationTier) ?? Number.MAX_SAFE_INTEGER;
44810
+ const ordered = [...entries].sort((a, b) => sectionIndex(a) - sectionIndex(b) || a.priority - b.priority);
44811
+ const seen = new Set;
44812
+ const unique = [];
44813
+ for (const entry of ordered) {
44814
+ if (seen.has(entry.id))
44815
+ continue;
44816
+ seen.add(entry.id);
44817
+ unique.push(entry);
44818
+ }
44819
+ return unique;
44636
44820
  }
44637
44821
  function collectRoutingPrefixes(group, getNativePrefix) {
44638
44822
  const slug = (group.primary.provider || "").toLowerCase();
@@ -44725,14 +44909,12 @@ async function getRecommendedModels(opts = {}) {
44725
44909
  if (!forceRefresh && cached && cached.generationId === readAllModelsCache()?.catalogGenerationId) {
44726
44910
  return cached;
44727
44911
  }
44728
- if (!forceRefresh && existsSync21(RECOMMENDED_MODELS_CACHE_PATH)) {
44729
- try {
44730
- const cacheData = JSON.parse(readFileSync21(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
44731
- if (cacheData.contractVersion === 3 && cacheData.generationId === readAllModelsCache()?.catalogGenerationId && cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
44732
- _cachedRecommendedModels = cacheData;
44733
- return cacheData;
44734
- }
44735
- } catch {}
44912
+ if (!forceRefresh) {
44913
+ const cacheData = readRecommendedModelsCacheFile();
44914
+ if (cacheData && cacheData.generationId === readAllModelsCache()?.catalogGenerationId && isFreshEnough(cacheData)) {
44915
+ _cachedRecommendedModels = cacheData;
44916
+ return cacheData;
44917
+ }
44736
44918
  }
44737
44919
  let fetchFailure;
44738
44920
  try {
@@ -44767,14 +44949,10 @@ function getRecommendedModelsSync() {
44767
44949
  const cached = _cachedRecommendedModels;
44768
44950
  if (cached && cached.generationId === generationId)
44769
44951
  return cached;
44770
- if (existsSync21(RECOMMENDED_MODELS_CACHE_PATH)) {
44771
- try {
44772
- const cacheData = JSON.parse(readFileSync21(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
44773
- if (cacheData.contractVersion === 3 && cacheData.generationId === generationId && cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
44774
- _cachedRecommendedModels = cacheData;
44775
- return cacheData;
44776
- }
44777
- } catch {}
44952
+ const cacheData = readRecommendedModelsCacheFile();
44953
+ if (cacheData && cacheData.generationId === generationId && isFreshEnough(cacheData)) {
44954
+ _cachedRecommendedModels = cacheData;
44955
+ return cacheData;
44778
44956
  }
44779
44957
  return { version: "0", lastUpdated: "", models: [] };
44780
44958
  }
@@ -44860,7 +45038,7 @@ function loadModelInfo() {
44860
45038
  }
44861
45039
  const data = getRecommendedModelsSync();
44862
45040
  const modelInfo = {};
44863
- for (const model of data.models) {
45041
+ for (const model of uniqueRecommendedModels(data.models)) {
44864
45042
  modelInfo[model.id] = {
44865
45043
  name: model.name,
44866
45044
  description: model.description,
@@ -44882,20 +45060,38 @@ function getAvailableModels() {
44882
45060
  return _cachedModelIds;
44883
45061
  }
44884
45062
  const data = getRecommendedModelsSync();
44885
- const modelIds = data.models.sort((a, b) => a.priority - b.priority).map((m) => m.id);
45063
+ const modelIds = uniqueRecommendedModels(data.models).map((m) => m.id);
44886
45064
  const result = [...modelIds, "custom"];
44887
45065
  _cachedModelIds = result;
44888
45066
  return result;
44889
45067
  }
44890
- var _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels = null, FIREBASE_BASE_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/queryModels", FIREBASE_RECOMMENDED_URL, RECOMMENDED_MODELS_CACHE_PATH, RECOMMENDED_FETCH_TIMEOUT_MS = 5000, SEARCH_FETCH_TIMEOUT_MS = 1e4, RECOMMENDED_ROUTE_TIER_ORDER;
45068
+ var RECOMMENDATION_SECTIONS, RECOMMENDATION_TIER_INDEX, _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels = null, FIREBASE_BASE_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/queryModels", FIREBASE_RECOMMENDED_URL, RECOMMENDED_MODELS_CACHE_PATH, RECOMMENDED_FETCH_TIMEOUT_MS = 5000, SEARCH_FETCH_TIMEOUT_MS = 1e4, RECOMMENDED_ROUTE_TIER_ORDER;
44891
45069
  var init_model_loader = __esm(() => {
44892
45070
  init_all_models_cache();
44893
45071
  init_auto_route();
44894
45072
  init_cache_ttl();
44895
45073
  init_catalog_client();
44896
45074
  init_catalog_route_bindings();
45075
+ RECOMMENDATION_SECTIONS = [
45076
+ { recommendationTier: "flagship", title: "Flagship", quickPickEligible: true },
45077
+ {
45078
+ recommendationTier: "cost_efficient",
45079
+ title: "Cost-efficient",
45080
+ description: "Best value: strong models at a much lower cost per task",
45081
+ quickPickEligible: true
45082
+ },
45083
+ { recommendationTier: "lightweight", title: "Lightweight", quickPickEligible: true },
45084
+ {
45085
+ recommendationTier: "luxury",
45086
+ title: "Luxury",
45087
+ description: "Most capable, most expensive. Use for the hardest tasks",
45088
+ quickPickEligible: false
45089
+ },
45090
+ { recommendationTier: "subscription", title: "Subscription", quickPickEligible: true }
45091
+ ];
45092
+ RECOMMENDATION_TIER_INDEX = new Map(RECOMMENDATION_SECTIONS.map((section, index) => [section.recommendationTier, index]));
44897
45093
  FIREBASE_RECOMMENDED_URL = `${FIREBASE_BASE_URL}?catalog=recommended`;
44898
- RECOMMENDED_MODELS_CACHE_PATH = join31(homedir28(), ".claudish", "recommended-models-cache.json");
45094
+ RECOMMENDED_MODELS_CACHE_PATH = join31(homedir28(), ".claudish", "recommended-models-cache-v2.json");
44899
45095
  RECOMMENDED_ROUTE_TIER_ORDER = {
44900
45096
  native: 0,
44901
45097
  general: 1,
@@ -50508,25 +50704,28 @@ function formatFirebaseProviderLabel(slug) {
50508
50704
  }
50509
50705
  async function loadRecommendedModels(forceRefresh = false) {
50510
50706
  try {
50511
- const doc = await getRecommendedModels({ forceRefresh });
50512
- return sortModelsNewestFirst(doc.models.map((model) => ({
50513
- id: model.id,
50514
- name: model.name,
50515
- description: model.description,
50516
- provider: formatFirebaseProviderLabel(model.provider),
50517
- providerSlug: model.provider.toLowerCase(),
50518
- pricing: model.pricing,
50519
- context: model.context,
50520
- contextLength: parseContextString(model.context),
50521
- supportsTools: model.supportsTools,
50522
- supportsReasoning: model.supportsReasoning,
50523
- supportsVision: model.supportsVision,
50524
- source: formatFirebaseProviderLabel(model.provider)
50525
- })));
50707
+ return _recommendedFallbackRows(await getRecommendedModels({ forceRefresh }));
50526
50708
  } catch {
50527
50709
  return [];
50528
50710
  }
50529
50711
  }
50712
+ function _recommendedFallbackRows(doc) {
50713
+ return sortModelsNewestFirst(uniqueRecommendedModels(doc.models).map((model) => ({
50714
+ id: model.id,
50715
+ name: model.name,
50716
+ description: model.description,
50717
+ provider: formatFirebaseProviderLabel(model.provider),
50718
+ providerSlug: model.provider.toLowerCase(),
50719
+ pricing: model.pricing,
50720
+ context: model.context,
50721
+ contextLength: parseContextString(model.context),
50722
+ supportsTools: model.supportsTools,
50723
+ supportsReasoning: model.supportsReasoning,
50724
+ supportsVision: model.supportsVision,
50725
+ releaseDate: model.releaseDate,
50726
+ source: formatFirebaseProviderLabel(model.provider)
50727
+ })));
50728
+ }
50530
50729
  function parseContextString(ctx) {
50531
50730
  if (!ctx || ctx === "N/A")
50532
50731
  return 0;
@@ -54434,6 +54633,159 @@ var init_provider_slug_resolve = __esm(() => {
54434
54633
  init_reserved_namespace();
54435
54634
  });
54436
54635
 
54636
+ // src/recommended-listing.ts
54637
+ function nativeShortcutForVendor(vendorSlug) {
54638
+ const canonical = nativeProviderForVendor(vendorSlug);
54639
+ if (!canonical)
54640
+ return null;
54641
+ const def = BUILTIN_PROVIDERS.find((provider) => provider.name === canonical);
54642
+ const shortcut = def?.shortcuts?.[0];
54643
+ return shortcut ? shortcut : null;
54644
+ }
54645
+ function textHeading(section) {
54646
+ return section.description ? `${section.title} \u2014 ${section.description}` : section.title;
54647
+ }
54648
+ function textRow(group, getNativePrefix) {
54649
+ const m = group.primary;
54650
+ const rawId = m.id;
54651
+ const modelId = rawId.length > 28 ? `${rawId.substring(0, 25)}...` : rawId;
54652
+ const modelIdPadded = modelId.padEnd(28);
54653
+ const pricing = formatListingPrice(m, { compact: true });
54654
+ const pricingPadded = pricing.padEnd(10);
54655
+ const context = m.context || "N/A";
54656
+ const contextPadded = context.padEnd(6);
54657
+ const caps = [];
54658
+ if (m.supportsTools)
54659
+ caps.push("\uD83D\uDD27");
54660
+ if (m.supportsReasoning)
54661
+ caps.push("\uD83E\uDDE0");
54662
+ if (m.supportsVision)
54663
+ caps.push("\uD83D\uDC41\uFE0F");
54664
+ const capabilities = caps.join(" ");
54665
+ const lines = [` ${modelIdPadded} ${pricingPadded} ${contextPadded} ${capabilities}`];
54666
+ const prefixes = collectRoutingPrefixes(group, getNativePrefix);
54667
+ if (prefixes.length > 0) {
54668
+ const viaLine = prefixes.map((p) => `${p}@`).join(" \xB7 ");
54669
+ lines.push(` via: ${viaLine}`);
54670
+ }
54671
+ return lines;
54672
+ }
54673
+ function renderRecommendedText(doc, getNativePrefix) {
54674
+ const lastUpdated = doc.lastUpdated || "unknown";
54675
+ const sections = groupRecommendedModels(doc.models);
54676
+ const lines = ["", `Recommended Models (last updated: ${lastUpdated}):`, ""];
54677
+ sections.forEach((section, sectionIndex) => {
54678
+ if (sectionIndex > 0)
54679
+ lines.push("");
54680
+ lines.push(textHeading(section));
54681
+ lines.push(` ${"\u2500".repeat(70)}`);
54682
+ section.groups.forEach((group, groupIndex) => {
54683
+ lines.push(...textRow(group, getNativePrefix));
54684
+ if (groupIndex < section.groups.length - 1)
54685
+ lines.push("");
54686
+ });
54687
+ });
54688
+ lines.push("");
54689
+ lines.push(" Capabilities: \uD83D\uDD27 Tools \uD83E\uDDE0 Reasoning \uD83D\uDC41\uFE0F Vision");
54690
+ const picks = computeQuickPicks(quickPickCandidates(sections));
54691
+ const pickLines = [];
54692
+ if (picks.budget)
54693
+ pickLines.push(` Budget \u2192 ${picks.budget.id} (${normalizePricingDisplay(picks.budget.pricing?.average)})`);
54694
+ if (picks.largeContext)
54695
+ pickLines.push(` Large ctx \u2192 ${picks.largeContext.id} (${picks.largeContext.context || "N/A"})`);
54696
+ if (picks.mostCapable)
54697
+ pickLines.push(` Most capable \u2192 ${picks.mostCapable.id}`);
54698
+ if (picks.visionCoding)
54699
+ pickLines.push(` Vision+code \u2192 ${picks.visionCoding.id}`);
54700
+ if (picks.agentic)
54701
+ pickLines.push(` Agentic \u2192 ${picks.agentic.id}`);
54702
+ if (pickLines.length > 0) {
54703
+ lines.push("");
54704
+ lines.push(" Quick picks:");
54705
+ lines.push(...pickLines);
54706
+ }
54707
+ lines.push("");
54708
+ lines.push(" Set default: export CLAUDISH_MODEL=<model>");
54709
+ lines.push(" or: claudish --model <model> ...");
54710
+ lines.push("");
54711
+ lines.push(" For more: claudish --models (browse full catalog)");
54712
+ lines.push(" claudish --providers (list all providers + counts)");
54713
+ lines.push(" claudish -s <query> (search by keyword)");
54714
+ lines.push(" claudish --models-top --models-refresh (refresh from Firebase)");
54715
+ lines.push("");
54716
+ return lines.join(`
54717
+ `);
54718
+ }
54719
+ function markdownRow(group, getNativePrefix) {
54720
+ const m = group.primary;
54721
+ const pricing = formatListingPrice(m);
54722
+ const ctx = m.context || "N/A";
54723
+ const caps = [];
54724
+ if (m.supportsTools)
54725
+ caps.push("tools");
54726
+ if (m.supportsReasoning)
54727
+ caps.push("reasoning");
54728
+ if (m.supportsVision)
54729
+ caps.push("vision");
54730
+ const capsLine = caps.length > 0 ? caps.join(", ") : "none";
54731
+ const prefixes = collectRoutingPrefixes(group, getNativePrefix);
54732
+ const accessLine = prefixes.length > 0 ? prefixes.map((p) => `\`${p}@${m.id}\``).join(" \xB7 ") : `\`${m.id}\``;
54733
+ return [
54734
+ `### ${m.id}`,
54735
+ `- **Pricing**: ${pricing} avg \xB7 ${ctx} context`,
54736
+ `- **Capabilities**: ${capsLine}`,
54737
+ `- **Access**: ${accessLine}`,
54738
+ ""
54739
+ ].join(`
54740
+ `);
54741
+ }
54742
+ function renderRecommendedMarkdown(doc, getNativePrefix) {
54743
+ const sections = groupRecommendedModels(doc.models);
54744
+ let output = `# Recommended Models
54745
+
54746
+ `;
54747
+ output += `_Last updated: ${doc.lastUpdated || "unknown"}_
54748
+
54749
+ `;
54750
+ for (const section of sections) {
54751
+ output += `## ${section.title}
54752
+
54753
+ `;
54754
+ if (section.description)
54755
+ output += `_${section.description}_
54756
+
54757
+ `;
54758
+ for (const group of section.groups)
54759
+ output += markdownRow(group, getNativePrefix);
54760
+ }
54761
+ const picks = computeQuickPicks(quickPickCandidates(sections));
54762
+ const pickLines = [];
54763
+ if (picks.budget)
54764
+ pickLines.push(`- **Budget**: \`${picks.budget.id}\` (${normalizePricingDisplay(picks.budget.pricing?.average)})`);
54765
+ if (picks.largeContext)
54766
+ pickLines.push(`- **Large context**: \`${picks.largeContext.id}\` (${picks.largeContext.context || "N/A"})`);
54767
+ if (picks.mostCapable)
54768
+ pickLines.push(`- **Most capable**: \`${picks.mostCapable.id}\``);
54769
+ if (picks.visionCoding)
54770
+ pickLines.push(`- **Vision + coding**: \`${picks.visionCoding.id}\``);
54771
+ if (picks.agentic)
54772
+ pickLines.push(`- **Agentic**: \`${picks.agentic.id}\``);
54773
+ if (pickLines.length > 0) {
54774
+ output += `## Quick picks
54775
+
54776
+ `;
54777
+ output += `${pickLines.join(`
54778
+ `)}
54779
+ `;
54780
+ }
54781
+ return output;
54782
+ }
54783
+ var init_recommended_listing = __esm(() => {
54784
+ init_model_loader();
54785
+ init_provider_definitions();
54786
+ init_route_candidates();
54787
+ });
54788
+
54437
54789
  // src/branding.ts
54438
54790
  function paint(line) {
54439
54791
  const { RESET, BOLD, CYAN, BLUE, DIM } = cliAnsi();
@@ -59799,7 +60151,7 @@ function clearAllModelCaches() {
59799
60151
  const cacheDir = join36(homedir32(), ".claudish");
59800
60152
  if (!existsSync25(cacheDir))
59801
60153
  return;
59802
- const cachePatterns = ["pricing-cache.json", "recommended-models-cache.json"];
60154
+ const cachePatterns = ["pricing-cache.json", "recommended-models-cache-v2.json"];
59803
60155
  let cleared = 0;
59804
60156
  try {
59805
60157
  const files = readdirSync4(cacheDir);
@@ -60599,95 +60951,7 @@ async function printRecommendedModels(jsonOutput, forceUpdate) {
60599
60951
  console.log(JSON.stringify(doc, null, 2));
60600
60952
  return;
60601
60953
  }
60602
- const lastUpdated = doc.lastUpdated || "unknown";
60603
- const { flagship, fast } = groupRecommendedModels(doc.models);
60604
- const providerByName = new Map(BUILTIN_PROVIDERS.map((p) => [p.name, p]));
60605
- const getNativePrefix = (firebaseSlug) => {
60606
- const canonical = nativeProviderForVendor(firebaseSlug);
60607
- if (!canonical)
60608
- return null;
60609
- const def = providerByName.get(canonical);
60610
- if (!def || !def.shortcuts || def.shortcuts.length === 0)
60611
- return null;
60612
- return def.shortcuts[0];
60613
- };
60614
- const renderGroup = (group) => {
60615
- const m = group.primary;
60616
- const rawId = m.id;
60617
- const modelId = rawId.length > 28 ? `${rawId.substring(0, 25)}...` : rawId;
60618
- const modelIdPadded = modelId.padEnd(28);
60619
- const pricing = formatListingPrice(m, { compact: true });
60620
- const pricingPadded = pricing.padEnd(10);
60621
- const context = m.context || "N/A";
60622
- const contextPadded = context.padEnd(6);
60623
- const caps = [];
60624
- if (m.supportsTools)
60625
- caps.push("\uD83D\uDD27");
60626
- if (m.supportsReasoning)
60627
- caps.push("\uD83E\uDDE0");
60628
- if (m.supportsVision)
60629
- caps.push("\uD83D\uDC41\uFE0F");
60630
- const capabilities = caps.join(" ");
60631
- console.log(` ${modelIdPadded} ${pricingPadded} ${contextPadded} ${capabilities}`);
60632
- const prefixes = collectRoutingPrefixes(group, getNativePrefix);
60633
- if (prefixes.length > 0) {
60634
- const viaLine = prefixes.map((p) => `${p}@`).join(" \xB7 ");
60635
- console.log(` via: ${viaLine}`);
60636
- }
60637
- };
60638
- console.log(`
60639
- Recommended Models (last updated: ${lastUpdated}):
60640
- `);
60641
- if (flagship.length > 0) {
60642
- console.log("Flagship models");
60643
- console.log(` ${"\u2500".repeat(70)}`);
60644
- for (let i = 0;i < flagship.length; i++) {
60645
- renderGroup(flagship[i]);
60646
- if (i < flagship.length - 1)
60647
- console.log("");
60648
- }
60649
- }
60650
- if (fast.length > 0) {
60651
- if (flagship.length > 0)
60652
- console.log("");
60653
- console.log("Fast variants");
60654
- console.log(` ${"\u2500".repeat(70)}`);
60655
- for (let i = 0;i < fast.length; i++) {
60656
- renderGroup(fast[i]);
60657
- if (i < fast.length - 1)
60658
- console.log("");
60659
- }
60660
- }
60661
- console.log("");
60662
- console.log(" Capabilities: \uD83D\uDD27 Tools \uD83E\uDDE0 Reasoning \uD83D\uDC41\uFE0F Vision");
60663
- const primaries = [...flagship, ...fast].map((g) => g.primary);
60664
- const picks = computeQuickPicks(primaries);
60665
- const pickLines = [];
60666
- if (picks.budget)
60667
- pickLines.push(` Budget \u2192 ${picks.budget.id} (${normalizePricingDisplay(picks.budget.pricing?.average)})`);
60668
- if (picks.largeContext)
60669
- pickLines.push(` Large ctx \u2192 ${picks.largeContext.id} (${picks.largeContext.context || "N/A"})`);
60670
- if (picks.mostCapable)
60671
- pickLines.push(` Most capable \u2192 ${picks.mostCapable.id}`);
60672
- if (picks.visionCoding)
60673
- pickLines.push(` Vision+code \u2192 ${picks.visionCoding.id}`);
60674
- if (picks.agentic)
60675
- pickLines.push(` Agentic \u2192 ${picks.agentic.id}`);
60676
- if (pickLines.length > 0) {
60677
- console.log("");
60678
- console.log(" Quick picks:");
60679
- for (const line of pickLines)
60680
- console.log(line);
60681
- }
60682
- console.log("");
60683
- console.log(" Set default: export CLAUDISH_MODEL=<model>");
60684
- console.log(" or: claudish --model <model> ...");
60685
- console.log("");
60686
- console.log(" For more: claudish --models (browse full catalog)");
60687
- console.log(" claudish --providers (list all providers + counts)");
60688
- console.log(" claudish -s <query> (search by keyword)");
60689
- console.log(" claudish --models-top --models-refresh (refresh from Firebase)");
60690
- console.log("");
60954
+ console.log(renderRecommendedText(doc, nativeShortcutForVendor));
60691
60955
  }
60692
60956
  async function printVersion() {
60693
60957
  if (!process.stdout.isTTY) {
@@ -61470,8 +61734,8 @@ var init_cli = __esm(() => {
61470
61734
  init_probe_runner();
61471
61735
  init_provider_definitions();
61472
61736
  init_provider_slug_resolve();
61473
- init_route_candidates();
61474
61737
  init_routing_rules();
61738
+ init_recommended_listing();
61475
61739
  init_settings();
61476
61740
  init_ansi();
61477
61741
  init_provider_resolver();
@@ -61662,7 +61926,7 @@ function buildLauncherScript(claudeBinary, claudeArgs, deltas) {
61662
61926
  }
61663
61927
  function magmuxPaneCapability(input) {
61664
61928
  const parentEnv = input.parentEnv ?? process.env;
61665
- if (isPaneChild(parentEnv))
61929
+ if (inMcpSession(parentEnv))
61666
61930
  return { kind: "none", reason: "pane-child" };
61667
61931
  if (!input.interactive)
61668
61932
  return { kind: "none", reason: "not-interactive" };
@@ -68629,6 +68893,26 @@ var init_channel = __esm(() => {
68629
68893
  init_types3();
68630
68894
  });
68631
68895
 
68896
+ // src/mcp/nested-mode.ts
68897
+ var NESTED_MCP_TOOL_NAMES, NESTED_INSTRUCTIONS = `Claudish MCP server provides access to external AI models for one-shot calls.
68898
+
68899
+ ## Nested mode \u2014 no sessions
68900
+
68901
+ This server runs inside a session that a claudish MCP server started (CLAUDISH_PANE_CHILD=1). One level of nesting is the limit, so these tools are not registered: create_session, team, send_input, get_output, cancel_session, list_sessions, get_diagnostics, capture_session, preflight, report_error. No channel notifications are sent.
68902
+
68903
+ - run_prompt or compare_models: a one-shot answer from another model.
68904
+ - list_models, search_models: find a model.
68905
+
68906
+ Do not start a claudish session another way: \`claudish -p\`, an interactive claudish or \`claudish team\` run from this session's shell exits 64 with "nested session refused".`;
68907
+ var init_nested_mode = __esm(() => {
68908
+ NESTED_MCP_TOOL_NAMES = [
68909
+ "run_prompt",
68910
+ "list_models",
68911
+ "search_models",
68912
+ "compare_models"
68913
+ ];
68914
+ });
68915
+
68632
68916
  // src/mcp/progress-heartbeat.ts
68633
68917
  function isProgressToken(v) {
68634
68918
  return typeof v === "string" || typeof v === "number" && Number.isFinite(v);
@@ -69026,8 +69310,9 @@ async function teamContractVerb(mode, args) {
69026
69310
  return contractErrorAnswer(e);
69027
69311
  }
69028
69312
  }
69029
- function defineTools(sessionManager, notifyChannel) {
69313
+ function defineTools(sessionManager, notifyChannel, nested) {
69030
69314
  const tools = [];
69315
+ const reportHint = (text) => nested ? "" : text;
69031
69316
  function withOpFailureContext(message, subject) {
69032
69317
  const block = renderOpFailureBlock(subject);
69033
69318
  return block.length === 0 ? message : `${message}
@@ -69070,10 +69355,10 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
69070
69355
  content: [
69071
69356
  {
69072
69357
  type: "text",
69073
- text: withOpFailureContext(`Error: ${errMsg}
69358
+ text: withOpFailureContext(`Error: ${errMsg}${reportHint(`
69074
69359
 
69075
69360
  ---
69076
- **To report this error**, use the \`report_error\` tool with \`error_type: "provider_failure"\` and \`model: "${args.model}"\`.`, `while routing ${args.model}`)
69361
+ **To report this error**, use the \`report_error\` tool with \`error_type: "provider_failure"\` and \`model: "${args.model}"\`.`)}`, `while routing ${args.model}`)
69077
69362
  }
69078
69363
  ],
69079
69364
  isError: true
@@ -69110,82 +69395,14 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
69110
69395
  ]
69111
69396
  };
69112
69397
  }
69113
- const { flagship, fast } = groupRecommendedModels(doc.models);
69114
- const providerByName = new Map(BUILTIN_PROVIDERS.map((p) => [p.name, p]));
69115
- const getNativePrefix = (firebaseSlug) => {
69116
- const canonical = nativeProviderForVendor(firebaseSlug);
69117
- if (!canonical)
69118
- return null;
69119
- const def = providerByName.get(canonical);
69120
- if (!def || !def.shortcuts || def.shortcuts.length === 0)
69121
- return null;
69122
- return def.shortcuts[0];
69123
- };
69124
- const renderGroup = (group) => {
69125
- const m = group.primary;
69126
- const pricing = formatListingPrice(m);
69127
- const ctx = m.context || "N/A";
69128
- const caps = [];
69129
- if (m.supportsTools)
69130
- caps.push("tools");
69131
- if (m.supportsReasoning)
69132
- caps.push("reasoning");
69133
- if (m.supportsVision)
69134
- caps.push("vision");
69135
- const capsLine = caps.length > 0 ? caps.join(", ") : "none";
69136
- const prefixes = collectRoutingPrefixes(group, getNativePrefix);
69137
- const accessLine = prefixes.length > 0 ? prefixes.map((p) => `\`${p}@${m.id}\``).join(" \xB7 ") : `\`${m.id}\``;
69138
- return [
69139
- `### ${m.id}`,
69140
- `- **Pricing**: ${pricing} avg \xB7 ${ctx} context`,
69141
- `- **Capabilities**: ${capsLine}`,
69142
- `- **Access**: ${accessLine}`,
69143
- ""
69144
- ].join(`
69145
- `);
69398
+ return {
69399
+ content: [
69400
+ {
69401
+ type: "text",
69402
+ text: renderRecommendedMarkdown(doc, nativeShortcutForVendor)
69403
+ }
69404
+ ]
69146
69405
  };
69147
- let output = `# Recommended Models
69148
-
69149
- `;
69150
- output += `_Last updated: ${doc.lastUpdated || "unknown"}_
69151
-
69152
- `;
69153
- if (flagship.length > 0) {
69154
- output += `## Flagship models
69155
-
69156
- `;
69157
- for (const group of flagship)
69158
- output += renderGroup(group);
69159
- }
69160
- if (fast.length > 0) {
69161
- output += `## Fast variants
69162
-
69163
- `;
69164
- for (const group of fast)
69165
- output += renderGroup(group);
69166
- }
69167
- const primaries = [...flagship, ...fast].map((g) => g.primary);
69168
- const picks = computeQuickPicks(primaries);
69169
- const pickLines = [];
69170
- if (picks.budget)
69171
- pickLines.push(`- **Budget**: \`${picks.budget.id}\` (${normalizePricingDisplay(picks.budget.pricing?.average)})`);
69172
- if (picks.largeContext)
69173
- pickLines.push(`- **Large context**: \`${picks.largeContext.id}\` (${picks.largeContext.context || "N/A"})`);
69174
- if (picks.mostCapable)
69175
- pickLines.push(`- **Most capable**: \`${picks.mostCapable.id}\``);
69176
- if (picks.visionCoding)
69177
- pickLines.push(`- **Vision + coding**: \`${picks.visionCoding.id}\``);
69178
- if (picks.agentic)
69179
- pickLines.push(`- **Agentic**: \`${picks.agentic.id}\``);
69180
- if (pickLines.length > 0) {
69181
- output += `## Quick picks
69182
-
69183
- `;
69184
- output += `${pickLines.join(`
69185
- `)}
69186
- `;
69187
- }
69188
- return { content: [{ type: "text", text: output }] };
69189
69406
  }
69190
69407
  });
69191
69408
  tools.push({
@@ -69352,7 +69569,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
69352
69569
  }
69353
69570
  const failed = results.filter((r) => r.error);
69354
69571
  if (failed.length > 0) {
69355
- output += '---\n**To report failed model(s)**, use the `report_error` tool with `error_type: "provider_failure"` and the model ID(s) above.\n';
69572
+ output += reportHint('---\n**To report failed model(s)**, use the `report_error` tool with `error_type: "provider_failure"` and the model ID(s) above.\n');
69356
69573
  }
69357
69574
  return { content: [{ type: "text", text: output }] };
69358
69575
  }
@@ -70128,13 +70345,15 @@ function mapEventToTaskStatus(event) {
70128
70345
  }
70129
70346
  async function main() {
70130
70347
  const toolMode = (process.env.CLAUDISH_MCP_TOOLS || "all").toLowerCase();
70348
+ const nested = inMcpSession();
70131
70349
  const enabledGroups = resolveToolGroups(toolMode);
70350
+ const channelEnabled = !nested && enabledGroups.has("channel");
70132
70351
  const server = new Server({ name: "claudish", version: "9.0.0" }, {
70133
70352
  capabilities: {
70134
- ...enabledGroups.has("channel") ? { experimental: { "claude/channel": {} } } : {},
70353
+ ...channelEnabled ? { experimental: { "claude/channel": {} } } : {},
70135
70354
  tools: {}
70136
70355
  },
70137
- instructions: INSTRUCTIONS
70356
+ instructions: nested ? NESTED_INSTRUCTIONS : INSTRUCTIONS
70138
70357
  });
70139
70358
  const sessionManager = new SessionManager({
70140
70359
  onStateChange: wrapStateChange((sessionId, event) => {
@@ -70161,7 +70380,6 @@ Call get_diagnostics with session_id: "${sessionId}" for the final screen, the u
70161
70380
  watchNotificationResult(result, { sessionId, eventType: event.type });
70162
70381
  })
70163
70382
  });
70164
- const channelEnabled = enabledGroups.has("channel");
70165
70383
  const notifyChannel = (p) => {
70166
70384
  if (!channelEnabled)
70167
70385
  return;
@@ -70186,10 +70404,11 @@ Call get_diagnostics with session_id: "${sessionId}" for the final screen, the u
70186
70404
  } catch {}
70187
70405
  };
70188
70406
  const progressIntervalMs = resolveProgressIntervalMs();
70189
- const allTools = defineTools(sessionManager, notifyChannel);
70190
- const enabledTools = allTools.filter((t) => enabledGroups.has(t.group));
70407
+ const allTools = defineTools(sessionManager, notifyChannel, nested);
70408
+ const nestedNames = NESTED_MCP_TOOL_NAMES;
70409
+ const enabledTools = allTools.filter((t) => enabledGroups.has(t.group) && (!nested || nestedNames.includes(t.name)));
70191
70410
  const toolMap = new Map(enabledTools.map((t) => [t.name, t]));
70192
- console.error(`[claudish] MCP server started (tools: ${toolMode}, ${enabledTools.length} tools)`);
70411
+ console.error(`[claudish] MCP server started (tools: ${nested ? "nested" : toolMode}, ${enabledTools.length} tools)`);
70193
70412
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
70194
70413
  tools: enabledTools.map((t) => ({
70195
70414
  name: t.name,
@@ -70293,8 +70512,10 @@ var init_mcp_server = __esm(() => {
70293
70512
  init_channel();
70294
70513
  init_parent_session();
70295
70514
  init_remote_provider_types();
70515
+ init_nested_mode();
70296
70516
  init_progress_heartbeat();
70297
70517
  init_model_loader();
70518
+ init_child_env();
70298
70519
  init_pane();
70299
70520
  init_port_manager();
70300
70521
  init_endpoint_registration();
@@ -70302,10 +70523,9 @@ var init_mcp_server = __esm(() => {
70302
70523
  init_native_route();
70303
70524
  init_onepassword();
70304
70525
  init_probe_live();
70305
- init_provider_definitions();
70306
- init_route_candidates();
70307
70526
  init_routing_rules();
70308
70527
  init_proxy_server();
70528
+ init_recommended_listing();
70309
70529
  init_redact();
70310
70530
  init_team_orchestrator();
70311
70531
  import_dotenv2 = __toESM(require_main(), 1);
@@ -70931,6 +71151,8 @@ async function teamCommand(args) {
70931
71151
  const firstArg = args[0] ?? "";
70932
71152
  const legacySubs = ["run", "judge", "run-and-judge", "status"];
70933
71153
  const subcommand = legacySubs.includes(firstArg) ? firstArg : "run";
71154
+ if (subcommand !== "status")
71155
+ assertNotNested();
70934
71156
  const rawSessionPath = getFlag(args, "--path") ?? ".";
70935
71157
  let sessionPath;
70936
71158
  try {
@@ -71017,6 +71239,7 @@ async function teamCommand(args) {
71017
71239
  }
71018
71240
  }
71019
71241
  var init_team_cli = __esm(() => {
71242
+ init_child_env();
71020
71243
  init_pane();
71021
71244
  init_team_orchestrator();
71022
71245
  });
@@ -80370,7 +80593,7 @@ function scrubChildEnv(env, opts) {
80370
80593
  for (const key of STRIPPED_CHILD_VARS)
80371
80594
  delete env[key];
80372
80595
  }
80373
- for (const key of PANE_MARKER_VARS)
80596
+ for (const key of PANE_LAUNCH_VARS)
80374
80597
  delete env[key];
80375
80598
  }
80376
80599
  function buildClaudishSettingsOverlay(statusLine, proxyAuthMode, paneChild = isPaneChild()) {
@@ -83791,6 +84014,7 @@ async function runCli() {
83791
84014
  await detectAndSetThemeMode();
83792
84015
  });
83793
84016
  const cliConfig = await traceSpan("startup:parse-args", () => parseArgs(process.argv.slice(2)));
84017
+ assertNotNested();
83794
84018
  assertPaneChildInteractive(cliConfig);
83795
84019
  await traceSpan("startup:endpoint-registration", async () => {
83796
84020
  await Promise.resolve().then(() => init_endpoint_registration());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "10.6.1",
3
+ "version": "10.6.3",
4
4
  "description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,10 +60,10 @@
60
60
  "ai"
61
61
  ],
62
62
  "optionalDependencies": {
63
- "@claudish/magmux-darwin-arm64": "10.6.1",
64
- "@claudish/magmux-darwin-x64": "10.6.1",
65
- "@claudish/magmux-linux-arm64": "10.6.1",
66
- "@claudish/magmux-linux-x64": "10.6.1"
63
+ "@claudish/magmux-darwin-arm64": "10.6.3",
64
+ "@claudish/magmux-darwin-x64": "10.6.3",
65
+ "@claudish/magmux-linux-arm64": "10.6.3",
66
+ "@claudish/magmux-linux-x64": "10.6.3"
67
67
  },
68
68
  "author": "Jack Rudenko <i@madappgang.com>",
69
69
  "license": "MIT",