dsh-code 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.en.md +21 -13
  2. package/README.md +285 -271
  3. package/bin/deepseek.mjs +26 -3
  4. package/lib/index.mjs +2962 -1560
  5. package/lib/types/app.d.ts +13 -2
  6. package/lib/types/commands.d.ts +13 -0
  7. package/lib/types/editor-keys.d.ts +105 -0
  8. package/lib/types/git-workflow.d.ts +6 -2
  9. package/lib/types/index.d.ts +28 -0
  10. package/lib/types/input-split.d.ts +54 -0
  11. package/lib/types/kernel-panels.d.ts +3 -1
  12. package/lib/types/keyboard.d.ts +8 -0
  13. package/lib/types/model-capabilities.d.ts +82 -0
  14. package/lib/types/provider-settings.d.ts +84 -0
  15. package/lib/types/render/lines.d.ts +25 -0
  16. package/lib/types/render/markdown.d.ts +1 -1
  17. package/lib/types/render/projection.d.ts +22 -2
  18. package/lib/types/render/status.d.ts +22 -15
  19. package/lib/types/render/text.d.ts +15 -9
  20. package/lib/types/render/width.d.ts +29 -0
  21. package/lib/types/session-directory.d.ts +27 -0
  22. package/lib/types/settings-file.d.ts +33 -0
  23. package/lib/types/skills.d.ts +1 -1
  24. package/lib/types/store.d.ts +10 -0
  25. package/lib/types/subagents.d.ts +13 -3
  26. package/package.json +159 -159
  27. package/src/app.ts +4514 -3892
  28. package/src/approval.ts +8 -3
  29. package/src/authorization-panel.ts +2 -4
  30. package/src/commands.ts +27 -3
  31. package/src/editor-keys.ts +371 -0
  32. package/src/git-workflow.ts +10 -6
  33. package/src/index.ts +1752 -1523
  34. package/src/input-split.ts +191 -0
  35. package/src/internals.ts +26 -8
  36. package/src/kernel-panels.ts +26 -10
  37. package/src/keyboard.ts +123 -88
  38. package/src/mentions.ts +42 -9
  39. package/src/model-capabilities.ts +318 -0
  40. package/src/provider-settings.ts +220 -0
  41. package/src/questions.ts +20 -0
  42. package/src/render/lines.ts +415 -356
  43. package/src/render/markdown.ts +18 -19
  44. package/src/render/projection.ts +162 -52
  45. package/src/render/status.ts +76 -71
  46. package/src/render/text.ts +158 -150
  47. package/src/render/width.ts +189 -0
  48. package/src/session-directory.ts +56 -0
  49. package/src/settings-file.ts +56 -0
  50. package/src/skills.ts +19 -6
  51. package/src/store.ts +26 -7
  52. package/src/subagents.ts +39 -6
  53. package/src/theme-panel.ts +79 -72
