zidane 5.0.2 → 5.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tui.js CHANGED
@@ -2,7 +2,7 @@ import { d as createAgent } from "./tools-CLazLRb4.js";
2
2
  import { n as formatTokenUsage } from "./stats-DZIsGqzu.js";
3
3
  import { n as loadSession, t as createSession } from "./session-791hhrFa.js";
4
4
  import { createTuiStore } from "./session/sqlite.js";
5
- import { C as useSafeModeQueue, Ct as findGitRoot, D as isOnSafelist, E as getSafelist, Et as uniqueSkillNamesFromReferences, F as supportsOAuth, Ft as detectAuth, G as shortId, H as ageString, I as buildMcpServers, J as DEFAULT_SETTINGS, K as listProjectFiles, N as splitPromptSegments, Ot as createFilesCompletionProvider, P as runOAuthLogin, Pt as useCompletion, Q as useSettings, R as discoverProjectMcps, S as useSafeModeActions, St as toolResultText, T as addToSafelist, Tt as createSkillsCompletionProvider, U as compactPath, V as generateSessionTitle, Vt as setProviderCredential, W as fmtTokens, X as SETTINGS_TOGGLES, Y as SETTINGS_CHOICES, Z as SettingsProvider, _ as discoverProjectSkills, a as ThemeProvider, b as writeSessionExport, c as useSurfaces, ct as ConfigProvider, d as finalizeStreamingMarkdown, f as finalizeStreamingMarkdownForOwner, ft as deriveSessionTitle, g as defaultSkillScanPaths, h as buildSkillsConfig, ht as listSessionMeta, i as turnAsText, j as suggestSafelistEntry, lt as useConfig, m as useStreamBuffer, mt as lastContextSizeFromTurns, n as deleteTurnSafely, nt as resolveTheme, o as useColors, p as turnContextSize, pt as eventsFromTurns, q as useEnabledToggleSet, qt as getContextWindow, r as truncateTurnsAt, s as useSelectStyle, tt as resolveChipColor, u as useTheme, ut as resolveConfig, vt as selectableTurnIds, x as SafeModeProvider, xt as toolCallPreview, yt as stripSpawnTokensLine } from "./turn-operations-5aQu4dJg.js";
5
+ import { $t as piIdOf, C as useSafeModeQueue, Ct as findGitRoot, D as isOnSafelist, E as getSafelist, Et as uniqueSkillNamesFromReferences, F as supportsOAuth, Ft as detectAuth, G as shortId, H as ageString, I as buildMcpServers, J as DEFAULT_SETTINGS, K as listProjectFiles, N as splitPromptSegments, Ot as createFilesCompletionProvider, P as runOAuthLogin, Pt as useCompletion, Q as useSettings, R as discoverProjectMcps, S as useSafeModeActions, St as toolResultText, T as addToSafelist, Tt as createSkillsCompletionProvider, U as compactPath, V as generateSessionTitle, Vt as setProviderCredential, W as fmtTokens, X as SETTINGS_TOGGLES, Y as SETTINGS_CHOICES, Yt as modelSupportsReasoning, Z as SettingsProvider, _ as discoverProjectSkills, a as ThemeProvider, b as writeSessionExport, c as useSurfaces, ct as ConfigProvider, d as finalizeStreamingMarkdown, f as finalizeStreamingMarkdownForOwner, ft as deriveSessionTitle, g as defaultSkillScanPaths, h as buildSkillsConfig, ht as listSessionMeta, i as turnAsText, j as suggestSafelistEntry, lt as useConfig, m as useStreamBuffer, mt as lastContextSizeFromTurns, n as deleteTurnSafely, nt as resolveTheme, o as useColors, p as turnContextSize, pt as eventsFromTurns, q as useEnabledToggleSet, qt as getContextWindow, r as truncateTurnsAt, s as useSelectStyle, tt as resolveChipColor, u as useTheme, ut as resolveConfig, vt as selectableTurnIds, x as SafeModeProvider, xt as toolCallPreview, yt as stripSpawnTokensLine } from "./turn-operations-BF3hMNgo.js";
6
6
  import { Buffer } from "node:buffer";
7
7
  import { createContext, createElement, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
8
8
  import { RGBA, SyntaxStyle, addDefaultParsers, createCliRenderer, defaultTextareaKeyBindings, getTreeSitterClient } from "@opentui/core";
@@ -474,9 +474,17 @@ function renderHintSpans(hints, COLOR) {
474
474
  fg: h.keyColor ?? COLOR.warn,
475
475
  children: h.key
476
476
  }),
