dsh-code 1.0.7 → 1.3.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 (89) hide show
  1. package/README.en.md +70 -24
  2. package/README.md +71 -25
  3. package/bin/deepseek.mjs +202 -39
  4. package/cordis.patch.yml +13 -4
  5. package/lib/index.mjs +5002 -1061
  6. package/lib/session-query.mjs +3 -2
  7. package/lib/startup.mjs +4 -4
  8. package/lib/{theme-DCT8Y2xf.mjs → theme-B3orFUYz.mjs} +665 -20
  9. package/lib/types/app.d.ts +120 -63
  10. package/lib/types/attachments.d.ts +16 -7
  11. package/lib/types/authorization-panel.d.ts +3 -3
  12. package/lib/types/git-workflow.d.ts +91 -2
  13. package/lib/types/history.d.ts +10 -0
  14. package/lib/types/i18n.d.ts +39 -0
  15. package/lib/types/index.d.ts +74 -2
  16. package/lib/types/input-split.d.ts +1 -1
  17. package/lib/types/kernel-panels.d.ts +89 -32
  18. package/lib/types/language-panel.d.ts +12 -0
  19. package/lib/types/locales/en.d.ts +498 -0
  20. package/lib/types/locales/zh.d.ts +9 -0
  21. package/lib/types/mentions.d.ts +7 -3
  22. package/lib/types/models.d.ts +14 -0
  23. package/lib/types/panel-accent.d.ts +28 -0
  24. package/lib/types/rainbow.d.ts +69 -0
  25. package/lib/types/render/animations.d.ts +42 -0
  26. package/lib/types/render/inspector.d.ts +26 -0
  27. package/lib/types/render/lines.d.ts +21 -1
  28. package/lib/types/render/markdown.d.ts +1 -1
  29. package/lib/types/render/projection.d.ts +95 -4
  30. package/lib/types/render/status.d.ts +12 -9
  31. package/lib/types/render/text.d.ts +6 -0
  32. package/lib/types/render/usage.d.ts +113 -0
  33. package/lib/types/session-directory.d.ts +42 -1
  34. package/lib/types/session-switch.d.ts +8 -0
  35. package/lib/types/startup.d.ts +1 -1
  36. package/lib/types/terminal-title.d.ts +8 -0
  37. package/lib/types/theme-panel.d.ts +2 -2
  38. package/lib/types/theme.d.ts +271 -52
  39. package/lib/types/update-panel.d.ts +27 -6
  40. package/lib/types/update.d.ts +10 -1
  41. package/lib/types/version.d.ts +6 -3
  42. package/package.json +26 -7
  43. package/src/app.ts +1426 -627
  44. package/src/approval.ts +166 -166
  45. package/src/attachments.ts +65 -19
  46. package/src/authorization-panel.ts +24 -18
  47. package/src/editor-keys.ts +371 -371
  48. package/src/fork.ts +11 -7
  49. package/src/git-workflow.ts +229 -3
  50. package/src/history.ts +14 -0
  51. package/src/i18n.ts +68 -0
  52. package/src/index.ts +503 -128
  53. package/src/input-split.ts +27 -7
  54. package/src/kernel-panels.ts +528 -113
  55. package/src/keyboard.ts +5 -4
  56. package/src/language-panel.ts +53 -0
  57. package/src/locales/en.ts +538 -0
  58. package/src/locales/zh.ts +537 -0
  59. package/src/mentions.ts +8 -4
  60. package/src/models.ts +264 -212
  61. package/src/panel-accent.ts +41 -0
  62. package/src/presets.ts +1 -1
  63. package/src/provider-settings.ts +1 -1
  64. package/src/rainbow.ts +218 -0
  65. package/src/render/animations.ts +104 -6
  66. package/src/render/editor.ts +20 -20
  67. package/src/render/export.ts +116 -95
  68. package/src/render/inspector.ts +42 -0
  69. package/src/render/lines.ts +628 -415
  70. package/src/render/markdown.ts +15 -3
  71. package/src/render/projection.ts +429 -19
  72. package/src/render/status.ts +119 -62
  73. package/src/render/text.ts +15 -0
  74. package/src/render/tool-preview.ts +77 -77
  75. package/src/render/usage.ts +430 -0
  76. package/src/render/width.ts +2 -2
  77. package/src/session-directory.ts +90 -9
  78. package/src/session-query.ts +8 -4
  79. package/src/session-switch.ts +14 -0
  80. package/src/startup.ts +3 -3
  81. package/src/store.ts +19 -1
  82. package/src/subagents.ts +229 -229
  83. package/src/terminal-title.ts +22 -5
  84. package/src/theme-panel.ts +17 -21
  85. package/src/theme.ts +281 -33
  86. package/src/update-panel.ts +148 -31
  87. package/src/update.ts +19 -3
  88. package/src/version.ts +63 -20
  89. package/src/whale-glyph.ts +23 -23
