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,117 @@
1
+ /** Slash-command parsing and completion candidates shared by the composer and help panel. */
2
+
3
+ import type { CommandDescriptor } from '@deepseek-ai/dsh-commands'
4
+ import { t, type MessageKey } from './i18n.ts'
5
+ import { rankByName } from './render/fuzzy.ts'
6
+ import type { SkillRow } from './skills.ts'
7
+
8
+ /** One TUI-owned slash command: label plus its i18n description key. */
9
+ export interface LocalCommand {
10
+ readonly label: string
11
+ readonly descriptionKey: MessageKey
12
+ }
13
+
14
+ /** One source of truth for TUI-owned slash commands in completion and `/help`. */
15
+ export const LOCAL_COMMANDS: readonly LocalCommand[] = [
16
+ { label: '/help', descriptionKey: 'cmd.help' },
17
+ { label: '/model', descriptionKey: 'cmd.model' },
18
+ { label: '/effort', descriptionKey: 'cmd.effort' },
19
+ { label: '/mode', descriptionKey: 'cmd.mode' },
20
+ { label: '/permission', descriptionKey: 'cmd.permission' },
21
+ { label: '/new', descriptionKey: 'cmd.new' },
22
+ { label: '/fork', descriptionKey: 'cmd.fork' },
23
+ { label: '/resume', descriptionKey: 'cmd.resume' },
24
+ { label: '/search', descriptionKey: 'cmd.search' },
25
+ { label: '/plugin', descriptionKey: 'cmd.plugin' },
26
+ { label: '/update', descriptionKey: 'cmd.update' },
27
+ { label: '/jobs', descriptionKey: 'cmd.jobs' },
28
+ { label: '/schedule', descriptionKey: 'cmd.schedule' },
29
+ { label: '/statusline', descriptionKey: 'cmd.statusline' },
30
+ { label: '/theme', descriptionKey: 'cmd.theme' },
31
+ { label: '/language', descriptionKey: 'cmd.language' },
32
+ { label: '/rainbow', descriptionKey: 'cmd.rainbow' },
33
+ { label: '/animation', descriptionKey: 'cmd.animation' },
34
+ { label: '/history', descriptionKey: 'cmd.history' },
35
+ { label: '/queue', descriptionKey: 'cmd.queue' },
36
+ { label: '/usage', descriptionKey: 'cmd.usage' },
37
+ { label: '/agents', descriptionKey: 'cmd.agents' },
38
+ { label: '/todos', descriptionKey: 'cmd.todos' },
39
+ { label: '/subagent', descriptionKey: 'cmd.subagent' },
40
+ { label: '/vscode-keys', descriptionKey: 'cmd.vscode-keys' },
41
+ { label: '/delete', descriptionKey: 'cmd.delete' },
42
+ { label: '/clear', descriptionKey: 'cmd.clear' },
43
+ { label: '/export', descriptionKey: 'cmd.export' },
44
+ { label: '/title', descriptionKey: 'cmd.title' },
45
+ { label: '/copy', descriptionKey: 'cmd.copy' },
46
+ { label: '/diff', descriptionKey: 'cmd.diff' },
47
+ { label: '/review', descriptionKey: 'cmd.review' },
48
+ { label: '/quit', descriptionKey: 'cmd.quit' },
49
+ ] as const
50
+
51
+ export const LOCAL_COMMAND_NAMES: ReadonlySet<string> = new Set(LOCAL_COMMANDS.map(command => command.label.slice(1)))
52
+
53
+ /** TUI-local commands that reject trailing input instead of forwarding it as a prompt. */
54
+ export const BARE_LOCAL_COMMANDS: ReadonlySet<string> = new Set([
55
+ 'quit', 'help', 'clear', 'copy', 'update', 'schedule', 'statusline', 'theme',
56
+ 'history', 'queue', 'usage', 'agents', 'todos', 'subagent',
57
+ ])
58
+
59
+ /** Split a slash line into the command name and any trailing input. */
60
+ export function slashNameAndArgs(text: string): { readonly name: string; readonly args: string } | undefined {
61
+ const match = /^\/([a-z][a-z0-9_-]*)(?:$|[\t ](.*))$/u.exec(text)
62
+ if (match === null || match[1] === undefined) return undefined
63
+ return { name: match[1], args: (match[2] ?? '').trim() }
64
+ }
65
+
66
+ /** One completion candidate row. */
67
+ export interface CompletionCandidate {
68
+ readonly label: string
69
+ readonly description: string
70
+ readonly origin: 'command' | 'skill' | 'mention'
71
+ }
72
+
73
+ /** Wrap one completion-menu cursor step; an empty menu keeps the index at zero. */
74
+ export function stepCompletionIndex(index: number, delta: number, count: number): number {
75
+ if (count <= 0) return 0
76
+ return ((index + delta) % count + count) % count
77
+ }
78
+
79
+ /** Merge local commands, registry descriptors, and skills using dispatch shadowing order. */
80
+ export function completionCandidates(
81
+ value: string,
82
+ descriptors: readonly CommandDescriptor[],
83
+ skills: readonly SkillRow[],
84
+ ): readonly CompletionCandidate[] {
85
+ if (!value.startsWith('/')) return []
86
+ const prefix = value.slice(1).split(' ')[0] ?? ''
87
+ const local: CompletionCandidate[] = LOCAL_COMMANDS.map(command => ({
88
+ label: command.label,
89
+ description: t(command.descriptionKey),
90
+ origin: 'command',
91
+ }))
92
+ const registry = descriptors
93
+ .filter(descriptor => !LOCAL_COMMAND_NAMES.has(descriptor.name))
94
+ .map((descriptor): CompletionCandidate => ({
95
+ label: `/${descriptor.name}`,
96
+ description: descriptor.description,
97
+ origin: 'command',
98
+ }))
99
+ const taken = new Set([...local, ...registry].map(candidate => candidate.label.slice(1)))
100
+ const skillRows = skills
101
+ .filter(skill => !taken.has(skill.name))
102
+ .map((skill): CompletionCandidate => ({
103
+ label: `/${skill.name}`,
104
+ description: skill.modelInvocable ? `skill · ${skill.description}` : `skill (user only) · ${skill.description}`,
105
+ origin: 'skill',
106
+ }))
107
+ const seen = new Set<string>()
108
+ const all: CompletionCandidate[] = []
109
+ for (const candidate of [...local, ...registry, ...skillRows]) {
110
+ const name = candidate.label.slice(1)
111
+ if (seen.has(name)) continue
112
+ seen.add(name)
113
+ all.push(candidate)
114
+ }
115
+ return rankByName(all.map(candidate => ({ name: candidate.label.slice(1), candidate })), prefix)
116
+ .map(entry => entry.candidate)
117
+ }