dsh-code 0.9.0 → 1.0.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 (59) hide show
  1. package/README.en.md +31 -8
  2. package/README.md +264 -241
  3. package/bin/deepseek.mjs +100 -6
  4. package/cordis.patch.yml +29 -1
  5. package/lib/index.mjs +2317 -708
  6. package/lib/startup.mjs +21 -11
  7. package/lib/{theme-BEi4i_aN.mjs → theme-DCT8Y2xf.mjs} +13 -9
  8. package/lib/types/app.d.ts +66 -14
  9. package/lib/types/attachments.d.ts +7 -0
  10. package/lib/types/editor.d.ts +6 -0
  11. package/lib/types/fork.d.ts +8 -0
  12. package/lib/types/git-workflow.d.ts +23 -0
  13. package/lib/types/index.d.ts +6 -0
  14. package/lib/types/kernel-panels.d.ts +39 -0
  15. package/lib/types/keyboard.d.ts +43 -0
  16. package/lib/types/mentions.d.ts +28 -38
  17. package/lib/types/presets.d.ts +1 -3
  18. package/lib/types/provider-settings.d.ts +16 -0
  19. package/lib/types/render/animations.d.ts +24 -41
  20. package/lib/types/render/editor.d.ts +137 -0
  21. package/lib/types/render/export.d.ts +1 -1
  22. package/lib/types/render/lines.d.ts +6 -2
  23. package/lib/types/render/markdown.d.ts +3 -1
  24. package/lib/types/render/projection.d.ts +29 -3
  25. package/lib/types/render/status.d.ts +5 -12
  26. package/lib/types/session-directory.d.ts +1 -3
  27. package/lib/types/startup.d.ts +14 -11
  28. package/lib/types/store.d.ts +11 -9
  29. package/lib/types/subagents.d.ts +3 -3
  30. package/lib/types/theme.d.ts +14 -1
  31. package/lib/types/version.d.ts +15 -2
  32. package/package.json +153 -117
  33. package/src/app.ts +4455 -3904
  34. package/src/attachments.ts +44 -0
  35. package/src/editor.ts +51 -0
  36. package/src/fork.ts +31 -0
  37. package/src/git-workflow.ts +87 -0
  38. package/src/index.ts +1510 -1374
  39. package/src/internals.ts +14 -1
  40. package/src/kernel-panels.ts +914 -798
  41. package/src/keyboard.ts +125 -0
  42. package/src/mentions.ts +72 -117
  43. package/src/presets.ts +1 -4
  44. package/src/provider-settings.ts +94 -0
  45. package/src/render/animations.ts +74 -60
  46. package/src/render/editor.ts +398 -0
  47. package/src/render/export.ts +79 -79
  48. package/src/render/lines.ts +342 -236
  49. package/src/render/markdown.ts +99 -26
  50. package/src/render/projection.ts +102 -19
  51. package/src/render/status.ts +713 -650
  52. package/src/render/text.ts +150 -150
  53. package/src/render/tool-detail.ts +3 -1
  54. package/src/session-directory.ts +3 -3
  55. package/src/startup.ts +136 -119
  56. package/src/store.ts +23 -11
  57. package/src/subagents.ts +13 -5
  58. package/src/theme.ts +214 -206
  59. package/src/version.ts +58 -1
package/bin/deepseek.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { spawn } from 'node:child_process'
3
+ import { spawn, spawnSync } from 'node:child_process'
4
4
  import { existsSync, readFileSync, realpathSync } from 'node:fs'
5
5
  import { createRequire } from 'node:module'
6
6
  import { homedir } from 'node:os'
@@ -8,10 +8,23 @@ import { join, resolve } from 'node:path'
8
8
  import { fileURLToPath, pathToFileURL } from 'node:url'
9
9
 
10
10
  const packageRequire = createRequire(import.meta.url)
11
+ const packageVersion = packageRequire('../package.json').version
11
12
 
12
13
  /** Arguments required to boot DSH-Code's conventional profile. */
13
14
  export const profileArgs = (args = []) => ['--profile', 'cli', ...args]
14
15
 
16
+ export const OPERATION_COMMANDS = ['setup', 'doctor', 'completion', 'update']
17
+
18
+ /** Exact first-day package spec used by setup (pnpm delays an unpinned release). */
19
+ export const setupBundle = (args = []) => args.includes('--local')
20
+ ? fileURLToPath(new URL('..', import.meta.url))
21
+ : `dsh-code@${packageVersion}`
22
+
23
+ /** Wrapper-owned operation, or undefined when arguments belong to the TUI. */
24
+ export function operationName(args = process.argv.slice(2)) {
25
+ return OPERATION_COMMANDS.includes(args[0]) ? args[0] : undefined
26
+ }
27
+
15
28
  /** The conventional cli profile directory under the DSH home. */
