dsh-code 1.3.0 → 1.4.0

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 (92) hide show
  1. package/README.en.md +2 -2
  2. package/README.md +2 -2
  3. package/lib/index.mjs +5115 -4390
  4. package/lib/types/app.d.ts +18 -51
  5. package/lib/types/completion.d.ts +29 -0
  6. package/lib/types/composer.d.ts +150 -0
  7. package/lib/types/git-workflow.d.ts +6 -0
  8. package/lib/types/index.d.ts +6 -188
  9. package/lib/types/locales/en.d.ts +16 -4
  10. package/lib/types/{authorization-panel.d.ts → panels/authorization-panel.d.ts} +6 -1
  11. package/lib/types/panels/completion-panel.d.ts +13 -0
  12. package/lib/types/panels/interaction-bars.d.ts +38 -0
  13. package/lib/types/{kernel-panels.d.ts → panels/kernel-panels.d.ts} +16 -37
  14. package/lib/types/{language-panel.d.ts → panels/language-panel.d.ts} +1 -1
  15. package/lib/types/panels/model-panels.d.ts +86 -0
  16. package/lib/types/{theme-panel.d.ts → panels/theme-panel.d.ts} +1 -1
  17. package/lib/types/{update-panel.d.ts → panels/update-panel.d.ts} +1 -1
  18. package/lib/types/provider-settings.d.ts +11 -0
  19. package/lib/types/render/inspector.d.ts +8 -0
  20. package/lib/types/render/text.d.ts +4 -0
  21. package/lib/types/runner/harness-gate.d.ts +83 -0
  22. package/lib/types/runner/input-history.d.ts +31 -0
  23. package/lib/types/runner/mode-cycle.d.ts +44 -0
  24. package/lib/types/runner/preferences.d.ts +40 -0
  25. package/lib/types/runner/quit.d.ts +27 -0
  26. package/lib/types/runner/search-rows.d.ts +38 -0
  27. package/lib/types/runner/session-io.d.ts +46 -0
  28. package/lib/types/runner/session-target.d.ts +42 -0
  29. package/lib/types/runner/startup-config.d.ts +33 -0
  30. package/lib/types/runner/submissions.d.ts +87 -0
  31. package/lib/types/session/attach.d.ts +39 -0
  32. package/lib/types/{store.d.ts → session/store.d.ts} +1 -1
  33. package/lib/types/{subagents.d.ts → session/subagents.d.ts} +8 -1
  34. package/lib/types/settings-file.d.ts +10 -0
  35. package/lib/types/{panel-accent.d.ts → ui/panel-accent.d.ts} +1 -1
  36. package/lib/types/ui/panel-gap.d.ts +6 -0
  37. package/lib/types/ui/query-editor.d.ts +10 -0
  38. package/lib/types/ui/styled-rows.d.ts +8 -0
  39. package/lib/types/{terminal-title.d.ts → ui/terminal-title.d.ts} +1 -1
  40. package/lib/types/ui/ui-contract.d.ts +12 -0
  41. package/lib/types/ui/use-frames.d.ts +6 -0
  42. package/lib/types/ui/use-stable-input.d.ts +7 -0
  43. package/package.json +1 -1
  44. package/src/app.ts +543 -4066
  45. package/src/completion.ts +117 -0
  46. package/src/composer.ts +1956 -0
  47. package/src/git-workflow.ts +18 -0
  48. package/src/index.ts +113 -633
  49. package/src/internals.ts +1 -1
  50. package/src/locales/en.ts +16 -4
  51. package/src/locales/zh.ts +16 -4
  52. package/src/{authorization-panel.ts → panels/authorization-panel.ts} +25 -6
  53. package/src/panels/completion-panel.ts +79 -0
  54. package/src/panels/interaction-bars.ts +567 -0
  55. package/src/{kernel-panels.ts → panels/kernel-panels.ts} +84 -65
  56. package/src/{language-panel.ts → panels/language-panel.ts} +4 -4
  57. package/src/panels/model-panels.ts +1021 -0
  58. package/src/{theme-panel.ts → panels/theme-panel.ts} +5 -5
  59. package/src/{update-panel.ts → panels/update-panel.ts} +6 -6
  60. package/src/provider-settings.ts +38 -0
  61. package/src/render/inspector.ts +23 -0
  62. package/src/render/text.ts +8 -0
  63. package/src/runner/harness-gate.ts +168 -0
  64. package/src/runner/input-history.ts +77 -0
  65. package/src/runner/mode-cycle.ts +49 -0
  66. package/src/runner/preferences.ts +67 -0
  67. package/src/runner/quit.ts +53 -0
  68. package/src/runner/search-rows.ts +55 -0
  69. package/src/runner/session-io.ts +206 -0
  70. package/src/runner/session-target.ts +81 -0
  71. package/src/runner/startup-config.ts +54 -0
  72. package/src/runner/submissions.ts +157 -0
  73. package/src/session/attach.ts +87 -0
  74. package/src/{session-directory.ts → session/session-directory.ts} +1 -1
  75. package/src/{store.ts → session/store.ts} +1 -1
  76. package/src/{subagents.ts → session/subagents.ts} +12 -1
  77. package/src/settings-file.ts +19 -1
  78. package/src/{panel-accent.ts → ui/panel-accent.ts} +1 -1
  79. package/src/ui/panel-gap.ts +9 -0
  80. package/src/ui/query-editor.ts +16 -0
  81. package/src/ui/styled-rows.ts +124 -0
  82. package/src/{terminal-title.ts → ui/terminal-title.ts} +1 -1
  83. package/src/ui/ui-contract.ts +10 -0
  84. package/src/ui/use-frames.ts +23 -0
  85. package/src/ui/use-stable-input.ts +17 -0
  86. /package/lib/types/{fork.d.ts → session/fork.d.ts} +0 -0
  87. /package/lib/types/{history.d.ts → session/history.d.ts} +0 -0
  88. /package/lib/types/{session-directory.d.ts → session/session-directory.d.ts} +0 -0
  89. /package/lib/types/{session-switch.d.ts → session/session-switch.d.ts} +0 -0
  90. /package/src/{fork.ts → session/fork.ts} +0 -0
  91. /package/src/{history.ts → session/history.ts} +0 -0
  92. /package/src/{session-switch.ts → session/session-switch.ts} +0 -0