@@ -1,95 +1,116 @@
1
- /**
2
- * Markdown export of one transcript view: the /export command's pure
3
- * formatter. Deterministic and side-effect free — the runner owns the file
4
- * write, so tests drive the builder with folded views directly.
5
- *
6
- * @module @deepseek-ai/dsh-code/render/export
7
- */
8
-
9
- import { assertNever } from '@deepseek-ai/dsh-util-values'
10
- import { fileLabels, imageLabels, type TranscriptView } from './projection.ts'
11
-
12
- /**
13
- * Render the transcript as a standalone markdown document.
14
- * @param view - the folded transcript view to export.
15
- * @param sessionId - the full session identity for the header.
16
- * @returns the complete markdown text.
17
- */
18
- /** Both user and queued rows export the same attachment label block. */
19
- const attachmentLabels = (entry: { images?: readonly unknown[]; files?: readonly unknown[] }): string =>
20
- [imageLabels(entry.images as never), fileLabels(entry.files as never)].filter(label => label !== '').join('\n')
21
-
22
- export function buildExportMarkdown(view: TranscriptView, sessionId: string): string {
23
- const out: string[] = [
24
- view.title === ''
25
- ? `# dsh session ${sessionId}`
26
- : `# ${view.title}`,
27
- `> session ${sessionId}`,
28
- '',
29
- ]
30
- // The effective system prompt (v3 surface nodes) heads the export in a
31
- // collapsed block: visible when audited, out of the way when scrolled.
32
- if (view.systemPrompt !== '') {
33
- out.push('<details><summary>system prompt</summary>', '', view.systemPrompt, '', '</details>', '')
34
- }
35
- for (const entry of view.entries) {
36
- switch (entry.kind) {
37
- case 'user':
38
- if (entry.notice) {
39
- out.push(`> ⤷ context: ${entry.text}`, '')
40
- } else {
41
- const attachments = attachmentLabels(entry)
42
- out.push('## user', '', entry.text, ...(attachments === '' ? [] : [attachments]), '')
43
- }
44
- break
45
- case 'assistant':
46
- if (entry.reasoning !== '') {
47
- out.push('<details><summary>thinking</summary>', '', entry.reasoning, '', '</details>', '')
48
- }
49
- out.push('## assistant', '', entry.text, '')
50
- break
51
- case 'tool':
52
- out.push(`### tool \`${entry.name}\``, '')
53
- if (entry.preview !== '') out.push(`- args: ${entry.preview}`)
54
- if (entry.summary !== '') out.push(`- ${entry.state === 'error' ? 'error' : 'result'}: ${entry.summary}`)
55
- out.push('')
56
- break
57
- case 'command':
58
- out.push(`### /${entry.name}${entry.args === '' ? '' : ` ${entry.args}`}`, '')
59
- if (entry.summary !== '') out.push(`- ${entry.state === 'error' ? 'error' : 'result'}: ${entry.summary}`)
60
- out.push('')
61
- break
62
- case 'error':
63
- out.push(`> ⨯ ${entry.text}`, '')
64
- break
65
- case 'turn-marker':
66
- out.push(`> ${entry.text}`, '')
67
- break
68
- case 'compaction':
69
- out.push(entry.ok
70
- ? `> compacted ~${entry.tokens} tokens`
71
- : `> compaction failed: ${entry.error}`, '')
72
- break
73
- case 'retry':
74
- out.push(`> retry ${entry.attempt}/${entry.max} (${entry.code})`, '')
75
- break
76
- case 'files':
77
- out.push(`> files changed: ${entry.paths.join(', ')}`, '')
78
- break
79
- case 'pending':
80
- // Codex PendingSteer: queued prompts export like ordinary user rows.
81
- out.push('## user', '', entry.text, ...(attachmentLabels(entry) === '' ? [] : [attachmentLabels(entry)]), '')
82
- break
83
- default:
84
- assertNever(entry, 'transcript entry kind')
85
- }
86
- }
87
- if (view.streaming !== '') out.push('## assistant (streaming)', '', view.streaming, '')
88
- const { stats } = view
89
- out.push('---', '')
90
- out.push(`- model: ${view.model === '' ? '(none yet)' : view.model}`)
91
- out.push(`- turns: ${stats.turns} · steps: ${stats.steps}`)
92
- out.push(`- tokens: ↑${stats.usage.inputTokens} ↓${stats.usage.outputTokens} · cache read ${stats.usage.cacheReadTokens}`)
93
- out.push(`- todos: ${view.todos.length}`)
94
- return out.join('\n')
95
- }
1
+ /**
2
+ * Markdown export of one transcript view: the /export command's pure
3
+ * formatter. Deterministic and side-effect free — the runner owns the file
4
+ * write, so tests drive the builder with folded views directly.
5
+ *
6
+ * @module @deepseek-ai/dsh-code/render/export
7
+ */
8
+
9
+ import { assertNever } from '@deepseek-ai/dsh-util-values'
10
+ import { fileLabels, imageLabels, type TranscriptView } from './projection.ts'
11
+ import { t } from '../i18n.ts'
12
+
13
+ /**
14
+ * Render the transcript as a standalone markdown document.
15
+ * @param view - the folded transcript view to export.
16
+ * @param sessionId - the full session identity for the header.
17
+ * @returns the complete markdown text.
18
+ */
19
+ /** Both user and queued rows export the same attachment label block. */
20
+ const attachmentLabels = (entry: { images?: readonly unknown[]; files?: readonly unknown[] }): string =>
21
+ [imageLabels(entry.images as never), fileLabels(entry.files as never)].filter(label => label !== '').join('\n')
22
+
23
+ export function buildExportMarkdown(view: TranscriptView, sessionId: string): string {
24
+ const out: string[] = [
25
+ view.title === ''
26
+ ? `# dsh session ${sessionId}`
27
+ : `# ${view.title}`,
28
+ `> session ${sessionId}`,
29
+ '',
30
+ ]
31
+ // The effective system prompt (v3 surface nodes) heads the export in a
32
+ // collapsed block: visible when audited, out of the way when scrolled.
33
+ if (view.systemPrompt !== '') {
34
+ out.push('<details><summary>system prompt</summary>', '', view.systemPrompt, '', '</details>', '')
35
+ }
36
+ for (const entry of view.entries) {
37
+ switch (entry.kind) {
38
+ case 'user':
39
+ if (entry.notice) {
40
+ out.push(`> context: ${entry.text}`, '')
41
+ } else {
42
+ const attachments = attachmentLabels(entry)
43
+ // How the prompt was delivered is part of the record: a queued or
44
+ // steered message reads differently from one typed into an idle
45
+ // composer. Ordinary prompts keep the bare heading.
46
+ const marker = entry.delivery === undefined ? '' : ` (${t(entry.delivery === 'queued' ? 'entry.delivery.queued' : 'entry.delivery.steered')})`
47
+ out.push(`## user${marker}`, '', entry.text, ...(attachments === '' ? [] : [attachments]), '')
48
+ }
49
+ break
50
+ case 'assistant':
51
+ if (entry.reasoning !== '') {
52
+ out.push('<details><summary>thinking</summary>', '', entry.reasoning, '', '</details>', '')
53
+ }
54
+ out.push('## assistant', '', entry.text, '')
55
+ break
56
+ case 'tool':
57
+ out.push(`### tool \`${entry.name}\``, '')
58
+ if (entry.preview !== '') out.push(`- args: ${entry.preview}`)
59
+ if (entry.subs.length > 0) {
60
+ for (const sub of entry.subs) {
61
+ const label = sub.preview === '' ? sub.name : `${sub.name} ${sub.preview}`
62
+ out.push(`- dispatch: ${sub.state === 'error' ? 'error' : sub.state === 'running' ? 'running' : 'ok'} · ${label}${sub.summary === '' ? '' : ` · ${sub.summary}`}`)
63
+ }
64
+ if (entry.subsDropped > 0) out.push(`- dispatch: … ${entry.subsDropped} earlier dispatch${entry.subsDropped === 1 ? '' : 'es'}`)
65
+ }
66
+ if (entry.summary !== '') out.push(`- ${entry.state === 'error' ? 'error' : 'result'}: ${entry.summary}`)
67
+ out.push('')
68
+ break
69
+ case 'command':
70
+ out.push(`### /${entry.name}${entry.args === '' ? '' : ` ${entry.args}`}`, '')
71
+ if (entry.summary !== '') out.push(`- ${entry.state === 'error' ? 'error' : 'result'}: ${entry.summary}`)
72
+ out.push('')
73
+ break
74
+ case 'error':
75
+ out.push(`> ⨯ ${entry.text}`, '')
76
+ break
77
+ case 'turn-marker':
78
+ out.push(`> ${entry.text}`, '')
79
+ break
80
+ case 'compaction':
81
+ out.push(entry.ok
82
+ ? `> compacted ~${entry.tokens} tokens`
83
+ : `> compaction failed: ${entry.error}`, '')
84
+ break
85
+ case 'retry':
86
+ out.push(`> retry ${entry.attempt}/${entry.max} (${entry.code})`, '')
87
+ break
88
+ case 'files':
89
+ out.push(`> files changed: ${entry.paths.join(', ')}`, '')
90
+ break
91
+ case 'workflow':
92
+ out.push(`### workflow \`${entry.name}\` (${entry.state})`, '')
93
+ for (const member of entry.members) {
94
+ const phase = member.phase === '' ? '' : ` [${member.phase}]`
95
+ out.push(`- ${member.outcome}: ${member.label}${phase}`)
96
+ }
97
+ if (entry.membersDropped > 0) out.push(`- … ${entry.membersDropped} earlier member${entry.membersDropped === 1 ? '' : 's'}`)
98
+ out.push('')
99
+ break
100
+ case 'pending':
101
+ // Codex PendingSteer: queued prompts export like ordinary user rows.
102
+ out.push('## user', '', entry.text, ...(attachmentLabels(entry) === '' ? [] : [attachmentLabels(entry)]), '')
103
+ break
104
+ default:
105
+ assertNever(entry, 'transcript entry kind')
106
+ }
107
+ }
108
+ if (view.streaming !== '') out.push('## assistant (streaming)', '', view.streaming, '')
109
+ const { stats } = view
110
+ out.push('---', '')
111
+ out.push(`- model: ${view.model === '' ? '(none yet)' : view.model}`)
112
+ out.push(`- turns: ${stats.turns} · steps: ${stats.steps}`)
113
+ out.push(`- tokens: ↑${stats.usage.uncachedInputTokens} ↓${stats.usage.outputTokens} · cache read ${stats.usage.cacheReadTokens} · cache write ${stats.usage.cacheWriteTokens}`)
114
+ out.push(`- todos: ${view.todos.length}`)
115
+ return out.join('\n')
116
+ }
@@ -24,6 +24,48 @@ export function layoutGutterRows(rows: number): 0 | 1 {
24
24
  return Math.max(1, Math.floor(rows)) >= 14 ? 1 : 0
25
25
  }
