@askdkc/dsh-cli 0.12.0 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +12 -9
  2. package/lib/types/components/ModelDialogLayer.d.ts +12 -0
  3. package/lib/types/components/ModelDialogLayer.d.ts.map +1 -0
  4. package/lib/types/components/ModelDialogLayer.js +39 -0
  5. package/lib/types/components/ModelPicker.d.ts +12 -41
  6. package/lib/types/components/ModelPicker.d.ts.map +1 -1
  7. package/lib/types/components/ModelPicker.js +15 -44
  8. package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
  9. package/lib/types/components/design-system/ListItem.js +1 -1
  10. package/lib/types/dsh-adapter/channel/command-completions.d.ts.map +1 -1
  11. package/lib/types/dsh-adapter/channel/command-completions.js +11 -2
  12. package/lib/types/dsh-adapter/contract.d.ts +4 -3
  13. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  14. package/lib/types/dsh-adapter/contract.js +6 -3
  15. package/lib/types/i18n.d.ts +18 -26
  16. package/lib/types/i18n.d.ts.map +1 -1
  17. package/lib/types/i18n.js +5 -7
  18. package/lib/types/modelFavorites.d.ts +8 -0
  19. package/lib/types/modelFavorites.d.ts.map +1 -0
  20. package/lib/types/modelFavorites.js +59 -0
  21. package/lib/types/modelGroups.d.ts +3 -6
  22. package/lib/types/modelGroups.d.ts.map +1 -1
  23. package/lib/types/modelGroups.js +4 -7
  24. package/lib/types/modelPickerRows.d.ts +19 -0
  25. package/lib/types/modelPickerRows.d.ts.map +1 -0
  26. package/lib/types/modelPickerRows.js +54 -0
  27. package/lib/types/screens/Chat.d.ts.map +1 -1
  28. package/lib/types/screens/Chat.js +186 -237
  29. package/lib/types/screens/chatOverlay.d.ts.map +1 -1
  30. package/lib/types/screens/chatOverlay.js +2 -0
  31. package/node_modules/@askdkc/dsh-auth/package.json +10 -10
  32. package/node_modules/dsh-working-activity/package.json +9 -9
  33. package/package.json +92 -92
@@ -18,8 +18,10 @@ import { homeDir } from '../utils/paths.js';
18
18
  import { execFileNoThrow } from '../utils/execFileNoThrow.js';
19
19
  import { cleanRenderText, cleanScalarText } from '../dsh-adapter/sanitize.js';
20
20
  import { nextModelQueryBoundary, previousModelQueryBoundary } from './modelSearchInput.js';
21
- import { deriveModelGroups, filterModels, modelPickerFlatIndex, modelPickerLanding, recentCatalogModels, RECENTS_GROUP_PROVIDER, } from '../modelGroups.js';
22
21
  import { readModelRecents, recordModelUse } from '../modelRecents.js';
22
+ import { readModelFavorites, toggleModelFavorite } from '../modelFavorites.js';
23
+ import { modelPickerRows, focusedModelRow, moveModelFocus } from '../modelPickerRows.js';
24
+ import { ModelDialogLayer } from '../components/ModelDialogLayer.js';
23
25
  import { TuiDialogStore } from '../dsh-adapter/dialogs.js';
24
26
  import { TuiStatusStore } from '../dsh-adapter/status.js';
25
27
  import { ActivityStore, useActivity } from '../dsh-adapter/activity-store.js';
@@ -344,48 +346,27 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
344
346
  const [models, setModels] = React.useState([]);
345
347
  const [modelCatalogStatus, setModelCatalogStatus] = React.useState('loading');
346
348
  const modelRequestRef = React.useRef(0);
347
- /** Provider display identities for the /model group level; refreshed alongside `models`. */
348
349
  const [providerInfos, setProviderInfos] = React.useState([]);
349
- /** /model 最近使用分组:成功切换即记录(去重置顶,上限 10),重启保留。 */
350
350
  const [modelRecents, setModelRecents] = React.useState(() => readModelRecents());
351
- /** Optional provider-group drill-down; undefined in the default flat list. */
352
- const [modelGroup, setModelGroup] = React.useState(undefined);
353
- /** Open /model on the complete, immediately searchable model list. */
354
- const [modelPickerFlat, setModelPickerFlat] = React.useState(true);
355
- /** Group rows over the current catalog, first-appearance (registry) order,
356
- * with the pinned recents pseudo-group first when any entry is catalogued. */
357
- const modelGroups = React.useMemo(() => deriveModelGroups(models, providerInfos, modelRecents), [models, providerInfos, modelRecents]);
358
- /** The drilled-in group, but only while it still exists in the catalog. */
359
- const activeModelGroup = modelGroup !== undefined && modelGroups.some(group => group.provider === modelGroup)
360
- ? modelGroup
361
- : undefined;
362
- const groupModels = React.useMemo(() => {
363
- if (activeModelGroup === undefined)
364
- return [];
365
- if (activeModelGroup === RECENTS_GROUP_PROVIDER)
366
- return recentCatalogModels(modelRecents, models);
367
- return models.filter(model => model.provider === activeModelGroup);
368
- }, [models, modelRecents, activeModelGroup]);
351
+ const [modelFavorites, setModelFavorites] = React.useState(() => readModelFavorites());
352
+ const [modelSwitching, setModelSwitching] = React.useState(false);
353
+ const [modelFallback, setModelFallback] = React.useState(false);
354
+ const modelSwitchingRef = React.useRef(false);
369
355
  const modelQuery = overlay.kind === 'model' ? (overlay.query ?? '') : '';