@@ -0,0 +1,9 @@
1
+ /** Shared optional spacer row used by bounded panel layouts. */
2
+
3
+ import { createElement, type ReactElement } from 'react'
4
+ import { Text } from 'ink'
5
+
6
+ /** Codex-style panel rhythm that still participates in the row budget. */
7
+ export function PanelGap({ visible }: { visible: boolean }): ReactElement | undefined {
8
+ return visible ? createElement(Text, null, ' ') : undefined
9
+ }
@@ -0,0 +1,16 @@
1
+ /** Shared one-line query editor for keyboard-owned filtering panels. */
2
+
3
+ import { stripPasteMarkers } from '../keyboard.ts'
4
+ import { deleteLastGrapheme } from '../render/editor.ts'
5
+
6
+ /**
7
+ * Apply one keystroke to a panel search query. IME commits arrive as one
8
+ * multi-character chunk, so the whole printable run is appended; paste
9
+ * markers are stripped and control-laden chunks are ignored.
10
+ */
11
+ export function editQuery(query: string, input: string, key: { backspace?: boolean; delete?: boolean }): string | undefined {
12
+ if (key.backspace || key.delete) return deleteLastGrapheme(query)
13
+ const text = stripPasteMarkers(input)
14
+ if (text !== '' && !/[\u0000-\u001f\u007f]/u.test(text)) return query + text
15
+ return undefined
16
+ }
@@ -0,0 +1,124 @@
1
+ /** Ink renderer for width-safe styled terminal rows. */
2
+
3
+ import { createElement, type ReactElement } from 'react'
4
+ import { Box, Text } from 'ink'
5
+ import type { MdSegment } from '../render/markdown.ts'
6
+ import type { LineStyle, StyledLine } from '../render/lines.ts'
7
+ import {
8
+ diffBackground,
9
+ getPalette,
10
+ inkColor,
11
+ promptRowTokens,
12
+ rowBackground,
13
+ } from '../theme.ts'
14
+
15
+ function segmentProps(style: MdSegment['style']): {
16
+ color: string | undefined
17
+ bold: boolean | undefined
18
+ italic: boolean | undefined
19
+ strikethrough: boolean | undefined
20
+ } {
21
+ switch (style) {
22
+ case 'accent':
23
+ return { color: inkColor(getPalette().brandBright), bold: undefined, italic: undefined, strikethrough: undefined }
24
+ case 'accentBold':
25
+ return { color: inkColor(getPalette().brandBright), bold: true, italic: undefined, strikethrough: undefined }
26
+ case 'code':
27
+ return { color: inkColor(getPalette().code), bold: undefined, italic: undefined, strikethrough: undefined }
28
+ case 'dim':
29
+ return { color: inkColor(getPalette().dim), bold: undefined, italic: undefined, strikethrough: undefined }
30
+ case 'bold':
31
+ return { color: undefined, bold: true, italic: undefined, strikethrough: undefined }
32
+ case 'italic':
33
+ return { color: undefined, bold: undefined, italic: true, strikethrough: undefined }
34
+ case 'boldItalic':
35
+ return { color: undefined, bold: true, italic: true, strikethrough: undefined }
36
+ case 'strike':
37
+ return { color: inkColor(getPalette().dim), bold: undefined, italic: undefined, strikethrough: true }
38
+ case 'diffAdd':
39
+ case 'diffDel':
40
+ // Inline-markdown twin of lineStyleProps' diff cases: tinted rows for
41
+ // ```diff fences rendered through the markdown span path. The diff
42
+ // foreground tokens stay AA-legible both on the row tints (when the
43
+ // background rides along) and on the plain terminal background.
44
+ return {
45
+ color: inkColor(style === 'diffAdd' ? getPalette().diffAddFg : getPalette().diffDelFg),
46
+ bold: undefined,
47
+ italic: undefined,
48
+ strikethrough: undefined,
49
+ }
50
+ default:
51
+ return { color: undefined, bold: undefined, italic: undefined, strikethrough: undefined }
52
+ }
53
+ }
54
+
55
+ /** Ink props for the richer line model used by bounded scrolling panels. */
56
+ function lineStyleProps(style: LineStyle): {
57
+ color: string | undefined
58
+ bold: boolean | undefined
59
+ italic: boolean | undefined
60
+ strikethrough: boolean | undefined
61
+ dimColor: boolean | undefined
62
+ backgroundColor: string | undefined
63
+ } {
64
+ switch (style) {
65
+ case 'brand':
66
+ return { color: inkColor(getPalette().brandBright), bold: undefined, italic: undefined, strikethrough: undefined, dimColor: undefined, backgroundColor: undefined }
67
+ case 'success':
68
+ return { color: inkColor(getPalette().success), bold: undefined, italic: undefined, strikethrough: undefined, dimColor: undefined, backgroundColor: undefined }
69
+ case 'error':
70
+ return { color: inkColor(getPalette().error), bold: undefined, italic: undefined, strikethrough: undefined, dimColor: undefined, backgroundColor: undefined }
71
+ case 'warn':
72
+ return { color: inkColor(getPalette().warn), bold: undefined, italic: undefined, strikethrough: undefined, dimColor: undefined, backgroundColor: undefined }
73
+ case 'dimItalic':
74
+ return { color: inkColor(getPalette().dim), bold: undefined, italic: true, strikethrough: undefined, dimColor: undefined, backgroundColor: undefined }
75
+ // Codex diff rendering: added/removed lines carry a theme tint behind
76
+ // the sign and text, with the AA-tuned diff foreground tokens on top; the
77
+ // depth gate turns this into plain foreground styling on 16-color
78
+ // terminals.
79
+ case 'diffAdd':
80
+ return { color: inkColor(getPalette().diffAddFg), bold: undefined, italic: undefined, strikethrough: undefined, dimColor: undefined, backgroundColor: diffBackground('diffAdd') }
81
+ case 'diffDel':
82
+ return { color: inkColor(getPalette().diffDelFg), bold: undefined, italic: undefined, strikethrough: undefined, dimColor: undefined, backgroundColor: diffBackground('diffDel') }
83
+ // Prompt rows: one full-width bar per delivery kind. The tint comes from
84
+ // the row token and the foreground from its AA-tuned twin; the depth gate
85
+ // inside rowBackground degrades this to foreground-only on 16-color
86
+ // terminals, matching the diff rows.
87
+ case 'promptRow':
88
+ case 'promptQueuedRow':
89
+ case 'promptSteeredRow': {
90
+ const tokens = promptRowTokens(style === 'promptQueuedRow' ? 'queued' : style === 'promptSteeredRow' ? 'steered' : undefined)
91
+ return {
92
+ color: inkColor(getPalette()[tokens.fg]),
93
+ bold: undefined,
94
+ italic: undefined,
95
+ strikethrough: undefined,
96
+ dimColor: undefined,
97
+ backgroundColor: rowBackground(tokens.fg),
98
+ }
99
+ }
100
+ default:
101
+ return { ...segmentProps(style), dimColor: undefined, backgroundColor: undefined }
102
+ }
103
+ }
104
+
105
+ /** Render width-safe rows; every child is exactly one terminal row. */
106
+ export function StyledRows({ lines }: { lines: readonly StyledLine[] }): ReactElement {
107
+ return createElement(
108
+ Box,
109
+ { flexDirection: 'column' },
110
+ ...lines.map((line, index) => createElement(
111
+ Text,
112
+ { key: index, wrap: 'truncate-end' },
113
+ line.segments.length === 0
114
+ ? ' '
115
+ : line.segments.map((segment, at) => createElement(
116
+ Text,
117
+ { key: at, ...lineStyleProps(segment.style) },
118
+ segment.text,
119
+ )),
120
+ )),
121
+ )
122
+ }
123
+
124
+ /** File-oriented, color-coded unified diff viewport. */
@@ -10,7 +10,7 @@
10
10
  * an empty OSC payload and the terminal falls back to its own default; the
