@iaforged/context-code 1.1.9 → 1.2.1

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 (78) hide show
  1. package/README.md +24 -0
  2. package/dist/src/commands/model/model.js +9 -5
  3. package/dist/src/commands/timeline/index.js +8 -0
  4. package/dist/src/commands/timeline/timeline.js +194 -0
  5. package/dist/src/commands.js +2 -0
  6. package/dist/src/components/AgentActivitySidebar.js +50 -0
  7. package/dist/src/components/AgentProgressLine.js +5 -5
  8. package/dist/src/components/ModelPicker.js +252 -441
  9. package/dist/src/components/PromptInput/PromptInputFooter.js +10 -29
  10. package/dist/src/components/Spinner/TeammateSpinnerLine.js +20 -62
  11. package/dist/src/components/Spinner/TeammateSpinnerTree.js +16 -258
  12. package/dist/src/components/Spinner/teammateSelectHint.js +1 -1
  13. package/dist/src/components/Spinner/utils.js +3 -6
  14. package/dist/src/components/ThemeBrowser.js +120 -0
  15. package/dist/src/components/ThemePicker.js +113 -321
  16. package/dist/src/components/design-system/ThemeProvider.js +3 -0
  17. package/dist/src/components/mcp/MCPListPanel.js +138 -444
  18. package/dist/src/components/permissions/SandboxPermissionRequest.js +5 -5
  19. package/dist/src/components/teams/TeamStatus.js +7 -71
  20. package/dist/src/constants/spinnerVerbs.js +80 -180
  21. package/dist/src/context/modalStackContext.js +12 -0
  22. package/dist/src/hooks/useTextInput.js +28 -18
  23. package/dist/src/main.js +12 -0
  24. package/dist/src/screens/REPL.js +386 -320
  25. package/dist/src/skills/loadSkillsDir.js +1 -0
  26. package/dist/src/tools/AgentTool/UI.js +8 -8
  27. package/dist/src/tools/BashTool/bashSecurity.js +1 -1
  28. package/dist/src/utils/handlePromptSubmit.js +12 -2
  29. package/dist/src/utils/processUserInput/processSlashCommand.js +9 -5
  30. package/dist/src/utils/sembleMcp/common.js +5 -0
  31. package/dist/src/utils/sembleMcp/setup.js +119 -0
  32. package/dist/src/utils/theme.js +24 -3
  33. package/dist/src/utils/themes/bootstrap.js +109 -0
  34. package/dist/src/utils/themes/builtin/opencode/_index.json +41 -0
  35. package/dist/src/utils/themes/builtin/opencode/amoled.json +49 -0
  36. package/dist/src/utils/themes/builtin/opencode/aura.json +51 -0
  37. package/dist/src/utils/themes/builtin/opencode/ayu.json +51 -0
  38. package/dist/src/utils/themes/builtin/opencode/carbonfox.json +53 -0
  39. package/dist/src/utils/themes/builtin/opencode/catppuccin-frappe.json +85 -0
  40. package/dist/src/utils/themes/builtin/opencode/catppuccin-macchiato.json +85 -0
  41. package/dist/src/utils/themes/builtin/opencode/catppuccin.json +45 -0
  42. package/dist/src/utils/themes/builtin/opencode/cobalt2.json +87 -0
  43. package/dist/src/utils/themes/builtin/opencode/cursor.json +91 -0
  44. package/dist/src/utils/themes/builtin/opencode/dracula.json +49 -0
  45. package/dist/src/utils/themes/builtin/opencode/everforest.json +89 -0
  46. package/dist/src/utils/themes/builtin/opencode/flexoki.json +86 -0
  47. package/dist/src/utils/themes/builtin/opencode/github.json +85 -0
  48. package/dist/src/utils/themes/builtin/opencode/gruvbox.json +45 -0
  49. package/dist/src/utils/themes/builtin/opencode/kanagawa.json +89 -0
  50. package/dist/src/utils/themes/builtin/opencode/lucent-orng.json +87 -0
  51. package/dist/src/utils/themes/builtin/opencode/material.json +87 -0
  52. package/dist/src/utils/themes/builtin/opencode/matrix.json +91 -0
  53. package/dist/src/utils/themes/builtin/opencode/mercury.json +86 -0
  54. package/dist/src/utils/themes/builtin/opencode/monokai.json +49 -0
  55. package/dist/src/utils/themes/builtin/opencode/nightowl.json +46 -0
  56. package/dist/src/utils/themes/builtin/opencode/nord.json +46 -0
  57. package/dist/src/utils/themes/builtin/opencode/oc-2.json +88 -0
  58. package/dist/src/utils/themes/builtin/opencode/one-dark.json +89 -0
  59. package/dist/src/utils/themes/builtin/opencode/onedarkpro.json +45 -0
  60. package/dist/src/utils/themes/builtin/opencode/opencode.json +89 -0
  61. package/dist/src/utils/themes/builtin/opencode/orng.json +87 -0
  62. package/dist/src/utils/themes/builtin/opencode/osaka-jade.json +88 -0
  63. package/dist/src/utils/themes/builtin/opencode/palenight.json +85 -0
  64. package/dist/src/utils/themes/builtin/opencode/rosepine.json +85 -0
  65. package/dist/src/utils/themes/builtin/opencode/shadesofpurple.json +51 -0
  66. package/dist/src/utils/themes/builtin/opencode/solarized.json +49 -0
  67. package/dist/src/utils/themes/builtin/opencode/synthwave84.json +87 -0
  68. package/dist/src/utils/themes/builtin/opencode/tokyonight.json +47 -0
  69. package/dist/src/utils/themes/builtin/opencode/vercel.json +90 -0
  70. package/dist/src/utils/themes/builtin/opencode/vesper.json +51 -0
  71. package/dist/src/utils/themes/builtin/opencode/zenburn.json +87 -0
  72. package/dist/src/utils/themes/index.js +4 -0
  73. package/dist/src/utils/themes/loader.js +147 -0
  74. package/dist/src/utils/themes/opencodeMapper.js +124 -0
  75. package/dist/src/utils/themes/resolver.js +66 -0
  76. package/dist/src/utils/themes/types.js +1 -0
  77. package/docs/MCP_SERVERS.md +27 -1
  78. package/package.json +1 -1