370
- const modelSearchActive = modelQuery.trim() !== '';
371
- const visibleModelRows = React.useMemo(() => filterModels(activeModelGroup === undefined ? models : groupModels, modelQuery, providerInfos), [activeModelGroup, groupModels, models, modelQuery, providerInfos]);
372
- const visibleModelGroups = activeModelGroup === undefined && !modelSearchActive && !modelPickerFlat ? modelGroups : [];
373
- const modelRowsAreGroups = activeModelGroup === undefined && !modelSearchActive && !modelPickerFlat;
374
- const modelRowCount = modelRowsAreGroups ? visibleModelGroups.length : visibleModelRows.length;
375
- const modelFocus = overlay.kind === 'model'
376
- ? Math.max(0, Math.min(overlay.index, modelRowCount - 1))
377
- : 0;
356
+ const modelRows = React.useMemo(() => modelPickerRows(models, providerInfos, modelFavorites, modelRecents, modelQuery), [models, providerInfos, modelFavorites, modelRecents, modelQuery]);
357
+ const modelFocus = overlay.kind === 'model' ? Math.max(0, Math.min(overlay.index, modelRows.length - 1)) : 0;
358
+ const modelFocused = focusedModelRow(modelRows, modelFocus);
359
+ const modelFocusIndexRef = React.useRef(null);
360
+ React.useEffect(() => {
361
+ modelFocusIndexRef.current = overlay.kind === 'model' ? { query: modelQuery, index: modelFocus } : null;
362
+ }, [overlay, modelQuery, modelFocus]);
378
363
  const modelFocusedRef = React.useRef(null);
379
364
  React.useEffect(() => {
380
- modelFocusedRef.current = overlay.kind === 'model' ? {
381
- query: modelQuery,
382
- group: activeModelGroup,
383
- rowsAreGroups: modelRowsAreGroups,
384
- provider: modelRowsAreGroups ? undefined : visibleModelRows[modelFocus]?.provider,
385
- id: modelRowsAreGroups ? undefined : visibleModelRows[modelFocus]?.id,
386
- groupKey: modelRowsAreGroups ? visibleModelGroups[modelFocus]?.provider : undefined,
365
+ modelFocusedRef.current = overlay.kind === 'model' && modelFocused ? {
366
+ query: modelQuery, section: modelFocused.section,
367
+ provider: modelFocused.model.provider, id: modelFocused.model.id,
387
368
  } : null;
388
- }, [overlay, modelQuery, activeModelGroup, modelRowsAreGroups, visibleModelRows, visibleModelGroups, modelFocus]);
369
+ }, [overlay, modelQuery, modelFocused]);
389
370
  React.useEffect(() => {
390
371
  const subscribe = channel.providerSetup?.()?.oauth?.onCredentialChange;
391
372
  if (subscribe === undefined)
@@ -393,42 +374,27 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
393
374
  return subscribe(() => {
394
375
  channel.invalidateModelCompletion();
395
376
  const request = ++modelRequestRef.current;
377
+ const binding = channel.agentBindingGeneration;
396
378
  void channel.listModels().then(list => {
397
- if (request !== modelRequestRef.current)
379
+ if (request !== modelRequestRef.current || binding !== channel.agentBindingGeneration)
398
380
  return;
399
381
  const focused = modelFocusedRef.current;
400
382
  if (focused !== null) {
401
- const freshGroups = deriveModelGroups(list, providerInfos, modelRecents);
402
- if (focused.group !== undefined && !freshGroups.some(group => group.provider === focused.group)) {
403
- setModelGroup(undefined);
404
- dispatchOverlay({ type: 'model-edit', query: '', cursor: 0 });
405
- dispatchOverlay({ type: 'set-index', kind: 'model', index: 0 });
406
- }
407
- else {
408
- const scope = focused.group === undefined ? list
409
- : focused.group === RECENTS_GROUP_PROVIDER ? recentCatalogModels(modelRecents, list)
410
- : list.filter(model => model.provider === focused.group);
411
- const rows = filterModels(scope, focused.query, providerInfos);
412
- const index = focused.rowsAreGroups
413
- ? freshGroups.findIndex(group => group.provider === focused.groupKey)
414
- : rows.findIndex(model => model.provider === focused.provider && model.id === focused.id);
415
- dispatchOverlay({ type: 'set-index', kind: 'model', index: Math.max(0, index) });
416
- }
383
+ const rows = modelPickerRows(list, providerInfos, modelFavorites, modelRecents, focused.query);
384
+ const same = rows.findIndex(row => row.kind === 'model' && row.section === focused.section
385
+ && row.model.provider === focused.provider && row.model.id === focused.id);
386
+ const index = same >= 0 ? same : rows.findIndex(row => row.kind === 'model'
387
+ && row.model.provider === focused.provider && row.model.id === focused.id);
388
+ dispatchOverlay({ type: 'set-index', kind: 'model', index: index >= 0 ? index : moveModelFocus(rows, -1, 1) });
417
389
  }
418
390
  setModels(list);
419
391
  setModelCatalogStatus('ready');
420
- }).catch(() => {
421
- if (request === modelRequestRef.current) {
422
- setModelCatalogStatus('error');
423
- channel.notify(t('picker-model-error'), { color: 'warning' });
424
- }
425
- });
426
- void channel.listProviders().then(list => {
427
- if (request === modelRequestRef.current)
428
- setProviderInfos(list);
429
- }).catch(() => undefined);
392
+ }).catch(() => { if (request === modelRequestRef.current && binding === channel.agentBindingGeneration)
393
+ setModelCatalogStatus('error'); });
394
+ void channel.listProviders().then(list => { if (request === modelRequestRef.current && binding === channel.agentBindingGeneration)
395
+ setProviderInfos(list); }).catch(() => undefined);
430
396
  });
