@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
package/README.md CHANGED
@@ -17,9 +17,7 @@
17
17
 
18
18
  > An interactive terminal UI plugin for DeepSeek Harness.
19
19
 
20
- This is an independently developed fork of [dsh-TUI by chimney](https://github.com/ccch1mneyyy/dsh-TUI),
21
- maintained by dkc. Releases and development decisions are made in this
22
- repository. Compatibility with DeepSeek Harness remains a separate requirement.
20
+ This is dkc's independently developed fork of [dsh-TUI by chimney](https://github.com/ccch1mneyyy/dsh-TUI).
23
21
 
24
22
  ## Preview
25
23
 
@@ -36,19 +34,19 @@ repository. Compatibility with DeepSeek Harness remains a separate requirement.
36
34
  - A pixel whale, live work status, context bar, TPS gauge, and clickable timeline.
37
35
  - Session management with resume, fork, rewind, background work, and export.
38
36
  - DSH presets, skills, MCP, goals, subagents, provider authentication, and extensions.
37
+ - Authentication for OpenAI, Claude, OpenCode, OpenRouter, Hermes Agent, Infron, and OrcaRouter.
39
38
  - Virtualized rendering and bounded caches for long sessions.
40
39
 
41
40
  ## Quick Start
42
41
 
43
42
  Requires [Node.js](https://nodejs.org/en) `^22.19 || >=24`, pnpm 11, a
44
43
  [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) source
45
- checkout with dependencies installed, and `DEEPSEEK_API_KEY`. The main
46
- compatibility target is DSH `0.1.7-rc.2`.
44
+ checkout with dependencies installed, and `DEEPSEEK_API_KEY`. We aim to support
45
+ the latest DSH release. The primary validated Harness version is `0.2.0-rc.2`;
46
+ older supported versions are listed in [ADAPTER.md](ADAPTER.md).
47
47
 
48
- The `dsh-auth/` source is tracked in this repository. Clone recursively for the
49
- remaining submodules; in an existing checkout, run
50
- `git submodule update --init --recursive` before installation. Builds use the
51
- checked-out auth source and do not fetch `dsh-auth-fork`.
48
+ Clone recursively to fetch submodules. In an existing checkout, run
49
+ `git submodule update --init --recursive` before installation.
52
50
 
53
51
  ```sh
54
52
  git clone --recurse-submodules https://github.com/askdkc/dsh-cli.git
@@ -82,6 +80,11 @@ Chinese. Ambiguous short requests keep that session's previous progress language
82
80
  selects a model. `/bg` keeps a session running until the TUI exits. See
83
81
  [Interaction and commands](docs/interaction.en.md) for the full reference.
84
82
 
83
+ `/model` opens a centered picker with Favorites, Recent, and provider sections.
84
+ `/model seek deep` opens it with an order-independent search; an exact
85
+ `/model provider/model-id` switches directly. In the picker, use `Ctrl+F` to
86
+ toggle a favorite, `Ctrl+A` to connect a provider, and `Esc` to close.
87
+
85
88
  To import Claude Code, Codex, OMP, zcode, or Grok Build conversations, run
86
89
  `dsh-cli migrate` to see available histories, then
87
90
  `dsh-cli migrate <agent> [--dry-run]`. Tool traffic is not imported.
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ /** Root-level, zero-layout-height modal. Its catcher and card are siblings. */
3
+ export declare function ModelDialogLayer({ children, onClose, onInsufficientSpace, fullscreen }: {
4
+ children(size: {
5
+ columns: number;
6
+ rows: number;
7
+ }): React.ReactNode;
8
+ onClose(): void;
9
+ onInsufficientSpace?(): void;
10
+ fullscreen: boolean;
11
+ }): React.ReactNode;
12
+ //# sourceMappingURL=ModelDialogLayer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ModelDialogLayer.d.ts","sourceRoot":"","sources":["../../../src/components/ModelDialogLayer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,EAAE;IACvF,QAAQ,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,KAAK,CAAC,SAAS,CAAA;IAClE,OAAO,IAAI,IAAI,CAAA;IACf,mBAAmB,CAAC,IAAI,IAAI,CAAA;IAC5B,UAAU,EAAE,OAAO,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,CAoClB"}
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Box, useApp, useTerminalSize } from '../ui.js';
4
+ import measureElement from '../ink/measure-element.js';
5
+ /** Root-level, zero-layout-height modal. Its catcher and card are siblings. */
6
+ export function ModelDialogLayer({ children, onClose, onInsufficientSpace, fullscreen }) {
7
+ const terminal = useTerminalSize();
8
+ const { stdout } = useApp();
9
+ const ref = React.useRef(null);
10
+ const [region, setRegion] = React.useState({ columns: terminal.columns, rows: terminal.rows });
11
+ React.useLayoutEffect(() => {
12
+ const node = ref.current;
13
+ const parent = node?.parentNode;
14
+ if (!node || !parent)
15
+ return;
16
+ const { width } = measureElement(node);
17
+ const { height } = measureElement(parent);
18
+ let bottom = height;
19
+ let rootHeight = height;
20
+ for (let ancestor = parent; ancestor; ancestor = ancestor.parentNode) {
21
+ bottom += ancestor.yogaNode?.getComputedTop() ?? 0;
22
+ rootHeight = ancestor.yogaNode?.getComputedHeight() ?? rootHeight;
23
+ }
24
+ const terminalRows = stdout.rows ?? terminal.rows;
25
+ const visibleTop = rootHeight > terminalRows ? rootHeight - terminalRows + 1 : 0;
26
+ const rows = fullscreen ? terminalRows : Math.max(1, Math.min(terminalRows, bottom - visibleTop));
27
+ if (!fullscreen && rows < 8)
28
+ onInsufficientSpace?.();
29
+ const columns = Math.max(1, width || terminal.columns);
30
+ setRegion(previous => previous.columns === columns && previous.rows === rows ? previous : { columns, rows });
31
+ });
32
+ const visible = region;
33
+ const columns = Math.max(1, Math.min(72, visible.columns - 2));
34
+ const rows = Math.max(1, Math.min(26, visible.rows - 2));
35
+ const left = Math.max(0, Math.floor((visible.columns - columns) / 2));
36
+ const bottom = Math.max(0, Math.ceil((visible.rows - rows) / 2));
37
+ const layer = _jsxs(_Fragment, { children: [_jsx(Box, { ref: ref, position: "absolute", bottom: 0, left: 0, width: "100%", height: visible.rows, backdrop: "dim", onClick: event => { event.stopImmediatePropagation(); onClose(); } }), _jsx(Box, { position: "absolute", bottom: bottom, left: left, width: columns, height: rows, backgroundColor: "toolCardBackground", opaque: true, overflow: "hidden", onClick: event => event.stopImmediatePropagation(), children: children({ columns, rows }) })] });
38
+ return layer;
39
+ }
@@ -1,46 +1,17 @@
1
1
  import React from 'react';
2
- import type { LlmModelInfo } from '../adapter/ports/channel-view.js';
3
- import type { ModelGroupRow } from '../modelGroups.js';
4
- /**
5
- * Model picker: a permission-colored Pane with
6
- * the rows as Select entries (❯ focus pointer, ✓ on the active row,
7
- * descriptions), plus the Enter/Esc hint line. Selection switches through
8
- * the Chat coordinator's live-fork path.
9
- *
10
- * Opens on the complete searchable model list. Tab can show provider groups
11
- * (registry display name + model count), where Enter drills into one
12
- * provider. Enter on a model switches through the live-fork path.
13
- *
14
- * 长列表按焦点窗口化(Select 同款):picker 经 OverlayAbove 浮层挂载后有
15
- * maxHeight 裁剪,全量渲染会让焦点行被裁掉(看不到焦点按 Enter)。
16
- */
17
- export declare function ModelPicker(props: {
18
- /** Top level: provider groups; Enter/click drills into one. */
19
- groups: readonly ModelGroupRow[];
2
+ import type { ModelPickerRow } from '../modelPickerRows.js';
3
+ import type { ModelRef } from '../modelGroups.js';
4
+ export declare function ModelPicker({ rows, focusIndex, currentModel, favorites, query, cursor, height, status, switching, onPick, onWheelStep }: {
5
+ rows: readonly ModelPickerRow[];
20
6
  focusIndex: number;
21
- /** Current route key — its group row carries the ✓ marker. */
22
- currentProvider: string;
23
- onPick?: (index: number) => void;
24
- query?: string;
25
- cursor?: number;
26
- emptyReason?: 'loading' | 'empty' | 'no-match' | 'error';
27
- } | {
28
- /** Flat catalog or one group's models (`showProviderPrefix` for mixed providers). */
29
- models: readonly LlmModelInfo[];
30
- /** The group's display label as this pane's title (default: "Model"). */
31
- groupLabel?: string;
32
- /** A drilled-in provider or recents group can return to the group list. */
33
- showBack: boolean;
34
- /** Flat catalog can switch to provider groups with Tab. */
35
- showGroups?: boolean;
36
- /** Prefix each row with its provider (the recents group mixes providers). */
37
- showProviderPrefix?: boolean;
38
- focusIndex: number;
39
- /** `provider/model` of the current model — its row carries the ✓ marker. */
40
7
  currentModel: string;
41
- onPick?: (index: number) => void;
42
- query?: string;
43
- cursor?: number;
44
- emptyReason?: 'loading' | 'empty' | 'no-match' | 'error';
8
+ favorites: readonly ModelRef[];
9
+ query: string;
10
+ cursor: number;
11
+ height: number;
12
+ status: 'loading' | 'ready' | 'error';
13
+ switching: boolean;
14
+ onPick(index: number): void;
15
+ onWheelStep(step: number): void;
45
16
  }): React.ReactNode;
46
17
  //# sourceMappingURL=ModelPicker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ModelPicker.d.ts","sourceRoot":"","sources":["../../../src/components/ModelPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAUtD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAC7B;IACA,+DAA+D;IAC/D,MAAM,EAAE,SAAS,aAAa,EAAE,CAAA;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,eAAe,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAA;CACzD,GACC;IACA,qFAAqF;IACrF,MAAM,EAAE,SAAS,YAAY,EAAE,CAAA;IAC/B,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2EAA2E;IAC3E,QAAQ,EAAE,OAAO,CAAA;IACjB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,6EAA6E;IAC7E,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,4EAA4E;IAC5E,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAA;CACzD,GAAG,KAAK,CAAC,SAAS,CA4EpB"}
1
+ {"version":3,"file":"ModelPicker.d.ts","sourceRoot":"","sources":["../../../src/components/ModelPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAMjD,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE;IACxI,IAAI,EAAE,SAAS,cAAc,EAAE,CAAA;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAA;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAA;IACrC,SAAS,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAChC,GAAG,KAAK,CAAC,SAAS,CA4BlB"}
@@ -1,51 +1,22 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { t } from '../i18n.js';
3
2
  import { Box, Text } from '../ui.js';
4
- import { RECENTS_GROUP_PROVIDER, RECENTS_LABEL_PLACEHOLDER } from '../modelGroups.js';
5
- import { Pane } from './design-system/Pane.js';
6
- import { ListItem } from './design-system/ListItem.js';
7
- import { HintLine } from './design-system/HintLine.js';
3
+ import { t } from '../i18n.js';
4
+ import { focusedModelRow } from '../modelPickerRows.js';
8
5
  import { listWindow } from './listWindow.js';
9
- import { useOverlayListRows } from './OverlayAbove.js';
10
6
  import { SearchBox } from './SearchBox.js';
7
+ import { ListItem } from './design-system/ListItem.js';
11
8
  import { useTerminalFocus } from '../ink/hooks/use-terminal-focus.js';
12
- /**
13
- * Model picker: a permission-colored Pane with
14
- * the rows as Select entries (❯ focus pointer, ✓ on the active row,
15
- * descriptions), plus the Enter/Esc hint line. Selection switches through
16
- * the Chat coordinator's live-fork path.
17
- *
18
- * Opens on the complete searchable model list. Tab can show provider groups
19
- * (registry display name + model count), where Enter drills into one
20
- * provider. Enter on a model switches through the live-fork path.
21
- *
22
- * 长列表按焦点窗口化(Select 同款):picker 经 OverlayAbove 浮层挂载后有
23
- * maxHeight 裁剪,全量渲染会让焦点行被裁掉(看不到焦点按 Enter)。
24
- */
25
- export function ModelPicker(props) {
26
- const inGroups = 'groups' in props;
9
+ export function ModelPicker({ rows, focusIndex, currentModel, favorites, query, cursor, height, status, switching, onPick, onWheelStep }) {
27
10
  const terminalFocused = useTerminalFocus();
28
- // Captured before the map: union narrowing does not survive into closures.
29
- const onPick = props.onPick;
30
- // 焦点窗口化按行预算:ListItem 带 description 时占 2 行(正文+描述,均
31
- // truncate 成单行),只数项数会把焦点裁出浮层(二次审查实证)。
32
- // 预算来自最近一层 OverlayAbove 的有效高度(已钳到输入簇上方的真实空间——
33
- // 按 terminalRows 预算在短会话 + 高终端下窗口高过浮层、顶部整行被裁、
34
- // 焦点行不可见,#493/#698),减去本面板框架行:Pane 2 + 标题 2 +
35
- // 搜索栏 1 + 结果数 1 + 页脚 1 + 挂载包裹 marginTop 1 = 8。
36
- const rowHeights = inGroups
37
- ? props.groups.map(() => 2)
38
- : props.models.map(m => (m.description ? 2 : 1));
39
- const rows = inGroups ? props.groups : props.models;
40
- const listRows = useOverlayListRows(8);
41
- const { start, end } = listWindow(rowHeights, props.focusIndex, listRows);
42
- const hint = inGroups
43
- ? t('hint-model-groups')
44
- : props.showBack ? t('hint-model-back') : props.showGroups ? t('hint-model-all') : t('hint-confirm-exit');
45
- return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: inGroups || props.groupLabel === undefined ? t('picker-title-model') : props.groupLabel }) }), _jsx(SearchBox, { query: props.query ?? '', cursorOffset: props.cursor ?? 0, isFocused: true, isTerminalFocused: terminalFocused, borderless: true, placeholder: t('picker-model-search') }), _jsx(Text, { dimColor: true, children: t('picker-model-results', { count: rows.length }) }), rows.length === 0 && _jsx(Text, { dimColor: true, children: t(props.emptyReason === 'loading' ? 'model-loading' : props.emptyReason === 'error' ? 'picker-model-error' : props.emptyReason === 'no-match' ? 'picker-model-no-match' : 'picker-model-empty') }), rows.slice(start, end).map((row, index) => {
46
- const absoluteIndex = start + index;
47
- return inGroups ? (_jsx(ListItem, { isFocused: absoluteIndex === props.focusIndex, declareCursor: false, isSelected: row.provider === props.currentProvider, description: t('picker-group-count', { count: row.count }), showScrollUp: absoluteIndex === start && start > 0, showScrollDown: absoluteIndex === end - 1 && end < rows.length, onClick: onPick ? () => onPick(absoluteIndex) : undefined, children: row.label === RECENTS_LABEL_PLACEHOLDER && row.provider === RECENTS_GROUP_PROVIDER
48
- ? t('picker-group-recent')
49
- : row.label }, row.provider)) : (_jsx(ListItem, { isFocused: absoluteIndex === props.focusIndex, declareCursor: false, isSelected: `${row.provider}/${row.id}` === props.currentModel, description: row.description, showScrollUp: absoluteIndex === start && start > 0, showScrollDown: absoluteIndex === end - 1 && end < rows.length, onClick: onPick ? () => onPick(absoluteIndex) : undefined, children: props.showProviderPrefix === true ? `${row.provider} / ${row.name}` : row.name }, `${row.provider}/${row.id}`));
50
- })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: hint }) })] }));
11
+ const available = Math.max(1, height - 6);
12
+ const window = listWindow(rows.map(() => 1), focusIndex, available);
13
+ const focused = focusedModelRow(rows, focusIndex);
14
+ const route = focused ? `${focused.model.provider}/${focused.model.id}` : '';
15
+ const hint = switching ? t('model-switching', { name: focused?.model.name ?? '' }) : t('hint-model-dialog');
16
+ return (_jsxs(Box, { flexDirection: "column", width: "100%", height: height, paddingX: 1, overflow: "hidden", onWheel: (event) => {
17
+ event.stopImmediatePropagation();
18
+ onWheelStep(event.deltaY < 0 ? -1 : 1);
19
+ }, children: [_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", children: [_jsx(Text, { bold: true, children: t('picker-title-model') }), _jsx(Text, { dimColor: true, children: "esc" })] }), _jsx(SearchBox, { query: query, cursorOffset: cursor, isFocused: true, isTerminalFocused: terminalFocused, borderless: true, placeholder: t('picker-model-search') }), _jsx(Text, { dimColor: true, children: t('picker-model-results', { count: rows.filter(row => row.kind === 'model').length }) }), rows.length === 0 && _jsx(Text, { dimColor: true, children: t(status === 'loading' ? 'model-loading' : status === 'error' ? 'picker-model-error' : query.trim() ? 'picker-model-no-match' : 'picker-model-empty') }), rows.slice(window.start, window.end).map((row, offset) => row.kind === 'heading'
20
+ ? _jsx(Text, { color: "warning", bold: true, wrap: "truncate-end", children: row.key === 'heading:favorites' ? t('picker-model-favorites') : row.key === 'heading:recent' ? t('picker-group-recent') : row.label }, row.key)
21
+ : _jsx(Box, { width: "100%", height: 1, overflow: "hidden", backgroundColor: window.start + offset === focusIndex ? 'userMessageBackgroundHover' : undefined, children: _jsxs(ListItem, { isFocused: window.start + offset === focusIndex, isSelected: `${row.model.provider}/${row.model.id}` === currentModel, declareCursor: false, onClick: () => onPick(window.start + offset), children: [favorites.some(ref => ref.provider === row.model.provider && ref.id === row.model.id) ? '★ ' : '', row.model.name, _jsx(Text, { dimColor: true, children: ` ${row.providerName}` })] }) }, row.key)), _jsx(Box, { flexGrow: 1 }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: route }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: hint })] }));
51
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ListItem.d.ts","sourceRoot":"","sources":["../../../../src/components/design-system/ListItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAGvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAGjE,MAAM,MAAM,aAAa,GAAG;IAC1B;qDACiD;IACjD,SAAS,EAAE,OAAO,CAAA;IAClB;uDACmD;IACnD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,4CAA4C;IAC5C,QAAQ,EAAE,SAAS,CAAA;IACnB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,oEAAoE;IACpE,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,yEAAyE;IACzE,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,UAAkB,EAClB,QAAQ,EACR,WAAW,EACX,cAAc,EACd,YAAY,EACZ,MAAa,EACb,QAAgB,EAChB,aAAa,EACb,OAAO,GACR,EAAE,aAAa,GAAG,KAAK,CAAC,SAAS,CAoFjC"}
1
+ {"version":3,"file":"ListItem.d.ts","sourceRoot":"","sources":["../../../../src/components/design-system/ListItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAGvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAGjE,MAAM,MAAM,aAAa,GAAG;IAC1B;qDACiD;IACjD,SAAS,EAAE,OAAO,CAAA;IAClB;uDACmD;IACnD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,4CAA4C;IAC5C,QAAQ,EAAE,SAAS,CAAA;IACnB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,oEAAoE;IACpE,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,yEAAyE;IACzE,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,UAAkB,EAClB,QAAQ,EACR,WAAW,EACX,cAAc,EACd,YAAY,EACZ,MAAa,EACb,QAAgB,EAChB,aAAa,EACb,OAAO,GACR,EAAE,aAAa,GAAG,KAAK,CAAC,SAAS,CAmFjC"}
@@ -58,7 +58,7 @@ export function ListItem({ isFocused, isSelected = false, children, description,
58
58
  // 非 Fragment 的 element(如调用方自己的 <Text>)保留原样——其子树高度
59
59
  // 由调用方负责。
60
60
  const flatChildren = flattenDeep(children);
61
- return (_jsxs(Box, { ref: cursorRef, flexDirection: "column", onClick: clickable ? onClick : undefined, onMouseEnter: clickable ? () => setHovered(true) : undefined, onMouseLeave: clickable ? () => setHovered(false) : undefined, backgroundColor: clickable && hovered ? 'userMessageBackgroundHover' : undefined, children: [_jsxs(Box, { flexDirection: "row", gap: 1, height: 1, flexShrink: 0, overflow: "hidden", width: "100%", children: [renderIndicator(), styled ? (_jsx(Text, { color: getTextColor(), dimColor: disabled, wrap: "truncate-end", children: flatChildren })) : (flatChildren), isSelected && !disabled && _jsx(Text, { color: "success", children: TICK })] }), description && (_jsx(Box, { paddingLeft: 2, children: _jsx(Text, { color: "inactive", wrap: "truncate", children: flattenLine(description) }) }))] }));
61
+ return (_jsxs(Box, { ref: cursorRef, flexDirection: "column", onClick: clickable ? onClick : undefined, onMouseEnter: clickable ? () => setHovered(true) : undefined, onMouseLeave: clickable ? () => setHovered(false) : undefined, backgroundColor: clickable && hovered ? 'userMessageBackgroundHover' : undefined, children: [_jsxs(Box, { flexDirection: "row", gap: 1, height: 1, flexShrink: 0, overflow: "hidden", width: "100%", paddingRight: isSelected && !disabled ? 2 : 0, children: [renderIndicator(), styled ? (_jsx(Text, { color: getTextColor(), dimColor: disabled, wrap: "truncate-end", children: flatChildren })) : (flatChildren), isSelected && !disabled && _jsx(Box, { position: "absolute", right: 1, width: 1, children: _jsx(Text, { color: "success", children: TICK }) })] }), description && (_jsx(Box, { paddingLeft: 2, children: _jsx(Text, { color: "inactive", wrap: "truncate", children: flattenLine(description) }) }))] }));
62
62
  }
63
63
  /** 单行化:内嵌换行折叠为空格(行尾/行首换行随之消除)。 */
64
64
  function flattenLine(s) {
@@ -1 +1 @@
1
- {"version":3,"file":"command-completions.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/command-completions.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8C,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAI1G,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,wFAAwF;AACxF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,KAAK,EAAE,MAAM,YAAY,CAAA;IACzB,SAAS,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAA;IACjD,YAAY,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,qBAAqB,EAAE,CAAA;KAAE,CAAA;IACtF,iBAAiB,IAAI,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACnG,KAAK,EAAE;QACL,cAAc,IAAI,IAAI,CAAA;QACtB,UAAU,IAAI,SAAS,qBAAqB,EAAE,CAAA;QAC9C,iBAAiB,IAAI,IAAI,CAAA;QACzB,aAAa,IAAI,SAAS;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,OAAO,CAAA;SAAE,EAAE,CAAA;QACpG,gBAAgB,IAAI,IAAI,CAAA;KACzB,CAAA;CACF,IAES,OAAO,MAAM,qDAyEtB"}
1
+ {"version":3,"file":"command-completions.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/command-completions.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8C,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAI1G,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,wFAAwF;AACxF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,KAAK,EAAE,MAAM,YAAY,CAAA;IACzB,SAAS,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAA;IACjD,YAAY,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,qBAAqB,EAAE,CAAA;KAAE,CAAA;IACtF,iBAAiB,IAAI,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACnG,KAAK,EAAE;QACL,cAAc,IAAI,IAAI,CAAA;QACtB,UAAU,IAAI,SAAS,qBAAqB,EAAE,CAAA;QAC9C,iBAAiB,IAAI,IAAI,CAAA;QACzB,aAAa,IAAI,SAAS;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,OAAO,CAAA;SAAE,EAAE,CAAA;QACpG,gBAAgB,IAAI,IAAI,CAAA;KACzB,CAAA;CACF,IAES,OAAO,MAAM,qDAmFtB"}
@@ -9,10 +9,19 @@ export function createCommandCompletions(deps) {
9
9
  const { themeHost, commandTrees, workspaceCommands, model } = deps;
10
10
  return (input) => {
11
11
  const state = deps.state();
12
+ // Model arguments are search text, not a hierarchy of route completions.
13
+ // Keep the original line so Enter, Tab and click cannot select the first model.
14
+ if (/^\/model(?:[\t ]|$)/iu.test(input) && !/[\r\n]/u.test(input)) {
15
+ return [{
16
+ name: input.slice(1),
17
+ description: 'Open model picker',
18
+ descriptionKey: 'sugg-model-open-desc',
19
+ replacement: input,
20
+ commandLine: input,
21
+ }];
22
+ }
12
23
  const head = input.slice(1).split(/[\t ]/)[0]?.toLowerCase() ?? '';
13
24
  if (head !== '') {
14
- if ('model'.startsWith(head))
15
- model.warmModelNodes();
16
25
  if ('preset'.startsWith(head))
17
26
  model.warmPresetOptions();
18
27
  if ('effort'.startsWith(head))
@@ -1,9 +1,10 @@
1
1
  /** Primary validated upstream line (newest). */
2
- export declare const UPSTREAM_VALIDATED_VERSION = "0.1.7-rc.2";
2
+ export declare const UPSTREAM_VALIDATED_VERSION = "0.2.0-rc.2";
3
3
  /**
4
4
  * Explicitly supported upstream prerelease lines, oldest first.
5
5
  *
6
- * 0.1.7-rc.2 = primary continuous-CI line; 0.1.7-rc.1 = previous 0.1.7
6
+ * 0.2.0-rc.2 = primary continuous-CI line; 0.2.0-rc.1 = previous primary;
7
+ * 0.1.7-rc.2/rc.1 = previous
7
8
  * build (mapped compatibility); 0.1.5-rc.1/alpha.2/alpha.1 = mapped
8
9
  * compatibility lines (source-checked when the primary line moves);
9
10
  * 0.1.3-alpha.2 = compatibility line (the only 0.1.3 build on npm);
@@ -16,7 +17,7 @@ export declare const UPSTREAM_VALIDATED_VERSION = "0.1.7-rc.2";
16
17
  * The peer range in package.json is deliberately wider than this list: an
17
18
  * install on an older or newer line is allowed but reports drift at boot.
18
19
  */
19
- export declare const UPSTREAM_VALIDATED_VERSIONS: readonly ["0.1.0-rc.6", "0.1.0-rc.7", "0.1.0-rc.8", "0.1.1-rc.1", "0.1.1-rc.2", "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.1.7-rc.2"];
20
+ export declare const UPSTREAM_VALIDATED_VERSIONS: readonly ["0.1.0-rc.6", "0.1.0-rc.7", "0.1.0-rc.8", "0.1.1-rc.1", "0.1.1-rc.2", "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.1.7-rc.2", "0.2.0-rc.1", "0.2.0-rc.2"];
20
21
  /**
21
22
  * Framework packages version on their own lines; the contract validates
22
23
  * their MAJOR (breaking surface), not the harness prerelease number.
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/contract.ts"],"names":[],"mappings":"AAkBA,gDAAgD;AAChD,eAAO,MAAM,0BAA0B,eAAe,CAAA;AAEtD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,2BAA2B,+OAgB9B,CAAA;AAEV;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAG5D,CAAA;AAED,qEAAqE;AACrE,eAAO,MAAM,yBAAyB,o8BA+B5B,CAAA;AAEV,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;CAClB;AAUD,4EAA4E;AAC5E,MAAM,MAAM,yBAAyB,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;AAE/D,4FAA4F;AAC5F,MAAM,MAAM,oBAAoB,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,yBAAyB,EAAE,MAAM,CAAC,CAAA;AAEvG,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,oBAAoB,GAAG,SAAS,CAKlG;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,CAAC,EAAE,oBAAoB,EAAE,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAQxF;AAkBD,sEAAsE;AACtE,eAAO,MAAM,wBAAwB,QAA6D,CAAA;AAYlG,wBAAgB,yBAAyB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAqB9E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAE9F;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAKnF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,iBAAiB,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAA+B,GAC5F,MAAM,EAAE,CAQV;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,iBAAiB,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAA+B,GAC5F,kBAAkB,EAAE,CAuBtB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEtE,wEAAwE;AACxE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,iBAAiB,CAAA;IACvB,sFAAsF;IACtF,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,iBAAiB,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAA+B,GAC5F,oBAAoB,GAAG,SAAS,CA0BlC"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/contract.ts"],"names":[],"mappings":"AAkBA,gDAAgD;AAChD,eAAO,MAAM,0BAA0B,eAAe,CAAA;AAEtD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,2BAA2B,2QAkB9B,CAAA;AAEV;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAG5D,CAAA;AAED,qEAAqE;AACrE,eAAO,MAAM,yBAAyB,o8BA+B5B,CAAA;AAEV,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;CAClB;AAUD,4EAA4E;AAC5E,MAAM,MAAM,yBAAyB,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;AAE/D,4FAA4F;AAC5F,MAAM,MAAM,oBAAoB,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,yBAAyB,EAAE,MAAM,CAAC,CAAA;AAEvG,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,oBAAoB,GAAG,SAAS,CAKlG;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,CAAC,EAAE,oBAAoB,EAAE,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAQxF;AAkBD,sEAAsE;AACtE,eAAO,MAAM,wBAAwB,QAA6D,CAAA;AAYlG,wBAAgB,yBAAyB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAqB9E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAE9F;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAKnF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,iBAAiB,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAA+B,GAC5F,MAAM,EAAE,CAQV;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,iBAAiB,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAA+B,GAC5F,kBAAkB,EAAE,CAuBtB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEtE,wEAAwE;AACxE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,iBAAiB,CAAA;IACvB,sFAAsF;IACtF,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,iBAAiB,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAA+B,GAC5F,oBAAoB,GAAG,SAAS,CA0BlC"}
@@ -2,7 +2,7 @@
2
2
  * Upstream compatibility contract.
3
3
  *
4
4
  * The TUI is validated against a set of upstream prerelease lines — the
5
- * current primary (0.1.7-rc.2) plus older lines kept in backward
5
+ * current primary (0.2.0-rc.2) plus older lines kept in backward
6
6
  * compatibility across the 0.1.5, 0.1.3, 0.1.2, 0.1.1 and 0.1.0 release
7
7
  * families.
8
8
  * Every official package this adapter touches is blessed here; anything
@@ -16,11 +16,12 @@
16
16
  import { readFileSync } from 'node:fs';
17
17
  import { fileURLToPath } from 'node:url';
18
18
  /** Primary validated upstream line (newest). */
19
- export const UPSTREAM_VALIDATED_VERSION = '0.1.7-rc.2';
19
+ export const UPSTREAM_VALIDATED_VERSION = '0.2.0-rc.2';
20
20
  /**
21
21
  * Explicitly supported upstream prerelease lines, oldest first.
22
22
  *
23
- * 0.1.7-rc.2 = primary continuous-CI line; 0.1.7-rc.1 = previous 0.1.7
23
+ * 0.2.0-rc.2 = primary continuous-CI line; 0.2.0-rc.1 = previous primary;
24
+ * 0.1.7-rc.2/rc.1 = previous
24
25
  * build (mapped compatibility); 0.1.5-rc.1/alpha.2/alpha.1 = mapped
25
26
  * compatibility lines (source-checked when the primary line moves);
26
27
  * 0.1.3-alpha.2 = compatibility line (the only 0.1.3 build on npm);
@@ -49,6 +50,8 @@ export const UPSTREAM_VALIDATED_VERSIONS = [
49
50
  '0.1.5-rc.1',
50
51
  '0.1.7-rc.1',
51
52
  '0.1.7-rc.2',
53
+ '0.2.0-rc.1',
54
+ '0.2.0-rc.2',
52
55
  ];
53
56
  /**
54
57
  * Framework packages version on their own lines; the contract validates
@@ -874,14 +874,6 @@ declare const dict: {
874
874
  readonly zh: "模型已切换,但工作区挂载失败 · {{err}}";
875
875
  readonly en: "Model switched, but workspace attachment failed · {{err}}";
876
876
  };
877
- readonly 'model-usage': {
878
- readonly zh: "用法:/model <provider/model>(如 deepseek/deepseek-flash)";
879
- readonly en: "Usage: /model <provider/model> (e.g. deepseek/deepseek-flash)";
880
- };
881
- readonly 'model-unknown': {
882
- readonly zh: "未知模型「{{spec}}」· /model 查看全部";
883
- readonly en: "Unknown model \"{{spec}}\" · /model to view all";
884
- };
885
877
  readonly 'compact-unavailable': {
886
878
  readonly zh: "压缩不可用——当前 leaf 没有压缩服务";
887
879
  readonly en: "Compaction unavailable · no compaction service in this leaf";
@@ -2880,14 +2872,26 @@ declare const dict: {
2880
2872
  readonly zh: "最近使用";
2881
2873
  readonly en: "Recently used";
2882
2874
  };
2883
- readonly 'picker-group-count': {
2884
- readonly zh: "{{count}} 个模型";
2885
- readonly en: "{{count}} models";
2886
- };
2887
2875
  readonly 'picker-model-search': {
2888
2876
  readonly zh: "输入关键词筛选模型";
2889
2877
  readonly en: "Type keywords to filter models";
2890
2878
  };
2879
+ readonly 'picker-model-favorites': {
2880
+ readonly zh: "收藏";
2881
+ readonly en: "Favorites";
2882
+ };
2883
+ readonly 'picker-model-favorite-save-error': {
2884
+ readonly zh: "无法保存模型收藏;本次会话仍可使用";
2885
+ readonly en: "Could not save model favorites; this session keeps the change";
2886
+ };
2887
+ readonly 'sugg-model-open-desc': {
2888
+ readonly zh: "打开模型选择界面";
2889
+ readonly en: "Open model picker";
2890
+ };
2891
+ readonly 'hint-model-dialog': {
2892
+ readonly zh: "Enter 切换 · Ctrl+F 收藏 · Ctrl+A 添加提供方 · Ctrl+R 重试 · Esc 关闭";
2893
+ readonly en: "Enter switch · Ctrl+F favorite · Ctrl+A connect · Ctrl+R retry · Esc close";
2894
+ };
2891
2895
  readonly 'picker-model-results': {
2892
2896
  readonly zh: "{{count}} 个结果";
2893
2897
  readonly en: "{{count}} results";
@@ -2901,20 +2905,8 @@ declare const dict: {
2901
2905
  readonly en: "No matching models";
2902
2906
  };
2903
2907
  readonly 'picker-model-error': {
2904
- readonly zh: "模型列表获取失败,请重新打开 /model";
2905
- readonly en: "Could not load models; reopen /model to retry";
2906
- };
2907
- readonly 'hint-model-groups': {
2908
- readonly zh: "**Enter** 查看模型 · **Tab** 全部模型 · Esc 退出";
2909
- readonly en: "**Enter** to view models · **Tab** all models · Esc to exit";
2910
- };
2911
- readonly 'hint-model-all': {
2912
- readonly zh: "**Enter** 切换模型 · **Tab** 提供方分组 · Esc 退出";
2913
- readonly en: "**Enter** to switch · **Tab** provider groups · Esc to exit";
2914
- };
2915
- readonly 'hint-model-back': {
2916
- readonly zh: "**Enter** 切换模型 · Esc/⌫ 返回上级";
2917
- readonly en: "**Enter** to switch · Esc/⌫ to go back";
2908
+ readonly zh: "模型列表获取失败,按 Ctrl+R 重试";
2909
+ readonly en: "Could not load models; press Ctrl+R to retry";
2918
2910
  };
2919
2911
  readonly 'picker-title-skills': {
2920
2912
  readonly zh: "技能";
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAMH,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAI9B,+DAA+D;AAC/D,eAAO,MAAM,KAAK,uBAAwB,CAAA;AAE1C;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9D,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAMH,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAI9B,+DAA+D;AAC/D,eAAO,MAAM,KAAK,uBAAwB,CAAA;AAE1C;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9D,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
package/lib/types/i18n.js CHANGED
@@ -280,8 +280,6 @@ const dict = {
280
280
  'model-switch-fork-failed': { zh: '无法切换模型 · {{err}}', en: 'Cannot switch models · {{err}}' },
281
281
  'model-switch-failed': { zh: '模型切换失败 · {{err}}', en: 'Model switch failed · {{err}}' },
282
282
  'model-switch-attach-failed': { zh: '模型已切换,但工作区挂载失败 · {{err}}', en: 'Model switched, but workspace attachment failed · {{err}}' },
283
- 'model-usage': { zh: '用法:/model <provider/model>(如 deepseek/deepseek-flash)', en: 'Usage: /model <provider/model> (e.g. deepseek/deepseek-flash)' },
284
- 'model-unknown': { zh: '未知模型「{{spec}}」· /model 查看全部', en: 'Unknown model "{{spec}}" · /model to view all' },
285
283
  'compact-unavailable': { zh: '压缩不可用——当前 leaf 没有压缩服务', en: 'Compaction unavailable · no compaction service in this leaf' },
286
284
  'compact-while-working': { zh: '回合运行中,无法压缩会话', en: 'Cannot compact while a turn is running' },
287
285
  'compact-working': { zh: '正在压缩会话…', en: 'Summarizing earlier turns…' },
@@ -899,15 +897,15 @@ const dict = {
899
897
  // ── components/ModelPicker.tsx / ThemePicker.tsx / ActivityPicker.tsx / EffortSlider.tsx ──
900
898
  'picker-title-model': { zh: '模型', en: 'Model' },
901
899
  'picker-group-recent': { zh: '最近使用', en: 'Recently used' },
902
- 'picker-group-count': { zh: '{{count}} 个模型', en: '{{count}} models' },
903
900
  'picker-model-search': { zh: '输入关键词筛选模型', en: 'Type keywords to filter models' },
901
+ 'picker-model-favorites': { zh: '收藏', en: 'Favorites' },
902
+ 'picker-model-favorite-save-error': { zh: '无法保存模型收藏;本次会话仍可使用', en: 'Could not save model favorites; this session keeps the change' },
903
+ 'sugg-model-open-desc': { zh: '打开模型选择界面', en: 'Open model picker' },
904
+ 'hint-model-dialog': { zh: 'Enter 切换 · Ctrl+F 收藏 · Ctrl+A 添加提供方 · Ctrl+R 重试 · Esc 关闭', en: 'Enter switch · Ctrl+F favorite · Ctrl+A connect · Ctrl+R retry · Esc close' },
904
905
  'picker-model-results': { zh: '{{count}} 个结果', en: '{{count}} results' },
905
906
  'picker-model-empty': { zh: '没有可用模型', en: 'No models available' },
906
907
  'picker-model-no-match': { zh: '没有匹配的模型', en: 'No matching models' },
907
- 'picker-model-error': { zh: '模型列表获取失败,请重新打开 /model', en: 'Could not load models; reopen /model to retry' },
908
- 'hint-model-groups': { zh: '**Enter** 查看模型 · **Tab** 全部模型 · Esc 退出', en: '**Enter** to view models · **Tab** all models · Esc to exit' },
909
- 'hint-model-all': { zh: '**Enter** 切换模型 · **Tab** 提供方分组 · Esc 退出', en: '**Enter** to switch · **Tab** provider groups · Esc to exit' },
910
- 'hint-model-back': { zh: '**Enter** 切换模型 · Esc/⌫ 返回上级', en: '**Enter** to switch · Esc/⌫ to go back' },
908
+ 'picker-model-error': { zh: '模型列表获取失败,按 Ctrl+R 重试', en: 'Could not load models; press Ctrl+R to retry' },
911
909
  'picker-title-skills': { zh: '技能', en: 'Skills' },
912
910
  'skills-loading': { zh: '正在加载技能', en: 'Loading skills' },
913
911
  'skills-loading-subtitle': { zh: '正在查询技能注册表…', en: 'Querying the skill registry…' },
@@ -0,0 +1,8 @@
1
+ import type { ModelRef } from './modelGroups.js';
2
+ export declare function parseModelFavorites(text: string): readonly ModelRef[];
3
+ export declare function readModelFavorites(dir?: string): readonly ModelRef[];
4
+ export declare function toggleModelFavorite(current: readonly ModelRef[], ref: ModelRef, dir?: string): {
5
+ favorites: readonly ModelRef[];
6
+ saved: boolean;
7
+ };
8
+ //# sourceMappingURL=modelFavorites.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modelFavorites.d.ts","sourceRoot":"","sources":["../../src/modelFavorites.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAEhD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,QAAQ,EAAE,CAgBrE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAiB,GAAG,SAAS,QAAQ,EAAE,CAG9E;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,SAAS,QAAQ,EAAE,EAC5B,GAAG,EAAE,QAAQ,EACb,GAAG,GAAE,MAAiB,GACrB;IAAE,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAepD"}
@@ -0,0 +1,59 @@
1
+ /** Persisted model favorites. Catalog availability never deletes a saved ref. */
2
+ import { mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { randomUUID } from 'node:crypto';
5
+ import { DATA_DIR } from './utils/paths.js';
6
+ export function parseModelFavorites(text) {
7
+ let parsed;
8
+ try {
9
+ parsed = JSON.parse(text);
10
+ }
11
+ catch {
12
+ return [];
13
+ }
14
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
15
+ return [];
16
+ const models = parsed.models;
17
+ if (!Array.isArray(models))
18
+ return [];
19
+ const result = [];
20
+ for (const value of models) {
21
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
22
+ continue;
23
+ const item = value;
24
+ if (typeof item.provider !== 'string' || !item.provider || typeof item.id !== 'string' || !item.id)
25
+ continue;
26
+ if (!result.some(ref => ref.provider === item.provider && ref.id === item.id)) {
27
+ result.push({ provider: item.provider, id: item.id });
28
+ }
29
+ }
30
+ return result;
31
+ }
32
+ export function readModelFavorites(dir = DATA_DIR) {
33
+ try {
34
+ return parseModelFavorites(readFileSync(join(dir, 'model-favorites.json'), 'utf8'));
35
+ }
36
+ catch {
37
+ return [];
38
+ }
39
+ }
40
+ export function toggleModelFavorite(current, ref, dir = DATA_DIR) {
41
+ const exists = current.some(item => item.provider === ref.provider && item.id === ref.id);
42
+ const favorites = exists
43
+ ? current.filter(item => item.provider !== ref.provider || item.id !== ref.id)
44
+ : [...current, ref];
45
+ const temporary = join(dir, `model-favorites.${randomUUID()}.tmp`);
46
+ try {
47
+ mkdirSync(dir, { recursive: true });
48
+ writeFileSync(temporary, `${JSON.stringify({ models: favorites }, null, 2)}\n`, { flag: 'wx' });
49
+ renameSync(temporary, join(dir, 'model-favorites.json'));
50
+ return { favorites, saved: true };
51
+ }
52
+ catch {
53
+ try {
54
+ unlinkSync(temporary);
55
+ }
56
+ catch { /* no temporary file */ }
57
+ return { favorites, saved: false };
58
+ }
59
+ }
@@ -1,10 +1,7 @@
1
1
  /**
2
- * Pure derivation for the two-level `/model` picker: providers as top-level
3
- * groups, their models one level down, with a pinned "recently used"
4
- * pseudo-group first. Kept free of React/channel/i18n state so
5
- * `scripts/verify-model-picker-groups.mjs` can drive it headless; the
6
- * recents row's localized label is resolved at render time (its `label`
7
- * field is the {@link RECENTS_LABEL_PLACEHOLDER} sentinel).
2
+ * Shared literal model filtering and the retained group-derivation helpers.
3
+ * The centered picker builds its display rows in modelPickerRows.ts;
4
+ * older group consumers and their regression tests still use the helpers here.
8
5
  *
9
6
  * @module dsh-tui/modelGroups
10
7
  */
@@ -1 +1 @@
1
- {"version":3,"file":"modelGroups.d.ts","sourceRoot":"","sources":["../../src/modelGroups.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAEpF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAA;AAEnD,gFAAgF;AAChF,eAAO,MAAM,yBAAyB,eAAe,CAAA;AAErD,8EAA8E;AAC9E,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACpB;AAED,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAC1B,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,SAAS,eAAe,EAAE,GACpC,SAAS,YAAY,EAAE,CAQzB;AAED,sDAAsD;AACtD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,MAAM,CAGR;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,SAAS,QAAQ,EAAE,EAC5B,MAAM,EAAE,SAAS,YAAY,EAAE,GAC9B,SAAS,YAAY,EAAE,CAUzB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,aAAa,EAAE,SAAS,eAAe,EAAE,EACzC,OAAO,CAAC,EAAE,SAAS,QAAQ,EAAE,GAC5B,SAAS,aAAa,EAAE,CAsB1B;AAED,0DAA0D;AAC1D,MAAM,WAAW,kBAAkB;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,kDAAkD;IAClD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,OAAO,CAAC,EAAE,SAAS,QAAQ,EAAE,GAC5B,kBAAkB,CAiBpB"}
1
+ {"version":3,"file":"modelGroups.d.ts","sourceRoot":"","sources":["../../src/modelGroups.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAEpF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAA;AAEnD,gFAAgF;AAChF,eAAO,MAAM,yBAAyB,eAAe,CAAA;AAErD,8EAA8E;AAC9E,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACpB;AAED,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAC1B,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,SAAS,eAAe,EAAE,GACpC,SAAS,YAAY,EAAE,CAQzB;AAED,sDAAsD;AACtD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,MAAM,CAGR;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,SAAS,QAAQ,EAAE,EAC5B,MAAM,EAAE,SAAS,YAAY,EAAE,GAC9B,SAAS,YAAY,EAAE,CAUzB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,aAAa,EAAE,SAAS,eAAe,EAAE,EACzC,OAAO,CAAC,EAAE,SAAS,QAAQ,EAAE,GAC5B,SAAS,aAAa,EAAE,CAsB1B;AAED,0DAA0D;AAC1D,MAAM,WAAW,kBAAkB;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,kDAAkD;IAClD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,OAAO,CAAC,EAAE,SAAS,QAAQ,EAAE,GAC5B,kBAAkB,CAiBpB"}