@@ -1,18 +1,19 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { c as _c } from "react/compiler-runtime";
3
2
  import capitalize from 'lodash-es/capitalize.js';
4
3
  import * as React from 'react';
5
4
  import { useMemo, useState } from 'react';
6
5
  import { useExitOnCtrlCDWithKeybindings } from '../hooks/useExitOnCtrlCDWithKeybindings.js';
7
- import { logEvent } from '../services/analytics/index.js';
8
- import { FAST_MODE_MODEL_DISPLAY, isFastModeAvailable, isFastModeCooldown, isFastModeEnabled } from '../utils/fastMode.js';
9
- import { Box, Text } from '../ink.js';
6
+ import { logEvent, } from '../services/analytics/index.js';
7
+ import { FAST_MODE_MODEL_DISPLAY, isFastModeAvailable, isFastModeCooldown, isFastModeEnabled, } from '../utils/fastMode.js';
8
+ import { Box, Text, useInput } from '../ink.js';
10
9
  import { useKeybindings } from '../keybindings/useKeybinding.js';
11
10
  import { useAppState, useSetAppState } from '../state/AppState.js';
12
- import { convertEffortValueToLevel, getDefaultEffortForModel, modelSupportsEffort, modelSupportsMaxEffort, resolvePickerEffortPersistence, toPersistableEffort } from '../utils/effort.js';
13
- import { getDefaultMainLoopModel, modelDisplayString, parseUserSpecifiedModel } from '../utils/model/model.js';
11
+ import { getGlobalConfig, saveGlobalConfig } from '../utils/config.js';
12
+ import { convertEffortValueToLevel, getDefaultEffortForModel, modelSupportsEffort, modelSupportsMaxEffort, resolvePickerEffortPersistence, toPersistableEffort, } from '../utils/effort.js';
13
+ import { getDefaultMainLoopModel, modelDisplayString, parseUserSpecifiedModel, } from '../utils/model/model.js';
14
14
  import { getModelOptions } from '../utils/model/modelOptions.js';
15
- import { getSettingsForSource, updateSettingsForSource } from '../utils/settings/settings.js';
15
+ import { getAPIProvider } from '../utils/model/providers.js';
16
+ import { getSettingsForSource, updateSettingsForSource, } from '../utils/settings/settings.js';
16
17
  import { ConfigurableShortcutHint } from './ConfigurableShortcutHint.js';
17
18
  import { Select } from './CustomSelect/index.js';
18
19
  import { Byline } from './design-system/Byline.js';
@@ -20,41 +21,93 @@ import { KeyboardShortcutHint } from './design-system/KeyboardShortcutHint.js';
20
21
  import { Pane } from './design-system/Pane.js';
21
22
  import { effortLevelToSymbol } from './EffortIndicator.js';
22
23
  const NO_PREFERENCE = '__NO_PREFERENCE__';