11
11
  * previously set title is not portable to read back and is never restored.
12
12
  *
13
- * @module @deepseek-ai/dsh-code/terminal-title
13
+ * @module @deepseek-ai/dsh-code/ui/terminal-title
14
14
  */
15
15
 
16
16
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
@@ -0,0 +1,10 @@
1
+ /** Shared terminal UI contracts used by the runner, App, and composer. */
2
+
3
+ /** Visual priority for one bounded local notice. */
4
+ export type NoticeTone = 'info' | 'warning' | 'error'
5
+
6
+ /** One mutation the terminal may request for a pending next-turn inbox item. */
7
+ export type QueueMutation =
8
+ | { readonly kind: 'remove' }
9
+ | { readonly kind: 'edit'; readonly text: string }
10
+ | { readonly kind: 'steer' }
@@ -0,0 +1,23 @@
1
+ /** Wall-clock animation frame hook shared by independent terminal leaves. */
2
+
3
+ import { useEffect, useState } from 'react'
4
+
5
+ /**
6
+ * Derive ticks from elapsed wall time so a stretched interval skips ahead
7
+ * instead of slowing the animation under a busy event loop or remote shell.
8
+ */
9
+ export function useFrames(intervalMs: number, active = true): number {
10
+ const [tick, setTick] = useState(0)
11
+ useEffect(() => {
12
+ if (!active) return
13
+ const startedAt = Date.now()
14
+ setTick(0)
15
+ const id = setInterval(() => {
16
+ setTick(Math.max(0, Math.floor((Date.now() - startedAt) / intervalMs)))
17
+ }, intervalMs)
18
+ return () => {
19
+ clearInterval(id)
20
+ }
21
+ }, [active, intervalMs])
22
+ return tick
23
+ }
@@ -0,0 +1,17 @@
1
+ /** Stable Ink input subscription for stateful keyboard-owned surfaces. */
2
+
3
+ import { useCallback, useRef } from 'react'
4
+ import { useInput, type Key } from 'ink'
5
+
6
+ /**
7
+ * Ink re-subscribes its input effect whenever the handler identity changes.
8
+ * Keep ownership stable while a surface updates cursor, scroll, or draft state.
9
+ */
10
+ export function useStableInput(handler: (input: string, key: Key) => void, active: boolean): void {
11
+ const handlerRef = useRef(handler)
12
+ handlerRef.current = handler
13
+ const stableHandler = useCallback((input: string, key: Key): void => {
14
+ handlerRef.current(input, key)
15
+ }, [])
16
+ useInput(stableHandler, { isActive: active })
17
+ }
File without changes
File without changes
File without changes