431
- }, [channel, providerInfos, modelRecents]);
397
+ }, [channel, providerInfos, modelFavorites, modelRecents]);
432
398
  /** Switch + record: every successful switch feeds the /model recents group
433
399
  * (picker Enter/click, `/model provider/id`, the wizard's live switch,
434
400
  * and /reload's applied model all ride this one path). */
@@ -444,6 +410,70 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
444
410
  return ok;
445
411
  });
446
412
  };
413
+ const refreshModelPicker = (initialQuery) => {
414
+ const request = ++modelRequestRef.current;
415
+ const binding = channel.agentBindingGeneration;
416
+ setModelCatalogStatus('loading');
417
+ void channel.listModels().then(list => {
418
+ if (request !== modelRequestRef.current || binding !== channel.agentBindingGeneration)
419
+ return;
420
+ const focused = modelFocusedRef.current;
421
+ const rows = modelPickerRows(list, providerInfos, modelFavorites, modelRecents, focused?.query ?? initialQuery ?? '');
422
+ const same = rows.findIndex(row => row.kind === 'model' && row.model.provider === (focused?.provider ?? channel.provider)
423
+ && row.model.id === (focused?.id ?? channel.model) && (!focused || row.section === focused.section));
424
+ const index = initialQuery?.trim() ? -1 : same >= 0 ? same : rows.findIndex(row => row.kind === 'model'
425
+ && row.model.provider === (focused?.provider ?? channel.provider) && row.model.id === (focused?.id ?? channel.model));
426
+ dispatchOverlay({ type: 'set-index', kind: 'model', index: index >= 0 ? index : moveModelFocus(rows, -1, 1) });
427
+ setModels(list);
428
+ setModelCatalogStatus('ready');
429
+ }).catch(() => {
430
+ if (request === modelRequestRef.current && binding === channel.agentBindingGeneration) {
431
+ setModels([]);
432
+ setModelCatalogStatus('error');
433
+ }
434
+ });
435
+ void channel.listProviders().then(list => { if (request === modelRequestRef.current && binding === channel.agentBindingGeneration)
436
+ setProviderInfos(list); }).catch(() => undefined);
437
+ };
438
+ const openModelPicker = (query, catalog) => {
439
+ setModelFallback(false);
440
+ modelFocusedRef.current = null;
441
+ modelFocusIndexRef.current = null;
442
+ setModels(catalog ?? []);
443
+ setModelCatalogStatus(catalog ? 'ready' : 'loading');
444
+ const rows = modelPickerRows(catalog ?? [], providerInfos, modelFavorites, modelRecents, query);
445
+ const current = query ? -1 : rows.findIndex(row => row.kind === 'model'
446
+ && row.model.provider === channel.provider && row.model.id === channel.model);
447
+ dispatchOverlay({ type: 'open', overlay: { kind: 'model', index: current >= 0 ? current : moveModelFocus(rows, -1, 1), query, cursor: query.length } });
448
+ if (!catalog)
449
+ refreshModelPicker(query);
450
+ else {
451
+ const request = ++modelRequestRef.current;
452
+ const binding = channel.agentBindingGeneration;
453
+ void channel.listProviders().then(list => {
454
+ if (request === modelRequestRef.current && binding === channel.agentBindingGeneration)
455
+ setProviderInfos(list);
456
+ }).catch(() => undefined);
457
+ }
458
+ };
459
+ const pickModel = async (model) => {
460
+ if (modelSwitchingRef.current)
461
+ return;
462
+ modelSwitchingRef.current = true;
463
+ setModelSwitching(true);
464
+ try {
465
+ const ok = await switchModelRecorded(model.provider, model.id, model.name);
466
+ if (ok)
467
+ dispatchOverlay({ type: 'close-if', kind: 'model' });
468
+ }
469
+ catch (error) {
470
+ channel.notify(error instanceof Error ? error.message : String(error), { color: 'error' });
471
+ }
472
+ finally {
473
+ modelSwitchingRef.current = false;
474
+ setModelSwitching(false);
475
+ }
476
+ };
447
477
  /** `/skills` 技能目录(issue #204):null = 注册表快照在途。 */