23
- export function ModelPicker(t0) {
24
- const $ = _c(82);
25
- const { initial, sessionModel, onSelect, onCancel, isStandaloneCommand, showFastModeNotice, headerText, skipSettingsWrite } = t0;
24
+ const HEADER_PREFIX = '__MODEL_HEADER__';
25
+ function readPickerState() {
26
+ const cfg = getGlobalConfig();
27
+ return {
28
+ favorites: cfg.modelPickerFavorites ?? [],
29
+ recent: cfg.modelPickerRecent ?? [],
30
+ };
31
+ }
32
+ function writePickerState(next) {
33
+ saveGlobalConfig(current => ({
34
+ ...current,
35
+ modelPickerFavorites: next.favorites,
36
+ modelPickerRecent: next.recent,
37
+ }));
38
+ }
39
+ function providerLabel(provider) {
40
+ switch (provider) {
41
+ case 'firstParty':
42
+ return 'Claude';
43
+ case 'openai':
44
+ return 'OpenAI';
45
+ case 'openrouter':
46
+ return 'OpenRouter';
47
+ case 'ollama':
48
+ return 'Ollama';
49
+ case 'ollama-cloud':
50
+ return 'Ollama Cloud';
51
+ case 'gemini-api':
52
+ return 'Gemini API';
53
+ case 'gemini-google':
54
+ return 'Gemini Google';
55
+ case 'zai':
56
+ return 'Z.AI';
57
+ case 'minimax':
58
+ return 'MiniMax';
59
+ case 'nvidia':
60
+ return 'NVIDIA';
61
+ default:
62
+ return provider;
63
+ }
64
+ }
65
+ function asSelectValue(value) {
66
+ return value === null ? NO_PREFERENCE : value;
67
+ }
68
+ function asModelValue(value) {
69
+ return value === NO_PREFERENCE ? null : value;
70
+ }
71
+ function isHeaderValue(value) {
72
+ return value?.startsWith(HEADER_PREFIX) ?? false;
73
+ }
74
+ function resolveOptionModel(value) {
75
+ if (!value || isHeaderValue(value))
76
+ return undefined;
77
+ return value === NO_PREFERENCE ? getDefaultMainLoopModel() : parseUserSpecifiedModel(value);
78
+ }
79
+ function getDefaultEffortLevelForOption(value) {
80
+ const resolved = resolveOptionModel(value) ?? getDefaultMainLoopModel();
81
+ const defaultValue = getDefaultEffortForModel(resolved);
82
+ return defaultValue !== undefined ? convertEffortValueToLevel(defaultValue) : 'high';
83
+ }
84
+ function cycleEffortLevel(current, direction, includeMax) {
85
+ const levels = includeMax
86
+ ? ['low', 'medium', 'high', 'max']
87
+ : ['low', 'medium', 'high'];
88
+ const idx = levels.indexOf(current);
89
+ const currentIndex = idx !== -1 ? idx : levels.indexOf('high');
90
+ if (direction === 'right') {
91
+ return levels[(currentIndex + 1) % levels.length];
92
+ }
93
+ return levels[(currentIndex - 1 + levels.length) % levels.length];
94
+ }
95
+ function EffortLevelIndicator({ effort }) {
96
+ return (_jsx(Text, { color: effort ? 'claude' : 'subtle', children: effortLevelToSymbol(effort ?? 'low') }));
97
+ }
98
+ export function ModelPicker({ initial, sessionModel, onSelect, onCancel, isStandaloneCommand, showFastModeNotice, headerText, skipSettingsWrite, onOpenProvider, }) {
26
99
  const setAppState = useSetAppState();
27
100
  const exitState = useExitOnCtrlCDWithKeybindings();
28
101
  const initialValue = initial === null ? NO_PREFERENCE : initial;
29
102
  const [focusedValue, setFocusedValue] = useState(initialValue);
30
- const isFastMode = useAppState(_temp);
103
+ const [pickerState, setPickerState] = useState(() => readPickerState());
104
+ const isFastMode = useAppState(s => (isFastModeEnabled() ? s.fastMode : false));
31
105
  const [hasToggledEffort, setHasToggledEffort] = useState(false);
32
- const effortValue = useAppState(_temp2);
33
- let t1;
34
- if ($[0] !== effortValue) {
35
- t1 = effortValue !== undefined ? convertEffortValueToLevel(effortValue) : undefined;
36
- $[0] = effortValue;
37
- $[1] = t1;
38
- }
39
- else {
40
- t1 = $[1];
41
- }
42
- const [effort, setEffort] = useState(t1);
43
- const t2 = (isFastMode ?? false);
44
- let t3;
45
- if ($[2] !== t2) {
46
- t3 = getModelOptions(t2);
47
- $[2] = t2;
48
- $[3] = t3;
49
- }
50
- else {
51
- t3 = $[3];
52
- }
106
+ const effortValue = useAppState(s => s.effortValue);
107
+ const [effort, setEffort] = useState(effortValue !== undefined ? convertEffortValueToLevel(effortValue) : undefined);
53
108
  const [dynamicModels, setDynamicModels] = useState([]);
54
- const [isLoadingDynamic, setIsLoadingDynamic] = useState(false);
55
109
  React.useEffect(() => {
56
- (async () => {
57
- const { getAPIProvider } = await import('../utils/model/providers.js');
110
+ void (async () => {
58
111
  const provider = getAPIProvider();
59
112
  if (provider === 'openai' ||
60
113
  provider === 'openrouter' ||
@@ -71,426 +124,184 @@ export function ModelPicker(t0) {
71
124
  setDynamicModels(cached);
72
125
  }
73
126
  else {
74
- setIsLoadingDynamic(true);
75
127
  const fetched = await fetchProviderModels(provider);
76
128
  setDynamicModels(fetched);
77
- setIsLoadingDynamic(false);
78
129
  }
79
130
  }
80
131
  })();
81
132
  }, []);
82
- const modelOptionsFromConfig = t3;
133
+ const modelOptionsFromConfig = useMemo(() => getModelOptions((isFastMode ?? false)), [isFastMode]);
83
134
  const modelOptions = useMemo(() => {
84
- if (dynamicModels.length > 0) {
85
- const seen = new Set();
86
- const merged = [...modelOptionsFromConfig, ...dynamicModels].filter(option => {
87
- const key = option.value ?? NO_PREFERENCE;
88
- if (seen.has(key)) {
89
- return false;
90
- }
91
- seen.add(key);
92
- return true;
93
- });
94
- return merged;
95
- }
96
- return modelOptionsFromConfig;
135
+ if (dynamicModels.length === 0)
136
+ return modelOptionsFromConfig;
137
+ const seen = new Set();
138
+ return [...modelOptionsFromConfig, ...dynamicModels].filter(option => {
139
+ const key = option.value ?? NO_PREFERENCE;
140
+ if (seen.has(key))
141
+ return false;
142
+ seen.add(key);
143
+ return true;
144
+ });
97
145
  }, [modelOptionsFromConfig, dynamicModels]);
98
- let t4;
99
- bb0: {
146
+ const optionsWithInitial = useMemo(() => {
100
147
  if (initial !== null && !modelOptions.some(opt => opt.value === initial)) {
101
- let t5;
102
- if ($[4] !== initial) {
103
- t5 = modelDisplayString(initial);
104
- $[4] = initial;
105
- $[5] = t5;
106
- }
107
- else {
108
- t5 = $[5];
109
- }
110
- let t6;
111
- if ($[6] !== initial || $[7] !== t5) {
112
- t6 = {
148
+ return [
149
+ ...modelOptions,
150
+ {
113
151
  value: initial,
114
- label: t5,
115
- description: "Modelo actual"
116
- };
117
- $[6] = initial;
118
- $[7] = t5;
119
- $[8] = t6;
120
- }
121
- else {
122
- t6 = $[8];
123
- }
124
- let t7;
125
- if ($[9] !== modelOptions || $[10] !== t6) {
126
- t7 = [...modelOptions, t6];
127
- $[9] = modelOptions;
128
- $[10] = t6;
129
- $[11] = t7;
130
- }
131
- else {
132
- t7 = $[11];
133
- }
134
- t4 = t7;
135
- break bb0;
152
+ label: modelDisplayString(initial),
153
+ description: 'Modelo actual',
154
+ },
155
+ ];
136
156
  }
137
- t4 = modelOptions;
138
- }
139
- const optionsWithInitial = t4;
140
- let t5;
141
- if ($[12] !== optionsWithInitial) {
142
- t5 = optionsWithInitial.map(_temp3);
143
- $[12] = optionsWithInitial;
144
- $[13] = t5;
145
- }
146
- else {
147
- t5 = $[13];
148
- }
149
- const selectOptions = t5;
150
- let t6;
151
- if ($[14] !== initialValue || $[15] !== selectOptions) {
152
- t6 = selectOptions.some(_ => _.value === initialValue) ? initialValue : selectOptions[0]?.value ?? undefined;
153
- $[14] = initialValue;
154
- $[15] = selectOptions;
155
- $[16] = t6;
156
- }
157
- else {
158
- t6 = $[16];
159
- }
160
- const initialFocusValue = t6;
161
- const visibleCount = Math.min(10, selectOptions.length);
162
- const hiddenCount = Math.max(0, selectOptions.length - visibleCount);
163
- let t7;
164
- if ($[17] !== focusedValue || $[18] !== selectOptions) {
165
- t7 = selectOptions.find(opt_1 => opt_1.value === focusedValue)?.label;
166
- $[17] = focusedValue;
167
- $[18] = selectOptions;
168
- $[19] = t7;
169
- }
170
- else {
171
- t7 = $[19];
172
- }
173
- const focusedModelName = t7;
174
- let focusedSupportsEffort;
175
- let t8;
176
- if ($[20] !== focusedValue) {
177
- const focusedModel = resolveOptionModel(focusedValue);
178
- focusedSupportsEffort = focusedModel ? modelSupportsEffort(focusedModel) : false;
179
- t8 = focusedModel ? modelSupportsMaxEffort(focusedModel) : false;
180
- $[20] = focusedValue;
181
- $[21] = focusedSupportsEffort;
182
- $[22] = t8;
183
- }
184
- else {
185
- focusedSupportsEffort = $[21];
186
- t8 = $[22];
187
- }
188
- const focusedSupportsMax = t8;
189
- let t9;
190
- if ($[23] !== focusedValue) {
191
- t9 = getDefaultEffortLevelForOption(focusedValue);
192
- $[23] = focusedValue;
193
- $[24] = t9;
194
- }
195
- else {
196
- t9 = $[24];
197
- }
198
- const focusedDefaultEffort = t9;
199
- const displayEffort = effort === "max" && !focusedSupportsMax ? "high" : effort;
200
- let t10;
201
- if ($[25] !== effortValue || $[26] !== hasToggledEffort) {
202
- t10 = value => {
203
- setFocusedValue(value);
204
- if (!hasToggledEffort && effortValue === undefined) {
205
- setEffort(getDefaultEffortLevelForOption(value));
206
- }
207
- };
208
- $[25] = effortValue;
209
- $[26] = hasToggledEffort;
210
- $[27] = t10;
211
- }
212
- else {
213
- t10 = $[27];
214
- }
215
- const handleFocus = t10;
216
- let t11;
217
- if ($[28] !== focusedDefaultEffort || $[29] !== focusedSupportsEffort || $[30] !== focusedSupportsMax) {
218
- t11 = direction => {
219
- if (!focusedSupportsEffort) {
220
- return;
157
+ return modelOptions;
158
+ }, [initial, modelOptions]);
159
+ const optionMap = useMemo(() => new Map(optionsWithInitial.map(option => [asSelectValue(option.value), option])), [optionsWithInitial]);
160
+ const groupedOptions = useMemo(() => {
161
+ const allValues = optionsWithInitial.map(opt => asSelectValue(opt.value));
162
+ const availableSet = new Set(allValues);
163
+ const favorites = pickerState.favorites.filter(value => availableSet.has(value));
164
+ const recent = pickerState.recent.filter(value => value !== NO_PREFERENCE && availableSet.has(value) && !favorites.includes(value));
165
+ const remaining = allValues.filter(value => !favorites.includes(value) && !recent.includes(value));
166
+ const rows = [];
167
+ if (favorites.length > 0) {
168
+ rows.push({
169
+ value: `${HEADER_PREFIX}:favorites`,
170
+ label: 'Favorites',
171
+ disabled: true,
172
+ });
173
+ for (const value of favorites) {
174
+ const option = optionMap.get(value);
175
+ if (!option)
176
+ continue;
177
+ rows.push({
178
+ value,
179
+ label: `★ ${option.label}`,
180
+ description: option.description,
181
+ });
221
182
  }
222
- setEffort(prev => cycleEffortLevel(prev ?? focusedDefaultEffort, direction, focusedSupportsMax));
223
- setHasToggledEffort(true);
224
- };
225
- $[28] = focusedDefaultEffort;
226
- $[29] = focusedSupportsEffort;
227
- $[30] = focusedSupportsMax;
228
- $[31] = t11;
229
- }
230
- else {
231
- t11 = $[31];
232
- }
233
- const handleCycleEffort = t11;
234
- let t12;
235
- if ($[32] !== handleCycleEffort) {
236
- t12 = {
237
- "modelPicker:decreaseEffort": () => handleCycleEffort("left"),
238
- "modelPicker:increaseEffort": () => handleCycleEffort("right")
239
- };
240
- $[32] = handleCycleEffort;
241
- $[33] = t12;
242
- }
243
- else {
244
- t12 = $[33];
245
- }
246
- let t13;
247
- if ($[34] === Symbol.for("react.memo_cache_sentinel")) {
248
- t13 = {
249
- context: "ModelPicker"
250
- };
251
- $[34] = t13;
252
- }
253
- else {
254
- t13 = $[34];
255
- }
256
- useKeybindings(t12, t13);
257
- let t14;
258
- if ($[35] !== effort || $[36] !== hasToggledEffort || $[37] !== onSelect || $[38] !== setAppState || $[39] !== skipSettingsWrite) {
259
- t14 = function handleSelect(value_0) {
260
- logEvent("tengu_model_command_menu_effort", {
261
- effort: effort
183
+ }
184
+ if (recent.length > 0) {
185
+ rows.push({
186
+ value: `${HEADER_PREFIX}:recent`,
187
+ label: 'Recent',
188
+ disabled: true,
262
189
  });
263
- if (!skipSettingsWrite) {
264
- const effortLevel = resolvePickerEffortPersistence(effort, getDefaultEffortLevelForOption(value_0), getSettingsForSource("userSettings")?.effortLevel, hasToggledEffort);
265
- const persistable = toPersistableEffort(effortLevel);
266
- if (persistable !== undefined) {
267
- updateSettingsForSource("userSettings", {
268
- effortLevel: persistable
269
- });
270
- }
271
- setAppState(prev_0 => ({
272
- ...prev_0,
273
- effortValue: effortLevel
274
- }));
190
+ for (const value of recent) {
191
+ const option = optionMap.get(value);
192
+ if (!option)
193
+ continue;
194
+ rows.push({
195
+ value,
196
+ label: option.label,
197
+ description: option.description,
198
+ });
275
199
  }
276
- const selectedModel = resolveOptionModel(value_0);
277
- const selectedEffort = hasToggledEffort && selectedModel && modelSupportsEffort(selectedModel) ? effort : undefined;
278
- if (value_0 === NO_PREFERENCE) {
279
- onSelect(null, selectedEffort);
280
- return;
200
+ }
201
+ rows.push({
202
+ value: `${HEADER_PREFIX}:provider`,
203
+ label: providerLabel(getAPIProvider()),
204
+ disabled: true,
205
+ });
206
+ for (const value of remaining) {
207
+ const option = optionMap.get(value);
208
+ if (!option)
209
+ continue;
210
+ rows.push({
211
+ value,
212
+ label: option.label,
213
+ description: option.description,
214
+ });
215
+ }
216
+ return rows;
217
+ }, [optionMap, optionsWithInitial, pickerState.favorites, pickerState.recent]);
218
+ const initialFocusValue = useMemo(() => {
219
+ if (groupedOptions.some(opt => opt.value === initialValue && !opt.disabled)) {
220
+ return initialValue;
221
+ }
222
+ return groupedOptions.find(opt => !opt.disabled)?.value;
223
+ }, [groupedOptions, initialValue]);
224
+ const visibleCount = Math.min(10, groupedOptions.length);
225
+ const hiddenCount = Math.max(0, groupedOptions.length - visibleCount);
226
+ const focusedModelName = groupedOptions.find(opt => opt.value === focusedValue)?.label;
227
+ const focusedModel = resolveOptionModel(focusedValue);
228
+ const focusedSupportsEffort = focusedModel ? modelSupportsEffort(focusedModel) : false;
229
+ const focusedSupportsMax = focusedModel ? modelSupportsMaxEffort(focusedModel) : false;
230
+ const focusedDefaultEffort = getDefaultEffortLevelForOption(focusedValue);
231
+ const displayEffort = effort === 'max' && !focusedSupportsMax ? 'high' : effort;
232
+ const handleCycleEffort = (direction) => {
233
+ if (!focusedSupportsEffort)
234
+ return;
235
+ setEffort(prev => cycleEffortLevel(prev ?? focusedDefaultEffort, direction, focusedSupportsMax));
236
+ setHasToggledEffort(true);
237
+ };
238
+ useKeybindings({
239
+ 'modelPicker:decreaseEffort': () => handleCycleEffort('left'),
240
+ 'modelPicker:increaseEffort': () => handleCycleEffort('right'),
241
+ }, { context: 'ModelPicker' });
242
+ useInput((input, key) => {
243
+ const value = focusedValue;
244
+ if (!value || isHeaderValue(value))
245
+ return;
246
+ if (key.ctrl && input.toLowerCase() === 'f' && value !== NO_PREFERENCE) {
247
+ const nextFavorites = pickerState.favorites.includes(value)
248
+ ? pickerState.favorites.filter(item => item !== value)
249
+ : [value, ...pickerState.favorites].slice(0, 25);
250
+ const nextState = { ...pickerState, favorites: nextFavorites };
251
+ setPickerState(nextState);
252
+ writePickerState(nextState);
253
+ return;
254
+ }
255
+ if (key.ctrl && input.toLowerCase() === 'a' && onOpenProvider) {
256
+ onOpenProvider();
257
+ }
258
+ });
259
+ const handleFocus = (value) => {
260
+ setFocusedValue(value);
261
+ if (!hasToggledEffort && effortValue === undefined && !isHeaderValue(value)) {
262
+ setEffort(getDefaultEffortLevelForOption(value));
263
+ }
264
+ };
265
+ const handleSelect = (value) => {
266
+ if (isHeaderValue(value))
267
+ return;
268
+ logEvent('tengu_model_command_menu_effort', {
269
+ effort: effort,
270
+ });
271
+ if (!skipSettingsWrite) {
272
+ const effortLevel = resolvePickerEffortPersistence(effort, getDefaultEffortLevelForOption(value), getSettingsForSource('userSettings')?.effortLevel, hasToggledEffort);
273
+ const persistable = toPersistableEffort(effortLevel);
274
+ if (persistable !== undefined) {
275
+ updateSettingsForSource('userSettings', { effortLevel: persistable });
281
276
  }
282
- onSelect(value_0, selectedEffort);
283
- };
284
- $[35] = effort;
285
- $[36] = hasToggledEffort;
286
- $[37] = onSelect;
287
- $[38] = setAppState;
288
- $[39] = skipSettingsWrite;
289
- $[40] = t14;
290
- }
291
- else {
292
- t14 = $[40];
293
- }
294
- const handleSelect = t14;
295
- let t15;
296
- if ($[41] === Symbol.for("react.memo_cache_sentinel")) {
297
- t15 = _jsx(Text, { color: "remember", bold: true, children: "Seleccionar modelo" });
298
- $[41] = t15;
299
- }
300
- else {
301
- t15 = $[41];
302
- }
303
- const t16 = headerText ?? "Cambia entre modelos. Se aplica a esta sesion y a futuras sesiones de Context Code. Para otros nombres de modelo, usa --model.";
304
- let t17;
305
- if ($[42] !== t16) {
306
- t17 = _jsx(Text, { dimColor: true, children: t16 });
307
- $[42] = t16;
308
- $[43] = t17;
309
- }
310
- else {
311
- t17 = $[43];
312
- }
313
- let t18;
314
- if ($[44] !== sessionModel) {
315
- t18 = sessionModel && _jsxs(Text, { dimColor: true, children: ["Usando ", modelDisplayString(sessionModel), " en esta sesion (definido por el modo plan). Al elegir otro modelo se deshace este ajuste."] });
316
- $[44] = sessionModel;
317
- $[45] = t18;
318
- }
319
- else {
320
- t18 = $[45];
321
- }
322
- let t19;
323
- if ($[46] !== t17 || $[47] !== t18) {
324
- t19 = _jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [t15, t17, t18] });
325
- $[46] = t17;
326
- $[47] = t18;
327
- $[48] = t19;
328
- }
329
- else {
330
- t19 = $[48];
331
- }
332
- const t20 = onCancel ?? _temp4;
333
- let t21;
334
- if ($[49] !== handleFocus || $[50] !== handleSelect || $[51] !== initialFocusValue || $[52] !== initialValue || $[53] !== selectOptions || $[54] !== t20 || $[55] !== visibleCount) {
335
- t21 = _jsx(Box, { flexDirection: "column", children: _jsx(Select, { defaultValue: initialValue, defaultFocusValue: initialFocusValue, options: selectOptions, onChange: handleSelect, onFocus: handleFocus, onCancel: t20, visibleOptionCount: visibleCount }) });
336
- $[49] = handleFocus;
337
- $[50] = handleSelect;
338
- $[51] = initialFocusValue;
339
- $[52] = initialValue;
340
- $[53] = selectOptions;
341
- $[54] = t20;
342
- $[55] = visibleCount;
343
- $[56] = t21;
344
- }
345
- else {
346
- t21 = $[56];
347
- }
348
- let t22;
349
- if ($[57] !== hiddenCount) {
350
- t22 = hiddenCount > 0 && _jsx(Box, { paddingLeft: 3, children: _jsxs(Text, { dimColor: true, children: ["y ", hiddenCount, " m\u00E1s\u2026"] }) });
351
- $[57] = hiddenCount;
352
- $[58] = t22;
353
- }
354
- else {
355
- t22 = $[58];
356
- }
357
- let t23;
358
- if ($[59] !== t21 || $[60] !== t22) {
359
- t23 = _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [t21, t22] });
360
- $[59] = t21;
361
- $[60] = t22;
362
- $[61] = t23;
363
- }
364
- else {
365
- t23 = $[61];
366
- }
367
- let t24;
368
- if ($[62] !== displayEffort || $[63] !== focusedDefaultEffort || $[64] !== focusedModelName || $[65] !== focusedSupportsEffort) {
369
- t24 = _jsx(Box, { marginBottom: 1, flexDirection: "column", children: focusedSupportsEffort ? _jsxs(Text, { dimColor: true, children: [_jsx(EffortLevelIndicator, { effort: displayEffort }), " ", capitalize(displayEffort === 'low' ? 'bajo' : displayEffort === 'medium' ? 'medio' : displayEffort === 'high' ? 'alto' : 'máximo'), " esfuerzo", displayEffort === focusedDefaultEffort ? " (predeterminado)" : "", " ", _jsx(Text, { color: "subtle", children: "\u2190 \u2192 para ajustar" })] }) : _jsxs(Text, { color: "subtle", children: [_jsx(EffortLevelIndicator, { effort: undefined }), " Esfuerzo no soportado", focusedModelName ? ` para ${focusedModelName}` : ""] }) });
370
- $[62] = displayEffort;
371
- $[63] = focusedDefaultEffort;
372
- $[64] = focusedModelName;
373
- $[65] = focusedSupportsEffort;
374
- $[66] = t24;
375
- }
376
- else {
377
- t24 = $[66];
378
- }
379
- let t25;
380
- if ($[67] !== showFastModeNotice) {
381
- t25 = isFastModeEnabled() ? showFastModeNotice ? _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["El modo r\u00E1pido est\u00E1 ", _jsx(Text, { bold: true, children: "ACTIVADO" }), " y disponible solo con", " ", FAST_MODE_MODEL_DISPLAY, " (/fast). Cambiar a otros modelos desactivar\u00E1 el modo r\u00E1pido."] }) }) : isFastModeAvailable() && !isFastModeCooldown() ? _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["Usa ", _jsx(Text, { bold: true, children: "/fast" }), " para activar el modo r\u00E1pido (solo ", FAST_MODE_MODEL_DISPLAY, ")."] }) }) : null : null;
382
- $[67] = showFastModeNotice;
383
- $[68] = t25;
384
- }
385
- else {
386
- t25 = $[68];
387
- }
388
- let t26;
389
- if ($[69] !== t19 || $[70] !== t23 || $[71] !== t24 || $[72] !== t25) {
390
- t26 = _jsxs(Box, { flexDirection: "column", children: [t19, t23, t24, t25] });
391
- $[69] = t19;
392
- $[70] = t23;
393
- $[71] = t24;
394
- $[72] = t25;
395
- $[73] = t26;
396
- }
397
- else {
398
- t26 = $[73];
399
- }
400
- let t27;
401
- if ($[74] !== exitState || $[75] !== isStandaloneCommand) {
402
- t27 = isStandaloneCommand && _jsx(Text, { dimColor: true, italic: true, children: exitState.pending ? _jsxs(_Fragment, { children: ["Presiona ", exitState.keyName, " de nuevo para salir"] }) : _jsxs(Byline, { children: [_jsx(KeyboardShortcutHint, { shortcut: "Enter", action: "confirmar" }), _jsx(ConfigurableShortcutHint, { action: "select:cancel", context: "Seleccionar", fallback: "Esc", description: "salir" })] }) });
403
- $[74] = exitState;
404
- $[75] = isStandaloneCommand;
405
- $[76] = t27;
406
- }
407
- else {
408
- t27 = $[76];
409
- }
410
- let t28;
411
- if ($[77] !== t26 || $[78] !== t27) {
412
- t28 = _jsxs(Box, { flexDirection: "column", children: [t26, t27] });
413
- $[77] = t26;
414
- $[78] = t27;
415
- $[79] = t28;
416
- }
417
- else {
418
- t28 = $[79];
419
- }
420
- const content = t28;
421
- if (!isStandaloneCommand) {
422
- return content;
423
- }
424
- let t29;
425
- if ($[80] !== content) {
426
- t29 = _jsx(Pane, { color: "permission", children: content });
427
- $[80] = content;
428
- $[81] = t29;
429
- }
430
- else {
431
- t29 = $[81];
432
- }
433
- return t29;
434
- }
435
- function _temp4() { }
436
- function _temp3(opt_0) {
437
- return {
438
- ...opt_0,
439
- value: opt_0.value === null ? NO_PREFERENCE : opt_0.value
277
+ setAppState(prev => ({
278
+ ...prev,
279
+ effortValue: effortLevel,
280
+ }));
281
+ }
282
+ const selectedEffort = hasToggledEffort && focusedModel && modelSupportsEffort(focusedModel)
283
+ ? effort
284
+ : undefined;
285
+ const recent = [value, ...pickerState.recent.filter(item => item !== value)].slice(0, 15);
286
+ const nextState = { ...pickerState, recent };
287
+ setPickerState(nextState);
288
+ writePickerState(nextState);
289
+ onSelect(asModelValue(value), selectedEffort);
440
290
  };
