dsh-code 1.0.7 → 1.2.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.
- package/README.en.md +70 -24
- package/README.md +71 -25
- package/bin/deepseek.mjs +202 -39
- package/cordis.patch.yml +13 -4
- package/lib/index.mjs +4063 -844
- package/lib/session-query.mjs +3 -2
- package/lib/startup.mjs +4 -4
- package/lib/{theme-DCT8Y2xf.mjs → theme-7u5Qo3dF.mjs} +657 -20
- package/lib/types/app.d.ts +100 -63
- package/lib/types/authorization-panel.d.ts +3 -3
- package/lib/types/git-workflow.d.ts +91 -2
- package/lib/types/i18n.d.ts +39 -0
- package/lib/types/index.d.ts +73 -1
- package/lib/types/input-split.d.ts +1 -1
- package/lib/types/kernel-panels.d.ts +86 -31
- package/lib/types/language-panel.d.ts +12 -0
- package/lib/types/locales/en.d.ts +450 -0
- package/lib/types/locales/zh.d.ts +9 -0
- package/lib/types/mentions.d.ts +7 -3
- package/lib/types/models.d.ts +14 -0
- package/lib/types/panel-accent.d.ts +28 -0
- package/lib/types/rainbow.d.ts +69 -0
- package/lib/types/render/animations.d.ts +42 -0
- package/lib/types/render/inspector.d.ts +26 -0
- package/lib/types/render/lines.d.ts +21 -1
- package/lib/types/render/markdown.d.ts +1 -1
- package/lib/types/render/projection.d.ts +95 -4
- package/lib/types/render/status.d.ts +8 -8
- package/lib/types/render/text.d.ts +6 -0
- package/lib/types/render/usage.d.ts +113 -0
- package/lib/types/session-directory.d.ts +17 -0
- package/lib/types/startup.d.ts +1 -1
- package/lib/types/terminal-title.d.ts +8 -0
- package/lib/types/theme-panel.d.ts +2 -2
- package/lib/types/theme.d.ts +271 -52
- package/lib/types/update-panel.d.ts +5 -5
- package/lib/types/update.d.ts +10 -1
- package/lib/types/version.d.ts +4 -3
- package/package.json +24 -7
- package/src/app.ts +1155 -478
- package/src/approval.ts +166 -166
- package/src/authorization-panel.ts +19 -16
- package/src/editor-keys.ts +371 -371
- package/src/git-workflow.ts +229 -3
- package/src/i18n.ts +68 -0
- package/src/index.ts +412 -76
- package/src/input-split.ts +3 -3
- package/src/kernel-panels.ts +471 -89
- package/src/keyboard.ts +5 -4
- package/src/language-panel.ts +53 -0
- package/src/locales/en.ts +489 -0
- package/src/locales/zh.ts +488 -0
- package/src/mentions.ts +8 -4
- package/src/models.ts +264 -212
- package/src/panel-accent.ts +41 -0
- package/src/presets.ts +1 -1
- package/src/provider-settings.ts +1 -1
- package/src/rainbow.ts +208 -0
- package/src/render/animations.ts +104 -6
- package/src/render/editor.ts +20 -20
- package/src/render/export.ts +116 -95
- package/src/render/inspector.ts +42 -0
- package/src/render/lines.ts +628 -415
- package/src/render/markdown.ts +15 -3
- package/src/render/projection.ts +429 -19
- package/src/render/status.ts +41 -35
- package/src/render/text.ts +14 -0
- package/src/render/tool-preview.ts +77 -77
- package/src/render/usage.ts +430 -0
- package/src/render/width.ts +2 -2
- package/src/session-directory.ts +8 -6
- package/src/session-query.ts +8 -4
- package/src/startup.ts +3 -3
- package/src/subagents.ts +229 -229
- package/src/terminal-title.ts +22 -5
- package/src/theme-panel.ts +17 -21
- package/src/theme.ts +281 -33
- package/src/update-panel.ts +37 -27
- package/src/update.ts +19 -3
- package/src/version.ts +58 -20
- package/src/whale-glyph.ts +23 -23
package/src/render/export.ts
CHANGED
|
@@ -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
|
-
|
|
14
|
-
*
|
|
15
|
-
* @param
|
|
16
|
-
* @
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
out.push(
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (entry.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
out.push(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
out.push(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
+
}
|
package/src/render/inspector.ts
CHANGED
|
@@ -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
|