448
478
  const [skillsList, setSkillsList] = React.useState(null);
449
479
  /**
@@ -1814,89 +1844,27 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1814
1844
  setHelpOpen(true);
1815
1845
  return true;
1816
1846
  case 'model': {
1817
- // `/model <provider/model>` switches directly (same live-fork path
1818
- // as the picker's Enter), bare `/model` opens the picker.
1819
- const parts = rawInput.trim().split(/\s+/).filter(Boolean);
1820
- if (parts.length > 0) {
1821
- setHelpOpen(false);
1822
- const spec = parts[0];
1823
- const slash = spec.indexOf('/');
1824
- const provider = slash >= 0 ? spec.slice(0, slash) : undefined;
1825
- const id = slash >= 0 ? spec.slice(slash + 1) : spec;
1826
- if (provider === undefined || id.length === 0 || provider.length === 0) {
1827
- channel.notify(t('model-usage'), { color: 'warning' });
1828
- return true;
1829
- }
1830
- void channel.listModels().then((list) => {
1831
- const model = list.find(m => m.provider === provider && m.id === id);
1832
- if (model === undefined) {
1833
- channel.notify(t('model-unknown', { spec }), { color: 'error', timeoutMs: 8000 });
1847
+ setHelpOpen(false);
1848
+ const query = rawInput.trim();
1849
+ const binding = channel.agentBindingGeneration;
1850
+ // A complete advertised route keeps the direct-switch contract.
1851
+ if (query && !/\s/u.test(query)) {
1852
+ void channel.listModels().then(list => {
1853
+ if (binding !== channel.agentBindingGeneration)
1854
+ return;
1855
+ const model = list.find(item => `${item.provider}/${item.id}` === query);
1856
+ if (model) {
1857
+ void switchModelRecorded(model.provider, model.id, model.name);
1834
1858
  return;
1835
1859
  }
1836
- void switchModelRecorded(provider, id, model.name);
1860
+ openModelPicker(query, list);
1861
+ }).catch(() => {
1862
+ if (binding === channel.agentBindingGeneration)
1863
+ openModelPicker(query);
1837
1864
  });
1838
1865
  return true;
1839
1866
  }
1840
- setHelpOpen(false);
1841
- // Opens over the cached catalog (empty cache shows the loading
1842
- // pane); the fresh list lands with the authoritative focus, and the
1843
- // kind-guarded set-index cannot re-focus a picker the user left.
1844
- // Seed-on-open: the model in use IS a use — recording it here means
1845
- // the recents group exists before the first post-update switch, and
1846
- // switching A→B keeps A in the list (the file records what was
1847
- // used, not only switches made after the file appeared).
1848
- let recentsNow = modelRecents;
1849
- if (channel.provider !== '' && channel.model !== ''
1850
- && !recentsNow.some(ref => ref.provider === channel.provider && ref.id === channel.model)) {
1851
- recentsNow = recordModelUse({ provider: channel.provider, id: channel.model });
1852
- setModelRecents(recentsNow);
1853
- }
1854
- // Search-first landing: show every available model immediately and
1855
- // focus the current one. Tab still opens the provider groups.
1856
- {
1857
- setModelGroup(undefined);
1858
- setModelPickerFlat(true);
1859
- dispatchOverlay({ type: 'open', overlay: { kind: 'model', index: modelPickerFlatIndex(models, channel.provider, channel.model), query: '', cursor: 0 } });
1860
- }
1861
- const modelRequest = ++modelRequestRef.current;
1862
- setModelCatalogStatus('loading');
1863
- void channel.listModels().then((list) => {
1864
- if (modelRequest !== modelRequestRef.current)
1865
- return;
1866
- const focused = modelFocusedRef.current;
1867
- if (models.length === 0 && (focused === null || (!focused.rowsAreGroups && focused.group === undefined && focused.query === ''))) {
1868
- dispatchOverlay({ type: 'set-index', kind: 'model', index: modelPickerFlatIndex(list, channel.provider, channel.model) });
1869
- }
1870
- else if (focused !== null) {
1871
- const freshGroups = deriveModelGroups(list, providerInfos, recentsNow);
1872
- if (focused.group !== undefined && !freshGroups.some(group => group.provider === focused.group)) {
1873
- setModelGroup(undefined);
1874
- dispatchOverlay({ type: 'model-edit', query: '', cursor: 0 });
1875
- dispatchOverlay({ type: 'set-index', kind: 'model', index: 0 });
1876
- }
1877
- else {
1878
- const scope = focused.group === undefined ? list
1879
- : focused.group === RECENTS_GROUP_PROVIDER ? recentCatalogModels(recentsNow, list)
1880
- : list.filter(model => model.provider === focused.group);
1881
- const rows = filterModels(scope, focused.query, providerInfos);
1882
- const index = focused.rowsAreGroups
1883
- ? freshGroups.findIndex(group => group.provider === focused.groupKey)
1884
- : rows.findIndex(model => model.provider === focused.provider && model.id === focused.id);
1885
- dispatchOverlay({ type: 'set-index', kind: 'model', index: Math.max(0, index) });
1886
- }
1887
- }
1888
- setModels(list);
1889
- setModelCatalogStatus('ready');
1890
- }).catch(() => {
1891
- if (modelRequest === modelRequestRef.current) {
1892
- setModelCatalogStatus('error');
1893
- channel.notify(t('picker-model-error'), { color: 'warning' });
1894
- }
1895
- });
1896
- void channel.listProviders().then(list => {
1897
- if (modelRequest === modelRequestRef.current)
1898
- setProviderInfos(list);
1899
- }).catch(() => undefined);
1867
+ openModelPicker(query);
1900
1868
  return true;
1901
1869
  }
1902
1870
  case 'skills': {
@@ -3255,88 +3223,84 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3255
3223
  }
3256
3224
  if (overlay.kind === 'model') {
3257
3225
  event.stopImmediatePropagation();
3258
- // Search-first model list; Tab toggles the optional provider groups.
3259
- const rowCount = modelRowCount;
3260
3226
  const query = overlay.query ?? '';
3261
3227
  const cursor = overlay.cursor ?? query.length;
3262
- const editModelQuery = (value, nextCursor) => dispatchOverlay({ type: 'model-edit', query: value, cursor: nextCursor });
3263
- if (key.tab && !key.shift && modelGroups.length > 1) {
3264
- if (modelPickerFlat) {
3265
- const landing = modelPickerLanding(models, channel.provider, channel.model, modelRecents);
3266
- setModelPickerFlat(false);
3267
- setModelGroup(landing.group);
3268
- dispatchOverlay({ type: 'model-edit', query: '', cursor: 0 });
3269
- dispatchOverlay({ type: 'set-index', kind: 'model', index: landing.index });
3228
+ const focusIndex = modelFocusIndexRef.current?.query === query ? modelFocusIndexRef.current.index : modelFocus;
3229
+ const focusedRow = focusedModelRow(modelRows, focusIndex);
3230
+ const edit = (value, nextCursor) => {
3231
+ dispatchOverlay({ type: 'model-edit', query: value, cursor: nextCursor });
3232
+ if (value !== query) {
3233
+ const rows = modelPickerRows(models, providerInfos, modelFavorites, modelRecents, value);
3234
+ const index = moveModelFocus(rows, -1, 1);
3235
+ modelFocusIndexRef.current = { query: value, index };
3236
+ dispatchOverlay({ type: 'set-index', kind: 'model', index });
3270
3237
  }
3238
+ };
3239
+ if (key.escape)
3240
+ dispatchOverlay({ type: 'close' });
3241
+ else if (key.ctrl && input === 'f' && focusedRow && !modelSwitchingRef.current) {
3242
+ const result = toggleModelFavorite(modelFavorites, focusedRow.model);
3243
+ setModelFavorites(result.favorites);
3244
+ const rows = modelPickerRows(models, providerInfos, result.favorites, modelRecents, query);
3245
+ const same = rows.findIndex(row => row.kind === 'model' && row.section === focusedRow.section
3246
+ && row.model.provider === focusedRow.model.provider && row.model.id === focusedRow.model.id);
3247
+ const route = rows.findIndex(row => row.kind === 'model' && row.model.provider === focusedRow.model.provider
3248
+ && row.model.id === focusedRow.model.id);
3249
+ const next = same >= 0 ? same : route >= 0 ? route : moveModelFocus(rows, -1, 1);
3250
+ modelFocusIndexRef.current = { query, index: next };
3251
+ dispatchOverlay({ type: 'set-index', kind: 'model', index: next });
3252
+ if (!result.saved)
3253
+ channel.notify(t('picker-model-favorite-save-error'), { color: 'warning' });
3254
+ }
3255
+ else if (key.ctrl && input === 'a' && !modelSwitchingRef.current) {
3256
+ if (!channel.providerSetup())
3257
+ channel.notify(t('provider-unavailable'), { color: 'warning' });
3271
3258
  else {
3272
- setModelPickerFlat(true);
3273
- setModelGroup(undefined);
3274
- dispatchOverlay({ type: 'model-edit', query: '', cursor: 0 });
3275
- dispatchOverlay({ type: 'set-index', kind: 'model', index: modelPickerFlatIndex(models, channel.provider, channel.model) });
3276
- }
3277
- }
3278
- else if (key.upArrow || key.downArrow) {
3279
- dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: rowCount });
3280
- }
3281
- else if (plainReturn) {
3282
- if (modelRowsAreGroups) {
3283
- const group = visibleModelGroups[modelFocus];
3284
- if (!group)
3285
- return;
3286
- setModelGroup(group.provider);
3287
- // The recents group opens on its most-recent entry; a provider
3288
- // group on its current model when it owns one, else its first row.
3289
- if (group.provider === RECENTS_GROUP_PROVIDER) {
3290
- dispatchOverlay({ type: 'set-index', kind: 'model', index: 0 });
3291
- return;
3292
- }
3293
- const landing = modelPickerLanding(models.filter(model => model.provider === group.provider), channel.provider, channel.model);
3294
- dispatchOverlay({ type: 'set-index', kind: 'model', index: landing.index });
3295
- return;
3296
- }
3297
- const model = visibleModelRows[modelFocus];
3298
- // oxlint-disable-next-line typescript/no-unnecessary-condition -- runtime guard: out-of-range index on an empty list
3299
- if (model) {
3300
- // Enter switches the live model right away: the conversation is
3301
- // forked at its end and continued with an agent routed to the new
3302
- // model (history replays unchanged) — and feeds the recents group.
3259
+ const binding = channel.agentBindingGeneration;
3260
+ let wizardBinding = null;
3303
3261
  dispatchOverlay({ type: 'close' });
3304
- void switchModelRecorded(model.provider, model.id, model.name);
3262
+ void runProviderWizard({ host: channel.providerSetup(), ask: (request, options) => questionStore.ask(request, options),
3263
+ notify: (message, options) => channel.notify(message, options), pushLocal: (title, lines) => channel.pushLocal(title, lines),
3264
+ working: () => channel.working, switchModel: async (provider, model) => {
3265
+ const changed = await switchModelRecorded(provider, model);
3266
+ if (changed)
3267
+ wizardBinding = channel.agentBindingGeneration;
3268
+ return changed;
3269
+ }, }).then(() => {
3270
+ if ((wizardBinding ?? binding) !== channel.agentBindingGeneration)
3271
+ return;
3272
+ channel.invalidateModelCompletion();
3273
+ openModelPicker(query);
3274
+ }).catch(() => channel.notify(t('provider-unavailable'), { color: 'warning' }));
3305
3275
  }
3306
3276
  }
3277
+ else if (key.ctrl && input === 'r')
3278
+ refreshModelPicker();
3279
+ else if (key.upArrow || key.downArrow || key.pageUp || key.pageDown) {
3280
+ const delta = key.upArrow ? -1 : key.downArrow ? 1 : key.pageUp ? -10 : 10;
3281
+ const next = moveModelFocus(modelRows, focusIndex, delta);
3282
+ modelFocusIndexRef.current = { query, index: next };
3283
+ dispatchOverlay({ type: 'set-index', kind: 'model', index: next });
3284
+ }
3285
+ else if (plainReturn && focusedRow && !modelSwitchingRef.current)
3286
+ void pickModel(focusedRow.model);
3307
3287
  else if (key.backspace && cursor > 0) {
3308
3288
  const start = previousModelQueryBoundary(query, cursor);
3309
- editModelQuery(query.slice(0, start) + query.slice(cursor), start);
3310
- }
3311
- else if (key.delete && cursor < query.length) {
3312
- editModelQuery(query.slice(0, cursor) + query.slice(nextModelQueryBoundary(query, cursor)), cursor);
3313
- }
3314
- else if (key.leftArrow && cursor > 0) {
3315
- editModelQuery(query, previousModelQueryBoundary(query, cursor));
3316
- }
3317
- else if (key.rightArrow && cursor < query.length) {
3318
- editModelQuery(query, nextModelQueryBoundary(query, cursor));
3319
- }
3320
- else if (key.home) {
3321
- editModelQuery(query, 0);
3322
- }
3323
- else if (key.end) {
3324
- editModelQuery(query, query.length);
3325
- }
3326
- else if (key.escape || (key.backspace && query === '')) {
3327
- if (activeModelGroup !== undefined && modelGroups.length > 1) {
3328
- setModelGroup(undefined);
3329
- const groupIndex = Math.max(0, modelGroups.findIndex(group => group.provider === activeModelGroup));
3330
- dispatchOverlay({ type: 'model-edit', query: '', cursor: 0 });
3331
- dispatchOverlay({ type: 'set-index', kind: 'model', index: groupIndex });
3332
- }
3333
- else {
3334
- dispatchOverlay({ type: 'close' });
3335
- }
3336
- }
3289
+ edit(query.slice(0, start) + query.slice(cursor), start);
3290
+ }
3291
+ else if (key.delete && cursor < query.length)
3292
+ edit(query.slice(0, cursor) + query.slice(nextModelQueryBoundary(query, cursor)), cursor);
3293
+ else if (key.leftArrow && cursor > 0)
3294
+ edit(query, previousModelQueryBoundary(query, cursor));
3295
+ else if (key.rightArrow && cursor < query.length)
3296
+ edit(query, nextModelQueryBoundary(query, cursor));
3297
+ else if (key.home)
3298
+ edit(query, 0);
3299
+ else if (key.end)
3300
+ edit(query, query.length);
3337
3301
  else if (input.length > 0 && !key.ctrl && !key.meta && !key.super && !key.tab) {
3338
3302
  const inserted = input.replace(/[\r\n\t]+/gu, ' ');
3339
- editModelQuery(query.slice(0, cursor) + inserted + query.slice(cursor), cursor + inserted.length);
3303
+ edit(query.slice(0, cursor) + inserted + query.slice(cursor), cursor + inserted.length);
3340
3304
  }
3341
3305
  return;
3342
3306
  }
@@ -4133,6 +4097,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4133
4097
  ? () => setPeekSuppressed(peekKey(activePreview.image, activePreview.title))
4134
4098
  : () => dispatchOverlay({ type: 'close-if', kind: 'image-preview' }), region: imagePreviewRegion }))
4135
4099
  : null;
4100
+ if (overlay.kind === 'model' && modelFallback && !fullscreen) {
4101
+ const height = Math.max(1, Math.min(26, terminalRows - 2));
4102
+ return _jsx(AlternateScreen, { children: _jsx(Box, { width: "100%", height: terminalRows, justifyContent: "center", alignItems: "center", children: _jsx(Box, { width: Math.max(1, Math.min(72, terminalColumns - 2)), height: height, backgroundColor: "toolCardBackground", opaque: true, overflow: "hidden", children: _jsx(ModelPicker, { rows: modelRows, focusIndex: modelFocus, currentModel: `${channel.provider}/${channel.model}`, favorites: modelFavorites, query: modelQuery, cursor: overlay.cursor ?? modelQuery.length, height: height, status: modelCatalogStatus, switching: modelSwitching, onPick: index => { const row = focusedModelRow(modelRows, index); if (row && !modelSwitchingRef.current)
4103
+ void pickModel(row.model); }, onWheelStep: step => dispatchOverlay({ type: 'set-index', kind: 'model', index: moveModelFocus(modelRows, modelFocus, step) }) }) }) }) });
4104
+ }
4136
4105
  return (_jsxs(Box, { ref: wakeTickRef, flexDirection: "column", flexGrow: 1, width: "100%", children: [!isSticky && anchorUserText && (_jsx(PinnedTurnHeader, { text: anchorUserText, onClick: () => {
4137
4106
  // Click snaps the pinned prompt to the viewport top. Jump by the
4138
4107
  // SAME content coordinate the
@@ -4254,28 +4223,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4254
4223
  return;
4255
4224
  dispatchOverlay({ type: 'set-index', kind: 'workspace-flow', index });
4256
4225
  runWorkspaceFlowAction(signal => choice.choose(signal));
4257
- } }) })), overlay.kind === 'model' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: modelRowsAreGroups ? (_jsx(ModelPicker, { groups: visibleModelGroups, query: modelQuery, cursor: overlay.cursor ?? modelQuery.length, emptyReason: modelCatalogStatus === 'loading' && models.length === 0 ? 'loading' : modelCatalogStatus === 'error' ? 'error' : 'empty', focusIndex: modelFocus, currentProvider: channel.provider, onPick: (index) => {
4258
- // 点击分组行 = 进入该组(与 Enter 同一条路径)
4259
- const group = visibleModelGroups[index];
4260
- if (!group)
4261
- return;
4262
- setModelGroup(group.provider);
4263
- if (group.provider === RECENTS_GROUP_PROVIDER) {
4264
- dispatchOverlay({ type: 'set-index', kind: 'model', index: 0 });
4265
- return;
4266
- }
4267
- const landing = modelPickerLanding(models.filter(model => model.provider === group.provider), channel.provider, channel.model);
4268
- dispatchOverlay({ type: 'set-index', kind: 'model', index: landing.index });
4269
- } })) : (_jsx(ModelPicker, { models: visibleModelRows, query: modelQuery, cursor: overlay.cursor ?? modelQuery.length, emptyReason: modelCatalogStatus === 'loading' && models.length === 0 ? 'loading' : modelCatalogStatus === 'error' ? 'error' : models.length === 0 ? 'empty' : 'no-match', groupLabel: activeModelGroup === RECENTS_GROUP_PROVIDER
4270
- ? t('picker-group-recent')
4271
- : modelGroups.find(group => group.provider === activeModelGroup)?.label, showBack: activeModelGroup !== undefined && modelGroups.length > 1, showGroups: modelPickerFlat && modelGroups.length > 1, showProviderPrefix: activeModelGroup === RECENTS_GROUP_PROVIDER || activeModelGroup === undefined, focusIndex: modelFocus, currentModel: `${channel.provider}/${channel.model}`, onPick: (index) => {
4272
- // 点击行 = 应用该行模型(与 Enter 同一条路径)
4273
- const model = visibleModelRows[index];
4274
- if (!model)
4275
- return;
4276
- dispatchOverlay({ type: 'close' });
4277
- void switchModelRecorded(model.provider, model.id, model.name);
4278
- } })) })), overlay.kind === 'migrate' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigratePicker, { rows: migrateRows ?? [], focusIndex: overlay.index, checked: migrateChecked, loading: migrateRows === null, onPick: (index) => {
4226
+ } }) })), overlay.kind === 'migrate' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigratePicker, { rows: migrateRows ?? [], focusIndex: overlay.index, checked: migrateChecked, loading: migrateRows === null, onPick: (index) => {
4279
4227
  const row = (migrateRows ?? [])[index];
4280
4228
  if (!row)
4281
4229
  return;
@@ -4373,7 +4321,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4373
4321
  const path = overlay.path;
4374
4322
  dispatchOverlay({ type: 'close' });
4375
4323
  runFileAction(index, path);
4376
- } }) })), overlay.kind === 'search' && _jsx(TranscriptSearch, { query: searchQuery, cursorOffset: searchCursor, count: searchCount, current: searchCurrent })] }))] })] }), _jsx(TooltipLayer, { invalidationKey: `${overlay.kind}:${dialogOverlayOpen}:${btw !== null}`, subscribeInvalidation: subscribeTooltipInvalidation }), _jsx(PromptEditorLayer, {}), promptEditorOpen && imagePreviewNode] }));
4324
+ } }) })), overlay.kind === 'search' && _jsx(TranscriptSearch, { query: searchQuery, cursorOffset: searchCursor, count: searchCount, current: searchCurrent })] }))] })] }), _jsx(TooltipLayer, { invalidationKey: `${overlay.kind}:${dialogOverlayOpen}:${btw !== null}`, subscribeInvalidation: subscribeTooltipInvalidation }), _jsx(PromptEditorLayer, {}), promptEditorOpen && imagePreviewNode, overlay.kind === 'model' && _jsx(ModelDialogLayer, { fullscreen: fullscreen, onClose: () => dispatchOverlay({ type: 'close' }), onInsufficientSpace: () => setModelFallback(true), children: size => _jsx(ModelPicker, { rows: modelRows, focusIndex: modelFocus, currentModel: `${channel.provider}/${channel.model}`, favorites: modelFavorites, query: modelQuery, cursor: overlay.cursor ?? modelQuery.length, height: size.rows, status: modelCatalogStatus, switching: modelSwitching, onPick: index => { const row = focusedModelRow(modelRows, index); if (row && !modelSwitchingRef.current)
4325
+ void pickModel(row.model); }, onWheelStep: step => dispatchOverlay({ type: 'set-index', kind: 'model', index: moveModelFocus(modelRows, modelFocus, step) }) }) })] }));
4377
4326
  }
4378
4327
  /**
4379
4328
  * The pinned prompt header shown above the ScrollBox while the user has
@@ -1 +1 @@
1
- {"version":3,"file":"chatOverlay.d.ts","sourceRoot":"","sources":["../../../src/screens/chatOverlay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chatOverlay.d.ts","sourceRoot":"","sources":["../../../src/screens/chatOverlay.ts"],"names":[],"mappings":"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"}
@@ -122,6 +122,8 @@ export function dialogOverlayVisible(overlay, gates) {
122
122
  // `<OverlayAbove>` wrapper for it would only churn the prompt area.
123
123
  case 'image-preview':
124
124
  return false;
125
+ case 'model':
126
+ return false;
125
127
  case 'workspace-picker':
126
128
  return gates.workspaceTargetCount > 0;
127
129
  case 'effort':
@@ -49,11 +49,11 @@
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@deepseek-ai/cordis": "^4.0.1",
52
- "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
53
- "@deepseek-ai/dsh-commands": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
54
- "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
55
- "@deepseek-ai/dsh-llm-pi-ai": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
56
- "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
52
+ "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1 || 0.2.0-rc.1 || 0.2.0-rc.2",
53
+ "@deepseek-ai/dsh-commands": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1 || 0.2.0-rc.1 || 0.2.0-rc.2",
54
+ "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1 || 0.2.0-rc.1 || 0.2.0-rc.2",
55
+ "@deepseek-ai/dsh-llm-pi-ai": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1 || 0.2.0-rc.1 || 0.2.0-rc.2",
56
+ "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1 || 0.2.0-rc.1 || 0.2.0-rc.2",
57
57
  "@deepseek-ai/schemastery": "^3.18.1"
58
58
  },
59
59
  "peerDependenciesMeta": {
@@ -63,11 +63,11 @@
63
63
  },
64
64
  "devDependencies": {
65
65
  "@deepseek-ai/cordis": "^4.0.1",
66
- "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
67
- "@deepseek-ai/dsh-commands": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
68
- "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
69
- "@deepseek-ai/dsh-llm-pi-ai": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
70
- "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1",
66
+ "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1 || 0.2.0-rc.1 || 0.2.0-rc.2",
67
+ "@deepseek-ai/dsh-commands": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1 || 0.2.0-rc.1 || 0.2.0-rc.2",
68
+ "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1 || 0.2.0-rc.1 || 0.2.0-rc.2",
69
+ "@deepseek-ai/dsh-llm-pi-ai": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1 || 0.2.0-rc.1 || 0.2.0-rc.2",
70
+ "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.6 || ^0.1.1-rc.1 || 0.1.2-alpha.3 || 0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.2 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.7-rc.1 || 0.2.0-rc.1 || 0.2.0-rc.2",
71
71
  "@deepseek-ai/schemastery": "^3.18.1",
72
72
  "@types/node": "^22.0.0",
73
73
  "typescript": "^6.0.3"