477
+ h.extra && /* @__PURE__ */ jsx("span", {
478
+ fg: h.extra.keyColor ?? COLOR.mute,
479
+ children: h.extra.key
480
+ }),
477
481
  /* @__PURE__ */ jsx("span", {
478
482
  fg: h.labelColor ?? COLOR.dim,
479
483
  children: ` ${h.label}`
484
+ }),
485
+ h.extra && /* @__PURE__ */ jsx("span", {
486
+ fg: h.extra.labelColor ?? COLOR.dim,
487
+ children: ` ${h.extra.label}`
480
488
  })
481
489
  ] }, i));
482
490
  }
@@ -645,7 +653,11 @@ function truncateTrailing(text, max) {
645
653
  */
646
654
  function hintsLength(hints) {
647
655
  if (hints.length === 0) return 0;
648
- return hints.reduce((sum, h, i) => sum + h.key.length + 1 + h.label.length + (i > 0 ? 3 : 0), 0);
656
+ return hints.reduce((sum, h, i) => {
657
+ const base = h.key.length + 1 + h.label.length;
658
+ const extra = h.extra ? h.extra.key.length + 1 + h.extra.label.length : 0;
659
+ return sum + base + extra + (i > 0 ? 3 : 0);
660
+ }, 0);
649
661
  }
650
662
  function contextIndicatorLength(context) {
651
663
  const ratio = context.max > 0 ? context.used / context.max : 0;
@@ -1203,6 +1215,94 @@ function ToolResultBlock({ text, indent }) {
1203
1215
  });
1204
1216
  }
1205
1217
  //#endregion
1218
+ //#region src/tui/effort-picker.tsx
1219
+ /**
1220
+ * Reasoning effort options surfaced in the picker. Mirrors {@link ThinkingLevel}
1221
+ * minus `'adaptive'` (Anthropic-only — opt in via {@link EffortPickerModal}'s
1222
+ * `supportsAdaptive` flag rather than confusing OpenAI / OpenRouter users with
1223
+ * a level their model silently treats as `'off'`).
1224
+ */
1225
+ const BASE_LEVELS = [
1226
+ {
1227
+ id: "off",
1228
+ description: "no reasoning — fastest, smallest output"
1229
+ },
1230
+ {
1231
+ id: "minimal",
1232
+ description: "tiny reasoning budget (gpt-5 family)"
1233
+ },
1234
+ {
1235
+ id: "low",
1236
+ description: "short reasoning pass"
1237
+ },
1238
+ {
1239
+ id: "medium",
1240
+ description: "balanced — sensible default"
1241
+ },
1242
+ {
1243
+ id: "high",
1244
+ description: "deep reasoning — slowest, longest"
1245
+ }
1246
+ ];
1247
+ const ADAPTIVE_LEVEL = {
1248
+ id: "adaptive",
1249
+ description: "model decides per-turn (Anthropic)"
1250
+ };
1251
+ /**
1252
+ * Modal that lets the user pick a reasoning effort for the active model.
1253
+ * Only surfaced for models whose registry entry reports
1254
+ * `reasoning: true` — see `modelSupportsReasoning`.
1255
+ *
1256
+ * `'adaptive'` is Anthropic-only; pass `supportsAdaptive` to surface it.
1257
+ */
1258
+ function EffortPickerModal({ current, supportsAdaptive, onPick }) {
1259
+ const COLOR = useColors();
1260
+ const SELECT_THEME = useSelectStyle();
1261
+ const levels = useMemo(() => supportsAdaptive ? [...BASE_LEVELS, ADAPTIVE_LEVEL] : BASE_LEVELS, [supportsAdaptive]);
1262
+ const options = useMemo(() => levels.map((l) => ({
1263
+ name: `${l.id === current ? "● " : " "}${l.id}`,
1264
+ description: l.description,
1265
+ value: l.id
1266
+ })), [levels, current]);
1267
+ const initialIndex = useMemo(() => {
1268
+ const idx = levels.findIndex((l) => l.id === current);
1269
+ return idx < 0 ? levels.findIndex((l) => l.id === "medium") : idx;
1270
+ }, [levels, current]);
1271
+ return /* @__PURE__ */ jsxs(Modal, {
1272
+ title: "select reasoning effort",
1273
+ children: [/* @__PURE__ */ jsx("select", {
1274
+ ...SELECT_THEME,
1275
+ focused: true,
1276
+ options,
1277
+ wrapSelection: true,
1278
+ selectedIndex: Math.max(0, initialIndex),
1279
+ style: { height: levels.length },
1280
+ onSelect: (_idx, option) => {
1281
+ if (option) onPick(option.value);
1282
+ }
1283
+ }), /* @__PURE__ */ jsxs("text", {
1284
+ fg: COLOR.mute,
1285
+ children: [
1286
+ /* @__PURE__ */ jsx("span", {
1287
+ fg: COLOR.warn,
1288
+ children: "↑↓"
1289
+ }),
1290
+ " navigate · ",
1291
+ /* @__PURE__ */ jsx("span", {
1292
+ fg: COLOR.warn,
1293
+ children: "↵"
1294
+ }),
1295
+ " select · ",
1296
+ /* @__PURE__ */ jsx("span", {
1297
+ fg: COLOR.warn,
1298
+ children: "esc"
1299
+ }),
1300
+ " close"
1301
+ ]
1302
+ })]
1303
+ });
1304
+ }
1305
+ //#endregion
1206
1306
  //#region src/tui/toggle-list-modal.tsx