441
- }
442
- function _temp2(s_0) {
443
- return s_0.effortValue;
444
- }
445
- function _temp(s) {
446
- return isFastModeEnabled() ? s.fastMode : false;
447
- }
448
- function resolveOptionModel(value) {
449
- if (!value)
450
- return undefined;
451
- return value === NO_PREFERENCE ? getDefaultMainLoopModel() : parseUserSpecifiedModel(value);
452
- }
453
- function EffortLevelIndicator(t0) {
454
- const $ = _c(5);
455
- const { effort } = t0;
456
- const t1 = effort ? "claude" : "subtle";
457
- const t2 = effort ?? "low";
458
- let t3;
459
- if ($[0] !== t2) {
460
- t3 = effortLevelToSymbol(t2);
461
- $[0] = t2;
462
- $[1] = t3;
463
- }
464
- else {
465
- t3 = $[1];
466
- }
467
- let t4;
468
- if ($[2] !== t1 || $[3] !== t3) {
469
- t4 = _jsx(Text, { color: t1, children: t3 });
470
- $[2] = t1;
471
- $[3] = t3;
472
- $[4] = t4;
473
- }
474
- else {
475
- t4 = $[4];
476
- }
477
- return t4;
478
- }
479
- function cycleEffortLevel(current, direction, includeMax) {
480
- const levels = includeMax ? ['low', 'medium', 'high', 'max'] : ['low', 'medium', 'high'];
481
- // If the current level isn't in the cycle (e.g. 'max' after switching to a
482
- // non-Opus model), clamp to 'high'.
483
- const idx = levels.indexOf(current);
484
- const currentIndex = idx !== -1 ? idx : levels.indexOf('high');
485
- if (direction === 'right') {
486
- return levels[(currentIndex + 1) % levels.length];
487
- }
488
- else {
489
- return levels[(currentIndex - 1 + levels.length) % levels.length];
490
- }
491
- }
492
- function getDefaultEffortLevelForOption(value) {
493
- const resolved = resolveOptionModel(value) ?? getDefaultMainLoopModel();
494
- const defaultValue = getDefaultEffortForModel(resolved);
495
- return defaultValue !== undefined ? convertEffortValueToLevel(defaultValue) : 'high';
291
+ const favoriteHint = focusedValue && !isHeaderValue(focusedValue) && focusedValue !== NO_PREFERENCE
292
+ ? pickerState.favorites.includes(focusedValue)
293
+ ? 'Unfavorite'
294
+ : 'Favorite'
295
+ : 'Favorite';
296
+ const content = (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [_jsx(Text, { color: "remember", bold: true, children: "Seleccionar modelo" }), _jsx(Text, { dimColor: true, children: headerText ??
297
+ 'Cambia entre modelos. Se aplica a esta sesion y a futuras sesiones de Context Code. Para otros nombres de modelo, usa --model.' }), sessionModel && (_jsxs(Text, { dimColor: true, children: ["Usando ", modelDisplayString(sessionModel), " en esta sesion (definido por el modo plan). Al elegir otro modelo se deshace este ajuste."] }))] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Select, { defaultValue: initialValue, defaultFocusValue: initialFocusValue, options: groupedOptions, onChange: handleSelect, onFocus: handleFocus, onCancel: onCancel ?? (() => { }), visibleOptionCount: visibleCount, hideIndexes: true, layout: "compact-vertical" }), hiddenCount > 0 && (_jsx(Box, { paddingLeft: 3, children: _jsxs(Text, { dimColor: true, children: ["y ", hiddenCount, " m\u00E1s\u2026"] }) }))] }), _jsx(Box, { marginBottom: 1, flexDirection: "column", children: focusedSupportsEffort ? (_jsxs(Text, { dimColor: true, children: [_jsx(EffortLevelIndicator, { effort: displayEffort }), ' ', capitalize(displayEffort === 'low'
298
+ ? 'bajo'
299
+ : displayEffort === 'medium'
300
+ ? 'medio'
301
+ : displayEffort === 'high'
302
+ ? 'alto'
303
+ : 'máximo'), ' ', "esfuerzo", displayEffort === focusedDefaultEffort ? ' (predeterminado)' : '', ' ', _jsx(Text, { color: "subtle", children: "\u2190 \u2192 para ajustar" })] })) : (_jsxs(Text, { color: "subtle", children: [_jsx(EffortLevelIndicator, { effort: undefined }), " Esfuerzo no soportado", focusedModelName ? ` para ${String(focusedModelName)}` : ''] })) }), isFastModeEnabled() ? (showFastModeNotice ? (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["El modo r\u00E1pido est\u00E1 ", _jsx(Text, { bold: true, children: "ACTIVADO" }), " y disponible solo con", ' ', FAST_MODE_MODEL_DISPLAY, " (/fast). Cambiar a otros modelos desactivar\u00E1 el modo r\u00E1pido."] }) })) : isFastModeAvailable() && !isFastModeCooldown() ? (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["Usa ", _jsx(Text, { bold: true, children: "/fast" }), " para activar el modo r\u00E1pido (solo", ' ', FAST_MODE_MODEL_DISPLAY, ")."] }) })) : null) : null, isStandaloneCommand && (_jsx(Text, { dimColor: true, italic: true, children: exitState.pending ? (_jsxs(_Fragment, { children: ["Presiona ", exitState.keyName, " de nuevo para salir"] })) : (_jsxs(Byline, { children: [_jsx(KeyboardShortcutHint, { shortcut: "Enter", action: "confirmar" }), _jsx(KeyboardShortcutHint, { shortcut: "Ctrl+F", action: favoriteHint }), _jsx(KeyboardShortcutHint, { shortcut: "Ctrl+A", action: "Provider" }), _jsx(ConfigurableShortcutHint, { action: "select:cancel", context: "Seleccionar", fallback: "Esc", description: "salir" })] })) }))] }));
304
+ if (!isStandaloneCommand)
305
+ return content;
306
+ return _jsx(Pane, { color: "permission", children: content });
496
307
  }