@@ -1,72 +1,79 @@
1
- /**
2
- * The `/theme` picker (the Codex `/theme` contract): one bounded list over
3
- * the three color themes — dark, light, and auto (terminal-sensed; auto
4
- * falls back to dark until OSC-11 detection lands). Enter applies the row
5
- * and the runner persists it; Esc closes without changing the theme.
6
- *
7
- * @module @deepseek-ai/dsh-tui/theme-panel
8
- */
9
-
10
- import { createElement, useState, type ReactElement } from 'react'
11
- import { Box, Text, useInput, useStdout } from 'ink'
12
- import { panelViewport } from './render/inspector.ts'
13
- import { truncateColumns } from './render/text.ts'
14
- import { getPalette, inkColor, type ThemeName } from './theme.ts'
15
-
16
- /** The three theme rows in canonical order (the /theme selection surface). */
17
- const THEME_ROWS: readonly { id: ThemeName; label: string; description: string }[] = [
18
- { id: 'dark', label: 'dark', description: 'DeepSeek dark palette (default)' },
19
- { id: 'light', label: 'light', description: 'light palette for bright terminals' },
20
- { id: 'auto', label: 'auto', description: 'follow the terminal; dark until detection lands' },
21
- ]
22
-
23
- /**
24
- * The /theme list: one row per theme, the current one marked with ●, the
25
- * focused one with ›. Enter applies the focused theme (the runner persists
26
- * it), Esc/q closes without changing anything. Colors read the ACTIVE
27
- * palette, so the panel itself adapts to a light theme once applied.
28
- */
29
- export function ThemePanel({ current, select, close }: {
30
- /** Theme name in force (the requested name; 'auto' included). */
31
- current: ThemeName
32
- /** Accept one theme name: applied immediately and persisted by the runner. */
33
- select(name: ThemeName): void
34
- /** Close without changing the theme. */
35
- close(): void
36
- }): ReactElement {
37
- const [cursor, setCursor] = useState(() => {
38
- const index = THEME_ROWS.findIndex(theme => theme.id === current)
39
- return index < 0 ? 0 : index
40
- })
41
- const stdout = useStdout().stdout
42
- const viewport = panelViewport(stdout?.columns ?? 80, stdout?.rows ?? 30)
43
- useInput((input, key) => {
44
- if (key.escape || input === 'q') return close()
45
- if (key.upArrow) return setCursor(value => (value + THEME_ROWS.length - 1) % THEME_ROWS.length)
46
- if (key.downArrow) return setCursor(value => (value + 1) % THEME_ROWS.length)
47
- if (key.return) return select(THEME_ROWS[cursor]!.id)
48
- })
49
- if (viewport.maxHeight === 0) return createElement(Box, { display: 'none' })
50
- if (viewport.compact) {
51
- return createElement(Text, { wrap: 'truncate-end' }, truncateColumns('/theme · esc close', viewport.contentColumns))
52
- }
53
- return createElement(
54
- Box,
55
- { width: viewport.outerColumns, borderStyle: 'round', borderColor: inkColor(getPalette().dim), flexDirection: 'column', paddingX: 1 },
56
- createElement(Text, { color: inkColor(getPalette().brandBright), wrap: 'truncate-end' }, truncateColumns('/theme — color palette', viewport.contentColumns)),
57
- ...THEME_ROWS.map((theme, index) => {
58
- const selected = index === cursor
59
- const active = theme.id === current
60
- return createElement(
61
- Text,
62
- {
63
- key: theme.id,
64
- color: selected ? inkColor(getPalette().brandBright) : undefined,
65
- wrap: 'truncate-end',
66
- },
67
- truncateColumns(`${selected ? '› ' : ' '}${active ? '● ' : '○ '}${theme.label}${active ? ' · current' : ''} · ${theme.description}`, viewport.contentColumns),
68
- )
69
- }),
70
- createElement(Text, { dimColor: true, wrap: 'truncate-end' }, truncateColumns('↑↓ choose · enter apply · esc/q close', viewport.contentColumns)),
71
- )
72
- }
1
+ /**
2
+ * The `/theme` picker (the Codex `/theme` contract): one bounded list over
3
+ * the three color themes — dark, light, and auto (terminal-sensed; auto
4
+ * falls back to dark until OSC-11 detection lands). Enter applies the row
5
+ * and the runner persists it; Esc closes without changing the theme.
6
+ *
7
+ * @module @deepseek-ai/dsh-tui/theme-panel
8
+ */
9
+
10
+ import { createElement, useState, type ReactElement } from 'react'
11
+ import { Box, Text, useInput, useStdout } from 'ink'
12
+ import { clampScroll, panelViewport } from './render/inspector.ts'
13
+ import { truncateColumns } from './render/text.ts'
14
+ import { getPalette, inkColor, type ThemeName } from './theme.ts'
15
+
16
+ /** The three theme rows in canonical order (the /theme selection surface). */
17
+ const THEME_ROWS: readonly { id: ThemeName; label: string; description: string }[] = [
18
+ { id: 'dark', label: 'dark', description: 'DeepSeek dark palette (default)' },
19
+ { id: 'light', label: 'light', description: 'light palette for bright terminals' },
20
+ { id: 'auto', label: 'auto', description: 'follow the terminal; dark until detection lands' },
21
+ ]
22
+
23
+ /**
24
+ * The /theme list: one row per theme, the current one marked with ●, the
25
+ * focused one with ›. Enter applies the focused theme (the runner persists
26
+ * it), Esc/q closes without changing anything. Colors read the ACTIVE
27
+ * palette, so the panel itself adapts to a light theme once applied.
28
+ */
29
+ export function ThemePanel({ current, select, close }: {
30
+ /** Theme name in force (the requested name; 'auto' included). */
31
+ current: ThemeName
32
+ /** Accept one theme name: applied immediately and persisted by the runner. */
33
+ select(name: ThemeName): void
34
+ /** Close without changing the theme. */
35
+ close(): void
36
+ }): ReactElement {
37
+ const [cursor, setCursor] = useState(() => {
38
+ const index = THEME_ROWS.findIndex(theme => theme.id === current)
39
+ return index < 0 ? 0 : index
40
+ })
41
+ const stdout = useStdout().stdout
42
+ const viewport = panelViewport(stdout?.columns ?? 80, stdout?.rows ?? 30)
43
+ useInput((input, key) => {
44
+ if (key.escape || input === 'q') return close()
45
+ if (key.upArrow) return setCursor(value => (value + THEME_ROWS.length - 1) % THEME_ROWS.length)
46
+ if (key.downArrow) return setCursor(value => (value + 1) % THEME_ROWS.length)
47
+ if (key.return) return select(THEME_ROWS[cursor]!.id)
48
+ })
49
+ if (viewport.maxHeight === 0 || viewport.compact) {
50
+ return createElement(Text, { wrap: 'truncate-end' }, truncateColumns('/theme · esc close', viewport.contentColumns))
51
+ }
52
+ // The theme rows share the panel's body budget like every other panel: an
53
+ // unsliced three-row list reached terminal-height equality on short
54
+ // terminals, where Ink rewrites the whole Static region every frame.
55
+ // Reveal-cursor slicing keeps the focused row visible instead.
56
+ const rowBudget = Math.max(1, viewport.bodyRows)
57
+ const first = clampScroll(cursor, THEME_ROWS.length, rowBudget)
58
+ const visibleThemes = THEME_ROWS.slice(first, first + rowBudget)
59
+ const hiddenThemes = THEME_ROWS.length - visibleThemes.length
60
+ return createElement(
61
+ Box,
62
+ { width: viewport.outerColumns, borderStyle: 'round', borderColor: inkColor(getPalette().dim), flexDirection: 'column', paddingX: 1 },
63
+ createElement(Text, { color: inkColor(getPalette().brandBright), wrap: 'truncate-end' }, truncateColumns('/theme — color palette', viewport.contentColumns)),
64
+ ...visibleThemes.map((theme, index) => {
65
+ const selected = first + index === cursor
66
+ const active = theme.id === current
67
+ return createElement(
68
+ Text,
69
+ {
70
+ key: theme.id,
71
+ color: selected ? inkColor(getPalette().brandBright) : undefined,
72
+ wrap: 'truncate-end',
73
+ },
74
+ truncateColumns(`${selected ? '› ' : ' '}${active ? '● ' : '○ '}${theme.label}${active ? ' · current' : ''} · ${theme.description}`, viewport.contentColumns),
75
+ )
76
+ }),
77
+ createElement(Text, { dimColor: true, wrap: 'truncate-end' }, truncateColumns(`↑↓ choose · enter apply · esc/q close${hiddenThemes > 0 ? ` · +${hiddenThemes} more` : ''}`, viewport.contentColumns)),
78
+ )
79
+ }