26
26
 
27
+ /** Measured chrome that sits below (or in) the live region. */
28
+ export interface LiveRegionChrome {
29
+ /** Terminal rows. */
30
+ readonly terminalRows: number
31
+ /** Editor rows inside the composer band (frozen reports 1). */
32
+ readonly composerRows: number
33
+ /** Status footer rows. */
34
+ readonly statusBarRows: 1 | 2
35
+ /** Completion menu rows (0 when closed). */
36
+ readonly menuRows: number
37
+ /** Transcript-to-composer gutter. */
38
+ readonly gutterRows: 0 | 1
39
+ /** Notice line present. */
40
+ readonly notice: boolean
41
+ /** Todo summary line present. */
42
+ readonly todo: boolean
43
+ /** Agents summary line present. */
44
+ readonly agents: boolean
45
+ }
46
+
47
+ /**
48
+ * Rows left for live transcript and streaming after pinning the composer and
49
+ * status at the bottom. Variable chrome (menu, notice, todos, agents, extra
50
+ * status row, extra editor rows) is deducted here so those rows cover the
51
+ * live region instead of growing the tree and moving the bottom bar.
52
+ */
53
+ export function liveRegionBudget(chrome: LiveRegionChrome): number {
54
+ const terminal = Math.max(1, Math.floor(chrome.terminalRows))
55
+ const editor = Math.max(1, Math.floor(chrome.composerRows))
56
+ const band = editor + 2
57
+ const status = chrome.statusBarRows === 2 ? 2 : 1
58
+ const menu = Math.max(0, Math.floor(chrome.menuRows))
59
+ const gutter = chrome.gutterRows
60
+ const notice = chrome.notice ? 1 : 0
61
+ const todo = chrome.todo ? 1 : 0
62
+ const agents = chrome.agents ? 1 : 0
63
+ // Two spare rows: Ink's parked cursor, plus one so the painted tree never
64
+ // reaches stdout.rows (equality takes the full-terminal clear path).
65
+ const inkSpare = 2
66
+ return Math.max(1, terminal - band - status - menu - gutter - notice - todo - agents - inkSpare)
67
+ }
68
+
27
69
  /**
28
70
  * Keep the inspector plus its persistent status/composer chrome below
29
71
  * `stdout.rows`: at equality Ink clears the terminal and rewrites all