16
29
  export function cliProfileDir(home = homedir()) {
17
30
  return join(home, '.dsh', 'profiles', 'cli')
@@ -46,20 +59,20 @@ export function globalDshRoots() {
46
59
  }
47
60
 
48
61
  /** Resolve the DSH entrypoint without passing user arguments through a Windows shell. */
49
- export function dshCommand(args, {
62
+ export function rawDshCommand(args, {
50
63
  platform = process.platform,
51
64
  moduleUrl = import.meta.url,
52
65
  fileExists = existsSync,
53
66
  roots = globalDshRoots(),
54
67
  resolvePackage = packageRequire.resolve,
55
68
  } = {}) {
56
- if (platform !== 'win32') return { command: 'dsh', args: profileArgs(args) }
69
+ if (platform !== 'win32') return { command: 'dsh', args }
57
70
  const adjacentEntrypoint = fileURLToPath(new URL('../../@deepseek-ai/dsh/lib/bin.js', moduleUrl))
58
- if (fileExists(adjacentEntrypoint)) return { command: process.execPath, args: [adjacentEntrypoint, ...profileArgs(args)] }
71
+ if (fileExists(adjacentEntrypoint)) return { command: process.execPath, args: [adjacentEntrypoint, ...args] }
59
72
  for (const root of roots) {
60
73
  try {
61
74
  const entrypoint = resolvePackage('@deepseek-ai/dsh/lib/bin.js', { paths: [root] })
62
- return { command: process.execPath, args: [entrypoint, ...profileArgs(args)] }
75
+ return { command: process.execPath, args: [entrypoint, ...args] }
63
76
  } catch {
64
77
  // The next configured global prefix may own DSH instead.
65
78
  }
@@ -67,6 +80,86 @@ export function dshCommand(args, {
67
80
  return undefined
68
81
  }
69
82
 
83
+ /** Resolve the normal TUI boot command. */
84
+ export function dshCommand(args, options = {}) {
85
+ return rawDshCommand(profileArgs(args), options)
86
+ }
87
+
88
+ /** Static shell completion for wrapper commands and the TUI's local flags. */
89
+ export function completionScript(shell) {
90
+ const words = 'setup doctor completion update --help --version --resume --continue --session --mode --theme --image'
91
+ if (shell === 'bash') return `_deepseek_complete() { COMPREPLY=( $(compgen -W "${words}" -- "\${COMP_WORDS[COMP_CWORD]}") ); }\ncomplete -F _deepseek_complete deepseek dsh-code`
92
+ if (shell === 'zsh') return `#compdef deepseek dsh-code\n_arguments '1:command:(${words})'`
93
+ if (shell === 'powershell' || shell === 'pwsh') return `Register-ArgumentCompleter -Native -CommandName deepseek,dsh-code -ScriptBlock { param($wordToComplete) '${words}'.Split(' ') | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } }`
94
+ throw new Error('completion needs one shell: bash, zsh, or powershell')
95
+ }
96
+
97
+ function printDoctor(resolveCommand = rawDshCommand, spawnCommand = spawnSync) {
98
+ const checks = []
99
+ const [major, minor] = process.versions.node.split('.').map(Number)
100
+ checks.push({ ok: major > 22 || (major === 22 && minor >= 19), label: `Node ${process.versions.node}`, detail: 'requires ^22.19 or >=24' })
101
+ const command = resolveCommand(['--profile', 'cli', '--dump-config'])
102
+ checks.push({ ok: command !== undefined, label: '@deepseek-ai/dsh', detail: command === undefined ? 'not found beside dsh-code' : 'entrypoint resolved' })
103
+ checks.push({ ok: profileHasDshCode(), label: 'cli profile', detail: cliProfileDir() })
104
+ if (command !== undefined && profileHasDshCode()) {
105
+ const probe = spawnCommand(command.command, command.args, { encoding: 'utf8', windowsHide: true })
106
+ const output = String(probe.stdout ?? '')
107
+ checks.push({ ok: probe.status === 0 && output.includes('dsh-code'), label: 'composition', detail: probe.status === 0 ? 'dump-config contains dsh-code' : String(probe.stderr ?? '').trim() })
108
+ }
109
+ for (const check of checks) console.log(`${check.ok ? 'ok ' : 'fail'} ${check.label} - ${check.detail}`)
110
+ process.exitCode = checks.every(check => check.ok) ? 0 : 1
111
+ }
112
+
113
+ function launchChild(command, args) {
114
+ const child = spawn(command, args, { stdio: 'inherit' })
115
+ child.once('error', error => {
116
+ console.error(`dsh-code: command failed: ${error.message}`)
117
+ process.exitCode = 1
118
+ })
119
+ child.once('exit', (code, signal) => { process.exitCode = code ?? (signal === null ? 0 : 1) })
120
+ return child
121
+ }
122
+
123
+ /** Run one wrapper-owned operational command. */
124
+ export function launchOperation(args = process.argv.slice(2)) {
125
+ const operation = operationName(args)
126
+ if (operation === undefined) return undefined
127
+ if (operation === 'completion') {
128
+ try {
129
+ console.log(completionScript(args[1]))
130
+ } catch (error) {
131
+ console.error(`dsh-code: ${error.message}`)
132
+ process.exitCode = 1
133
+ }
134
+ return true
135
+ }
136
+ if (operation === 'doctor') {
137
+ printDoctor()
138
+ return true
139
+ }
140
+ if (operation === 'setup') {
141
+ // pnpm deliberately delays unpinned packages during their first 24 hours.
142
+ // Setup must mount the exact globally installed release on launch day.
143
+ const command = rawDshCommand(['plugin', '--profile', 'cli', 'add', setupBundle(args)])
144
+ if (command === undefined) {
145
+ console.error('dsh-code: @deepseek-ai/dsh is not installed; run: npm install -g @deepseek-ai/dsh dsh-code')
146
+ process.exitCode = 1
147
+ return true
148
+ }
149
+ return launchChild(command.command, command.args)
150
+ }
151
+ if (args.includes('--apply')) {
152
+ return launchChild(process.platform === 'win32' ? 'npm.cmd' : 'npm', ['install', '-g', '@deepseek-ai/dsh', 'dsh-code'])
153
+ }
154
+ const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'
155
+ for (const name of ['@deepseek-ai/dsh', 'dsh-code']) {
156
+ const result = spawnSync(npm, ['view', name, 'version'], { encoding: 'utf8', windowsHide: true })
157
+ console.log(`${name}: ${result.status === 0 ? String(result.stdout).trim() : 'version check failed'}`)
158
+ }
159
+ console.log('Run `deepseek update --apply` to install the latest versions.')
160
+ return true
161
+ }
162
+
70
163
  /** Launch the installed DSH CLI while preserving its exit status and stdio. */
71
164
  export function launchDsh(
72
165
  args = process.argv.slice(2),
@@ -101,5 +194,6 @@ export function launchDsh(
101
194
 
102
195
  const entrypoint = process.argv[1]
103
196
  if (entrypoint !== undefined && pathToFileURL(realpathSync(resolve(entrypoint))).href === import.meta.url) {
104
- launchDsh()
197
+ if (operationName() === undefined) launchDsh()
198
+ else launchOperation()
105
199
  }
package/cordis.patch.yml CHANGED
@@ -69,7 +69,14 @@
69
69
  - id: tool-todo
70
70
  disabled: true
71
71
  - id: tool-web
72
- disabled: true
72
+ config:
73
+ # web_fetch is a core TUI capability, not an opt-in: the fetch provider
74
+ # (web-fetch-http below) needs no API key. The per-preset tool-web rows
75
+ # keep `fetch: false` on the agent plane; through the scope-layered tool
76
+ # registry the preset's web_search shadows the host's same-name tool while
77
+ # the host's web_fetch stays visible, so every model still sees both.
78
+ fetch: true
79
+ searchTimeoutMs: 60000
73
80
 
74
81
  - insert:
75
82
  # Code Mode is a core execution capability, not a Web component.
@@ -82,6 +89,13 @@
82
89
  - id: session-reference
83
90
  name: '@deepseek-ai/dsh-session-reference'
84
91
 
92
+ # Workspace @file mention discovery: a bounded per-agent fuzzy index over
93
+ # the session cwd (directory listing, symlink guards, tool/result
94
+ # invalidation). The TUI's @ completion consumes ctx.fileReferences
95
+ # instead of running its own workspace scan.
96
+ - id: file-reference-local
97
+ name: '@deepseek-ai/dsh-file-reference-local'
98
+
85
99
  # The launcher supplies the shipped preset root beside its own config and
86
100
  # the service also discovers the user's local preset root.
87
101
  - id: agent-presets
@@ -89,6 +103,20 @@
89
103
  config:
90
104
  default: standard
91
105
 
106
+ # Cordis self-inspection (the shipped `cordis` agent preset's toolset):
107
+ # the host runner publishes the `dynamicCordisRunner`/`cordisInspect`
108
+ # services `tool-cordis` injects. Without this host row the preset mount
109
+ # fails ("1 row(s) did not activate: tool-cordis"), because models write
110
+ # composition through the agent plane but the runner is a host singleton.
111
+ - id: cordis-host-runner
112
+ name: '@deepseek-ai/dsh-cordis-host-runner'
113
+
114
+ # Anonymous public HTTP(S) fetch provider for web_fetch (no key): the web
115
+ # service and its search provider stay on the host plane (dsh-base), and
116
+ # this row is what makes fetching real URLs work out of the box.
117
+ - id: web-fetch-http
118
+ name: '@deepseek-ai/dsh-web-fetch-http'
119
+
92
120
  - id: tui-startup
93
121
  name: 'dsh-code/startup'
94
122