1207
1307
  /**
1208
1308
  * Generic list-with-checkboxes modal. Powers both the Skills and MCP
@@ -4160,9 +4260,15 @@ function AppShell() {
4160
4260
  const descriptor = providerRegistry[provider.key];
4161
4261
  if (!descriptor) return null;
4162
4262
  const remembered = initialState.lastModelByProvider?.[provider.key];
4163
- return {
4263
+ const model = modelId ?? remembered ?? descriptor.defaultModel ?? descriptor.factory().meta.defaultModel;
4264
+ const effort = effortForModel(descriptor, model, initialState.lastEffortByModel);
4265
+ return effort ? {
4266
+ provider,
4267
+ model,
4268
+ effort
4269
+ } : {
4164
4270
  provider,
4165
- model: modelId ?? remembered ?? descriptor.defaultModel ?? descriptor.factory().meta.defaultModel
4271
+ model
4166
4272
  };
4167
4273
  }, [providerRegistry, initialState]);
4168
4274
  const buildAgent = useCallback((session, key) => {
@@ -4429,6 +4535,7 @@ function AppShell() {
4429
4535
  const onPickModel = useCallback((modelId) => {
4430
4536
  setPicked((prev) => {
4431
4537
  if (!prev) return prev;
4538
+ const descriptor = providerRegistry[prev.provider.key];
4432
4539
  const prior = stateStore.load();
4433
4540
  stateStore.save({
4434
4541
  ...prior,
@@ -4437,13 +4544,45 @@ function AppShell() {
4437
4544
  [prev.provider.key]: modelId
4438
4545
  }
4439
4546
  });
4440
- return {
4547
+ const nextEffort = descriptor ? effortForModel(descriptor, modelId, prior.lastEffortByModel) : void 0;
4548
+ return nextEffort ? {
4441
4549
  ...prev,
4550
+ model: modelId,
4551
+ effort: nextEffort
4552
+ } : {
4553
+ provider: prev.provider,
4442
4554
  model: modelId
4443
4555
  };
4444
4556
  });
4445
4557
  modal.close();
4558
+ }, [
4559
+ modal,
4560
+ stateStore,
4561
+ providerRegistry
4562
+ ]);
4563
+ const onPickEffort = useCallback((effort) => {
4564
+ setPicked((prev) => {
4565
+ if (!prev) return prev;
4566
+ const prior = stateStore.load();
4567
+ stateStore.save({
4568
+ ...prior,
4569
+ lastEffortByModel: {
4570
+ ...prior.lastEffortByModel,
4571
+ [prev.model]: effort
4572
+ }
4573
+ });
4574
+ return {
4575
+ ...prev,
4576
+ effort
4577
+ };
4578
+ });
4579
+ modal.close();
4446
4580
  }, [modal, stateStore]);
4581
+ const modelHasReasoning = useMemo(() => {
4582
+ if (!picked) return false;
4583
+ const descriptor = providerRegistry[picked.provider.key];
4584
+ return !!descriptor && modelSupportsReasoning(descriptor, picked.model);
4585
+ }, [picked, providerRegistry]);
4447
4586
  const onPickAgent = useCallback(async (id) => {
4448
4587
  const profile = agentRegistry[id];
4449
4588
  if (!profile) return;
@@ -4500,7 +4639,8 @@ function AppShell() {
4500
4639
  try {
4501
4640
  await agent.run({
4502
4641
  model: picked.model,
4503
- prompt
4642
+ prompt,
4643
+ ...picked.effort ? { thinking: picked.effort } : {}
4504
4644
  });
4505
4645
  await session.save().catch((err) => debugLog("session.save failed", err));
4506
4646
  setCurrentSession((prev) => prev ? {
@@ -4818,6 +4958,15 @@ function AppShell() {
4818
4958
  }));
4819
4959
  return;
4820
4960
  }
4961
+ if (key.ctrl && key.name === "n" && screen === "chat" && picked && !busy && modelHasReasoning) {
4962
+ const descriptor = providerRegistry[picked.provider.key];
4963
+ modal.open(/* @__PURE__ */ jsx(EffortPickerModal, {
4964
+ current: picked.effort,
4965
+ supportsAdaptive: !!descriptor && piIdOf(descriptor) === "anthropic",
4966
+ onPick: onPickEffort
4967
+ }));
4968
+ return;
4969
+ }
4821
4970
  if (key.ctrl && key.name === "s" && screen === "chat" && !busy && !pendingApproval) {
4822
4971
  enterSelectMode();
4823
4972
  return;
@@ -4848,6 +4997,9 @@ function AppShell() {
4848
4997
  hasMultipleAgents,
4849
4998
  modelLabel: picked?.model ?? null,
4850
4999
  modelColor: COLOR.model,
5000
+ effortLabel: modelHasReasoning ? picked?.effort ?? "medium" : null,
5001
+ effortColor: COLOR.warn,
5002
+ effortKeyColor: COLOR.warn,
4851
5003
  agentLabel: pickedAgent.label,
4852
5004
  agentColor: accentColor(pickedAgent.accent, COLOR)
4853
5005
  }), [
@@ -4858,7 +5010,8 @@ function AppShell() {
4858
5010
  hasMultipleAgents,
4859
5011
  picked,
4860
5012
  pickedAgent,
4861
- COLOR
5013
+ COLOR,
5014
+ modelHasReasoning
4862
5015
  ]);
4863
5016
  const promptTriggerHints = useMemo(() => {
4864
5017
  const out = [];
@@ -4941,12 +5094,25 @@ function AppShell() {
4941
5094
  });
4942
5095
  }
4943
5096
  /**
5097
+ * Resolve the reasoning effort to seed `Picked.effort` for the given model.
5098
+ * Returns `undefined` when the model has no reasoning knob; otherwise the
5099
+ * per-model remembered value, defaulting to `'medium'` (sensible middle
5100
+ * ground when the user has never picked an explicit effort for this model).
5101
+ */
5102
+ function effortForModel(descriptor, modelId, remembered) {
5103
+ if (!modelSupportsReasoning(descriptor, modelId)) return void 0;
5104
+ return remembered?.[modelId] ?? "medium";
5105
+ }
5106
+ /**
4944
5107
  * Build the footer's shortcut hints for the current screen. On the chat
4945
5108
  * screen the model id rides next to its `ctrl+m` shortcut and the agent
4946
5109
  * label rides next to `shift+tab`, each in its accent color — the bar
4947
- * doubles as the status display without needing separate badges.
5110
+ * doubles as the status display without needing separate badges. When
5111
+ * the active model exposes reasoning, the `ctrl+m` hint grows a
5112
+ * secondary `/n` chord with the current effort label, surfacing the
5113
+ * effort picker as a discoverable, in-place affordance.
4948
5114
  */
4949
- function buildHints({ screen, busy, pending, currentSession, hasMultipleAgents, modelLabel, modelColor, agentLabel, agentColor }) {
5115
+ function buildHints({ screen, busy, pending, currentSession, hasMultipleAgents, modelLabel, modelColor, effortLabel, effortColor, effortKeyColor, agentLabel, agentColor }) {
4950
5116
  if (pending) return [
4951
5117
  {
4952
5118
  key: "↑↓",
@@ -5001,17 +5167,24 @@ function buildHints({ screen, busy, pending, currentSession, hasMultipleAgents,
5001
5167
  label: currentSession ? "back" : "exit"
5002
5168
  }
5003
5169
  ];
5170
+ const modelHint = modelLabel ? {
5171
+ key: "ctrl+m",
5172
+ label: modelLabel,
5173
+ labelColor: modelColor,
5174
+ ...effortLabel ? { extra: {
5175
+ key: "/n",
5176
+ keyColor: effortKeyColor,
5177
+ label: effortLabel,
5178
+ labelColor: effortColor
5179
+ } } : {}
5180
+ } : null;
5004
5181
  return [
5005
5182
  ...hasMultipleAgents ? [{
5006
5183
  key: "shift+tab",
5007
5184
  label: agentLabel,
5008
5185
  labelColor: agentColor
5009
5186
  }] : [],
5010
- ...modelLabel ? [{
5011
- key: "ctrl+m",
5012
- label: modelLabel,
5013
- labelColor: modelColor
5014
- }] : [],
5187
+ ...modelHint ? [modelHint] : [],
5015
5188
  ...currentSession ? [{
5016
5189
  key: "ctrl+x",
5017
5190
  label: "session"