@antst/dashi 0.1.0-alpha.18 → 0.1.0-alpha.19

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 (55) hide show
  1. package/README.md +5 -5
  2. package/package.json +38 -39
  3. package/lib/application.d.ts +0 -45
  4. package/lib/application.js +0 -273
  5. package/lib/at-trigger.d.ts +0 -8
  6. package/lib/at-trigger.js +0 -13
  7. package/lib/catalogs.d.ts +0 -28
  8. package/lib/catalogs.js +0 -308
  9. package/lib/clipboard-image.d.ts +0 -3
  10. package/lib/clipboard-image.js +0 -74
  11. package/lib/completion-trigger.d.ts +0 -6
  12. package/lib/completion-trigger.js +0 -19
  13. package/lib/diff-view.d.ts +0 -5
  14. package/lib/diff-view.js +0 -30
  15. package/lib/external-editor.d.ts +0 -3
  16. package/lib/external-editor.js +0 -39
  17. package/lib/help.d.ts +0 -2
  18. package/lib/help.js +0 -6
  19. package/lib/history-records.d.ts +0 -4
  20. package/lib/history-records.js +0 -4
  21. package/lib/image-input.d.ts +0 -8
  22. package/lib/image-input.js +0 -37
  23. package/lib/index.d.ts +0 -4
  24. package/lib/index.js +0 -329
  25. package/lib/input.d.ts +0 -17
  26. package/lib/input.js +0 -267
  27. package/lib/memory.d.ts +0 -3
  28. package/lib/memory.js +0 -27
  29. package/lib/mouse-input.d.ts +0 -1
  30. package/lib/mouse-input.js +0 -6
  31. package/lib/presentation.d.ts +0 -9
  32. package/lib/presentation.js +0 -54
  33. package/lib/renderer.d.ts +0 -21
  34. package/lib/renderer.js +0 -491
  35. package/lib/rewind.d.ts +0 -31
  36. package/lib/rewind.js +0 -114
  37. package/lib/session-export.d.ts +0 -3
  38. package/lib/session-export.js +0 -27
  39. package/lib/session-list.d.ts +0 -15
  40. package/lib/session-list.js +0 -65
  41. package/lib/session-runtime.d.ts +0 -49
  42. package/lib/session-runtime.js +0 -1492
  43. package/lib/shell-command.d.ts +0 -10
  44. package/lib/shell-command.js +0 -66
  45. package/lib/state.d.ts +0 -517
  46. package/lib/state.js +0 -685
  47. package/lib/terminal-guard.d.ts +0 -14
  48. package/lib/terminal-guard.js +0 -76
  49. package/lib/tool-presentation.d.ts +0 -14
  50. package/lib/tool-presentation.js +0 -156
  51. package/lib/transcript.d.ts +0 -14
  52. package/lib/transcript.js +0 -336
  53. package/lib/tui-root.d.ts +0 -20
  54. package/lib/tui-root.js +0 -25
  55. package/validated-dsh-versions.json +0 -3
package/lib/catalogs.js DELETED
@@ -1,308 +0,0 @@
1
- import { readdir, readFile } from 'node:fs/promises';
2
- import { join } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import { formatFileMention } from '@deepseek-ai/dsh-file-reference/grammar';
5
- import { isUserInvocable } from '@deepseek-ai/dsh-skill';
6
- import { detectAtTrigger } from './at-trigger.js';
7
- import { pluginCompletionQuery, slashCompletionQuery } from './completion-trigger.js';
8
- import { isImagePath } from './image-input.js';
9
- import { sessionTitle } from './session-list.js';
10
- function matchRank(name, query) {
11
- const candidate = name.toLocaleLowerCase();
12
- const needle = query.toLocaleLowerCase();
13
- return candidate.startsWith(needle) ? 0 : candidate.includes(needle) ? 1 : 2;
14
- }
15
- function selectedModel(ctx, agent) {
16
- const selection = ctx.sessionProjections.snapshot(agent.session, ['modelSelection']).values.modelSelection;
17
- return selection?.next ?? selection?.lastUsed ?? undefined;
18
- }
19
- /** Build command and skill completion rows for one exact root. */
20
- export async function completionOptions(ctx, agent, input, caret = input.length, signal) {
21
- const plugin = pluginCompletionQuery(input, caret);
22
- if (plugin !== undefined) {
23
- let candidates = ['add', 'remove', 'update', 'outdated', 'list', 'why', 'exec', 'licenses'];
24
- if (plugin.command !== undefined) {
25
- const profile = fileURLToPath(new URL('.', ctx.baseUrl));
26
- if (plugin.command === 'exec') {
27
- candidates = (await readdir(join(profile, 'node_modules', '.bin')).catch((error) => error.code === 'ENOENT' ? [] : Promise.reject(error))).sort();
28
- }
29
- else {
30
- const manifest = JSON.parse(await readFile(join(profile, 'package.json'), 'utf8'));
31
- candidates = Object.keys(manifest.dependencies ?? {}).sort();
32
- }
33
- }
34
- return candidates.filter(name => matchRank(name, plugin.query) < 2).map(name => ({
35
- group: 'Commands', label: name,
36
- value: { kind: 'insert', text: `/plugin ${plugin.command === undefined ? '' : `${plugin.command} `}${name} ` },
37
- }));
38
- }
39
- const at = detectAtTrigger(input, caret);
40
- if (at !== undefined) {
41
- const service = ctx.get('fileReferences');
42
- if (service === undefined)
43
- return [];
44
- const candidates = await service.list(agent, at.query, signal ?? new AbortController().signal);
45
- return candidates.flatMap((candidate) => {
46
- const mention = formatFileMention(candidate, at.quoted);
47
- if (mention === undefined)
48
- return [];
49
- const text = `${input.slice(0, at.start)}${mention}${input.slice(at.end)}`;
50
- const image = candidate.kind === 'file' && isImagePath(candidate.path);
51
- return [{
52
- detail: candidate.kind === 'directory' ? 'directory' : image ? 'attach image' : 'file',
53
- group: 'Files',
54
- label: `${candidate.path}${candidate.kind === 'directory' ? '/' : ''}`,
55
- value: image
56
- ? {
57
- kind: 'attach',
58
- path: candidate.path,
59
- source: input,
60
- text: `${input.slice(0, at.start)}${input.slice(at.end)}`,
61
- }
62
- : { kind: 'insert', text },
63
- }];
64
- });
65
- }
66
- const query = slashCompletionQuery(input);
67
- if (query === undefined)
68
- return [];
69
- const commands = ctx.commands.list(agent)
70
- .filter(command => matchRank(command.name, query) < 2)
71
- .sort((left, right) => matchRank(left.name, query) - matchRank(right.name, query)
72
- || left.name.localeCompare(right.name))
73
- .map(command => ({
74
- detail: command.description,
75
- group: 'Commands',
76
- label: `/${command.name}${command.input?.hint === undefined ? '' : ` ${command.input.hint}`}`,
77
- ...(command.input?.hint === undefined ? { submitOnEnter: true } : {}),
78
- value: { kind: 'insert', text: `/${command.name} ` },
79
- }));
80
- const skills = (await ctx.skills.list({ cwd: agent.session.header.cwd, scope: agent, signal }))
81
- .filter(isUserInvocable)
82
- .filter(skill => matchRank(skill.name, query) < 2)
83
- .sort((left, right) => matchRank(left.name, query) - matchRank(right.name, query)
84
- || left.name.localeCompare(right.name))
85
- .map(skill => ({
86
- detail: skill.description,
87
- group: 'Skills',
88
- label: `/${skill.name}`,
89
- value: { kind: 'insert', text: `/${skill.name} ` },
90
- }));
91
- return [...commands, ...skills];
92
- }
93
- /** Build a filtered view of the skills resolved for one live session. */
94
- export async function skillOverlay(ctx, agent, filter, signal) {
95
- const lookup = { cwd: agent.session.header.cwd, scope: agent, signal };
96
- const needle = filter.trim().toLocaleLowerCase();
97
- const skills = (await ctx.skills.list(lookup)).filter(skill => needle === ''
98
- || skill.name.toLocaleLowerCase().includes(needle)
99
- || skill.description.toLocaleLowerCase().includes(needle));
100
- const definitions = await Promise.all(skills.map(skill => ctx.skills.get(skill.name, lookup)));
101
- return {
102
- cursor: 0, kind: 'list', purpose: 'skills', title: needle === '' ? 'Skills' : `Skills · ${filter.trim()}`,
103
- options: skills.map((skill, index) => ({
104
- detail: `${skill.description} · user ${skill.invocation.userInvocable ? 'yes' : 'no'} · model ${skill.invocation.modelInvocable ? 'yes' : 'no'} · source ${skill.source} · provider ${skill.provider} · path ${definitions[index]?.path ?? 'unavailable'}`,
105
- label: `/${skill.name}`,
106
- value: { kind: 'insert', text: `/${skill.name} ` },
107
- })),
108
- };
109
- }
110
- /** Build the cold session picker without adopting any candidate. */
111
- export function sessionOverlay(items, currentId, cwd) {
112
- return {
113
- cursor: 0,
114
- kind: 'list',
115
- options: items.filter(item => item.origin === undefined && (cwd === undefined || item.cwd === cwd)).map(item => ({
116
- active: String(item.sessionId) === currentId,
117
- detail: `${item.cwd ?? 'cwd unavailable'} · ${new Date(item.updatedAt).toISOString()}`,
118
- label: `${sessionTitle(item) ?? 'Untitled'} · ${String(item.sessionId)}`,
119
- value: { kind: 'resume', sessionId: String(item.sessionId) },
120
- })),
121
- purpose: 'resume',
122
- title: 'Resume session',
123
- };
124
- }
125
- /** Flatten DSH's provider/model/effort catalog into one terminal picker. */
126
- export function modelOverlay(catalog, selected) {
127
- const options = [];
128
- for (const group of catalog.groups) {
129
- for (const model of group.models) {
130
- const efforts = model.reasoning?.efforts ?? [];
131
- if (efforts.length === 0) {
132
- options.push({
133
- active: selected?.provider === group.id && selected.model === model.id,
134
- label: `${group.name} · ${model.name}`,
135
- value: { kind: 'model', model: model.id, provider: group.id },
136
- ...(model.description === undefined ? {} : { detail: model.description }),
137
- });
138
- continue;
139
- }
140
- for (const effort of efforts) {
141
- options.push({
142
- active: selected?.provider === group.id && selected.model === model.id
143
- && (selected.reasoningEffort ?? model.reasoning?.defaultEffort) === effort.id,
144
- label: `${group.name} · ${model.name} · ${effort.name}`,
145
- value: { kind: 'model', effort: effort.id, model: model.id, provider: group.id },
146
- ...(effort.description ?? model.description) === undefined
147
- ? {} : { detail: effort.description ?? model.description },
148
- });
149
- }
150
- }
151
- }
152
- return { cursor: Math.max(0, options.findIndex(option => option.active === true)), kind: 'list', options, purpose: 'model', title: 'Model' };
153
- }
154
- /** Build the preset picker from the native preset service. */
155
- export function permissionOverlay(ctx, agent) {
156
- const current = ctx.permissionPresets.current(agent.session);
157
- const options = ctx.permissionPresets.names.map((preset) => {
158
- const option = ctx.permissionPresets.optionOf(preset);
159
- const spec = ctx.permissionPresets.resolve(preset);
160
- return {
161
- active: preset === current,
162
- confirmDetail: [`Sandbox: ${spec.sandbox}`, `Approval: ${spec.approval}`],
163
- danger: spec.approval === 'never',
164
- label: option.name,
165
- value: { kind: 'permission', preset },
166
- ...(option.description === undefined ? {} : { detail: option.description }),
167
- };
168
- });
169
- return {
170
- cursor: Math.max(0, options.findIndex(option => option.active)),
171
- kind: 'list', options, purpose: 'permission', title: 'Permission preset',
172
- };
173
- }
174
- function number(value) {
175
- return typeof value === 'number' ? value.toLocaleString('en-US') : 'unavailable';
176
- }
177
- function milliseconds(value) {
178
- return typeof value === 'number' ? `${number(value)} ms` : 'unavailable';
179
- }
180
- function compactTokens(value) {
181
- return Intl.NumberFormat('en-US', { maximumFractionDigits: 1, notation: 'compact' }).format(value).replace('K', 'k');
182
- }
183
- export function sessionStatusLine(ctx, agent, root, repo) {
184
- const { modelSelection, permissions, tokenUsage, contextPressure } = ctx.sessionProjections
185
- .snapshot(agent.session, ['modelSelection', 'permissions', 'tokenUsage', 'contextPressure']).values;
186
- const model = modelSelection?.next ?? modelSelection?.lastUsed;
187
- const input = tokenUsage === undefined ? 0 : tokenUsage.uncachedInputTokens + tokenUsage.cacheReadTokens + tokenUsage.cacheWriteTokens;
188
- const total = input + (tokenUsage?.outputTokens ?? 0);
189
- const used = contextPressure?.projectedTokens ?? contextPressure?.pressureTokens;
190
- const context = used === undefined ? undefined
191
- : contextPressure?.contextWindow === undefined ? `ctx ${compactTokens(used)}`
192
- : `ctx ${compactTokens(used)}/${compactTokens(contextPressure.contextWindow)} ${String(Math.min(100, Math.round(used / contextPressure.contextWindow * 100)))}%`;
193
- const agents = root.subagents?.filter(item => item.state === 'running').length ?? 0;
194
- const jobs = root.jobs?.filter(item => item.status === 'running' || item.status === 'stopping').length ?? 0;
195
- return [
196
- model?.model ?? root.model,
197
- ...(model?.reasoningEffort === undefined ? [] : [model.reasoningEffort]),
198
- permissions?.currentValue ?? root.permission ?? 'unknown',
199
- ...(context === undefined ? [] : [context]),
200
- ...(input === 0 ? [] : [`cache ${String(Math.min(tokenUsage?.cacheReadTokens === input ? 100 : 99, Math.round((tokenUsage?.cacheReadTokens ?? 0) / input * 100)))}%`]),
201
- ...(tokenUsage === undefined ? [] : [`${compactTokens(total)} tok`]),
202
- ...(agents === 0 ? [] : [`${String(agents)} agents`]),
203
- ...(jobs === 0 ? [] : [`${String(jobs)} jobs`]),
204
- ...(root.title === undefined ? [] : [root.title]),
205
- ...(repo === undefined ? [] : [repo]),
206
- ].join(' · ');
207
- }
208
- /** Read DSH-owned root facts for /status in one projection cut. */
209
- export function statusOverlay(ctx, agent, root) {
210
- const values = ctx.sessionProjections.snapshot(agent.session, [
211
- 'modelSelection', 'permissions', 'tokenUsage', 'contextPressure', 'contextBreakdown',
212
- ]).values;
213
- const model = values.modelSelection?.next ?? values.modelSelection?.lastUsed;
214
- const usage = values.tokenUsage;
215
- const pressure = values.contextPressure;
216
- const breakdown = values.contextBreakdown;
217
- return {
218
- kind: 'info',
219
- lines: [
220
- `UUID: ${root.id}`,
221
- `Title: ${root.title ?? 'Untitled'}`,
222
- `Cwd: ${root.cwd}`,
223
- root.parent === undefined
224
- ? 'Lineage: root session'
225
- : `Lineage: forked from ${root.parent} at turn ${String(root.parentTurn ?? 'unknown')}`,
226
- `Model: ${model === null || model === undefined ? root.model : `${model.provider}/${model.model}`}`,
227
- `Effort: ${model?.reasoningEffort ?? root.effort ?? 'default'}`,
228
- `Permission: ${ctx.permissionPresets.current(agent.session)}`,
229
- `Usage: input ${number(usage?.uncachedInputTokens)} · output ${number(usage?.outputTokens)} · cache read ${number(usage?.cacheReadTokens)} · cache write ${number(usage?.cacheWriteTokens)}`,
230
- `Context: ${number(pressure?.projectedTokens)} / ${number(pressure?.contextWindow)} tokens`,
231
- `Composition: system ${number(breakdown?.systemTokens)} · tools ${number(breakdown?.toolsTokens)} · messages ${number(breakdown?.messageTokens)}`,
232
- ],
233
- title: 'Status',
234
- };
235
- }
236
- /** Show DSH's heuristic next-request composition without treating it as an exact total. */
237
- export function contextOverlay(ctx, agent) {
238
- const breakdown = ctx.sessionProjections.snapshot(agent.session, ['contextBreakdown'])
239
- .values.contextBreakdown;
240
- return {
241
- kind: 'info',
242
- lines: [
243
- `System prompt: ${number(breakdown?.systemTokens)} tokens`,
244
- `Tool schemas: ${number(breakdown?.toolsTokens)} tokens`,
245
- `Messages: ${number(breakdown?.messageTokens)} tokens`,
246
- 'These are DSH heuristic estimates for the next request, not a provider-reported total.',
247
- ],
248
- title: 'Context',
249
- };
250
- }
251
- /** Read DSH's whole-log token and timing projections without folding session history. */
252
- export function usageOverlay(ctx, agent) {
253
- const values = ctx.sessionProjections.snapshot(agent.session, ['tokenUsage', 'sessionStats']).values;
254
- const tokens = values.tokenUsage;
255
- const stats = values.sessionStats;
256
- const measured = stats === undefined ? undefined : stats.llmMs + stats.toolMs;
257
- return {
258
- kind: 'info',
259
- lines: [
260
- `Input tokens: ${number(tokens?.uncachedInputTokens)}`,
261
- `Output tokens: ${number(tokens?.outputTokens)}`,
262
- `Cache read: ${number(tokens?.cacheReadTokens)}`,
263
- `Cache write: ${number(tokens?.cacheWriteTokens)}`,
264
- `Turns: ${number(stats?.turns)} · Steps: ${number(stats?.steps)}`,
265
- `Model time: ${milliseconds(stats?.llmMs)}`,
266
- `Tool time: ${milliseconds(stats?.toolMs)}`,
267
- `Measured wall time: ${milliseconds(measured)}`,
268
- ],
269
- title: 'Usage',
270
- };
271
- }
272
- /** Build the native agent-preset picker; broken presets are visible elsewhere, not selectable here. */
273
- export function agentPresetOverlay(presets, current, blank) {
274
- const options = presets.filter(preset => preset.broken === undefined).map(preset => ({
275
- active: preset.id === current,
276
- label: preset.name ?? preset.id,
277
- value: { kind: 'agent-preset', preset: preset.id },
278
- ...(preset.description === undefined ? {} : { detail: preset.description }),
279
- }));
280
- return {
281
- cursor: Math.max(0, options.findIndex(option => option.active)),
282
- kind: 'list',
283
- notice: blank ? 'The current session is blank.' : 'Choosing a preset starts a new session.',
284
- options,
285
- purpose: 'agents',
286
- title: 'Agent preset',
287
- };
288
- }
289
- /** Build bounded same-cwd prompt-search rows from DSH query hits. */
290
- export function searchOverlay(items, rootId) {
291
- return {
292
- cursor: 0,
293
- kind: 'list',
294
- options: items.map(item => ({
295
- detail: `${String(item.header.id)} · ${item.header.cwd ?? 'cwd unavailable'}`,
296
- label: item.bestMatch.snippet.replaceAll(/\s+/gu, ' ').trim(),
297
- value: {
298
- kind: 'search-result', rootId, seq: item.bestMatch.seq,
299
- sessionId: String(item.header.id),
300
- },
301
- })),
302
- purpose: 'search',
303
- title: 'Prompt search',
304
- };
305
- }
306
- export function currentModel(ctx, agent) {
307
- return selectedModel(ctx, agent);
308
- }
@@ -1,3 +0,0 @@
1
- import type { DraftAttachment } from './state.js';
2
- /** Read a PNG from an installed platform clipboard helper. */
3
- export declare function readClipboardImage(platform?: NodeJS.Platform, path?: string): Promise<DraftAttachment>;
@@ -1,74 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
- import { draftImage } from './image-input.js';
3
- const APPLE_SCRIPT = `
4
- ObjC.import('AppKit')
5
- const pasteboard = $.NSPasteboard.generalPasteboard
6
- let data = pasteboard.dataForType('public.png')
7
- if (!data) {
8
- const tiff = pasteboard.dataForType('public.tiff')
9
- if (tiff) {
10
- const image = $.NSBitmapImageRep.imageRepWithData(tiff)
11
- if (image) data = image.representationUsingTypeProperties($.NSBitmapImageFileTypePNG, $())
12
- }
13
- }
14
- if (!data) $.exit(2)
15
- console.log(ObjC.unwrap(data.base64EncodedStringWithOptions(0)))
16
- `.trim();
17
- function capture(command, args, base64, path) {
18
- return new Promise((resolve, reject) => {
19
- const child = spawn(command, args, {
20
- ...(path === undefined ? {} : { env: { ...process.env, PATH: path } }),
21
- stdio: ['ignore', 'pipe', 'ignore'],
22
- });
23
- const chunks = [];
24
- child.stdout.on('data', (chunk) => { chunks.push(chunk); });
25
- child.once('error', error => {
26
- if (error.code === 'ENOENT')
27
- resolve({ found: false });
28
- else
29
- reject(error);
30
- });
31
- child.once('close', code => {
32
- if (code !== 0)
33
- return resolve({ found: true });
34
- const output = Buffer.concat(chunks);
35
- if (output.length === 0)
36
- return resolve({ found: true });
37
- if (!base64)
38
- return resolve({ found: true, output: new Uint8Array(output) });
39
- try {
40
- const decoded = Buffer.from(output.toString('utf8').trim(), 'base64');
41
- resolve({ found: true, ...(decoded.length === 0 ? {} : { output: new Uint8Array(decoded) }) });
42
- }
43
- catch (error) {
44
- reject(error);
45
- }
46
- });
47
- });
48
- }
49
- /** Read a PNG from an installed platform clipboard helper. */
50
- export async function readClipboardImage(platform = process.platform, path) {
51
- const attempts = platform === 'darwin'
52
- ? [
53
- ['pngpaste', ['-'], false],
54
- ['osascript', ['-l', 'JavaScript', '-e', APPLE_SCRIPT], true],
55
- ]
56
- : platform === 'linux'
57
- ? [
58
- ['wl-paste', ['--no-newline', '--type', 'image/png'], false],
59
- ['xclip', ['-selection', 'clipboard', '-t', 'image/png', '-o'], false],
60
- ]
61
- : [];
62
- let helperFound = false;
63
- for (const [command, args, base64] of attempts) {
64
- const result = await capture(command, args, base64, path);
65
- helperFound ||= result.found;
66
- if (result.output !== undefined)
67
- return draftImage(result.output, 'image/png', 'clipboard.png', 'clipboard');
68
- }
69
- if (attempts.length === 0)
70
- throw new Error('Clipboard image paste is supported on Linux and macOS.');
71
- throw new Error(helperFound
72
- ? 'The clipboard does not contain a PNG image.'
73
- : `Clipboard image paste needs ${platform === 'darwin' ? 'pngpaste or osascript' : 'wl-paste or xclip'}.`);
74
- }
@@ -1,6 +0,0 @@
1
- export declare function slashCompletionQuery(input: string): string | undefined;
2
- export declare function pluginCompletionQuery(input: string, caret: number): {
3
- readonly command?: string;
4
- readonly query: string;
5
- } | undefined;
6
- export declare function hasCompletionTrigger(input: string, caret: number): boolean;
@@ -1,19 +0,0 @@
1
- import { detectAtTrigger } from './at-trigger.js';
2
- export function slashCompletionQuery(input) {
3
- return /^\/([a-z0-9_-]*)$/u.exec(input)?.[1];
4
- }
5
- export function pluginCompletionQuery(input, caret) {
6
- if (caret !== input.length)
7
- return undefined;
8
- const match = /^\/plugin +([^\s]*)(?: +([^\s]*))?$/u.exec(input);
9
- if (match === null)
10
- return undefined;
11
- const command = match[1] ?? '';
12
- if (match[2] === undefined)
13
- return { query: command };
14
- return /^(?:exec|remove|update|why)$/u.test(command) ? { command, query: match[2] } : undefined;
15
- }
16
- export function hasCompletionTrigger(input, caret) {
17
- return slashCompletionQuery(input) !== undefined || pluginCompletionQuery(input, caret) !== undefined
18
- || detectAtTrigger(input, caret) !== undefined;
19
- }
@@ -1,5 +0,0 @@
1
- import type { Context } from '@deepseek-ai/cordis';
2
- import type { Agent } from '@deepseek-ai/dsh-agent';
3
- import type { Overlay } from './state.js';
4
- import { type ToolPresenter } from './tool-presentation.js';
5
- export declare function diffOverlay(ctx: Context, agent: Agent, presenter: ToolPresenter, mode: '' | 'turn', signal: AbortSignal): Promise<Overlay>;
package/lib/diff-view.js DELETED
@@ -1,30 +0,0 @@
1
- import { HUMAN_SHELL_STREAM_BYTES } from './shell-command.js';
2
- import { boundedBody } from './tool-presentation.js';
3
- import { foldCells } from './transcript.js';
4
- import { latestCompletedTurn } from './rewind.js';
5
- export async function diffOverlay(ctx, agent, presenter, mode, signal) {
6
- if (mode === 'turn') {
7
- const events = agent.session.snapshotEvents();
8
- const boundary = latestCompletedTurn(events);
9
- const end = boundary.atSeq === undefined ? -1 : events.findIndex(event => event.seq === boundary.atSeq);
10
- let start = end;
11
- while (start >= 0 && events[start]?.type !== 'turn/start')
12
- start--;
13
- const cells = (start < 0 ? [] : foldCells(events.slice(start, end + 1), presenter)).filter(cell => cell.pending !== true && cell.tool?.card === 'diff' && (cell.tool.diffs?.length ?? 0) > 0);
14
- return { cells, kind: 'info', lines: cells.length === 0 ? ['No write/edit changes in the last completed turn.'] : [],
15
- title: `Last completed turn diff${boundary.open ? ' · trailing turn open' : ''}` };
16
- }
17
- const command = 'git diff --no-ext-diff --no-color HEAD --';
18
- const result = await ctx.shell.run(ctx.shell.resolve({
19
- command, sandboxPolicy: ctx.sandboxPolicy.resolve({ session: agent.session }), signal,
20
- stdoutMaxBytes: HUMAN_SHELL_STREAM_BYTES, timeoutMs: 30_000, workdir: agent.session.header.cwd,
21
- }));
22
- const output = [result.stdout.text, result.stderr.text].filter(Boolean).join('\n');
23
- const cell = {
24
- key: 'diff:working', kind: result.exitCode === 0 ? 'tool' : 'error', text: 'git diff',
25
- tool: { card: 'terminal', title: 'git diff', status: result.exitCode === 0 ? output === '' ? 'clean' : 'changed'
26
- : result.exitCode === null ? result.signal ?? 'failed' : `exit ${String(result.exitCode)}`,
27
- ...(output === '' ? {} : { body: boundedBody(output) }) },
28
- };
29
- return { cells: [cell], kind: 'info', lines: [], title: 'Working tree diff' };
30
- }
@@ -1,3 +0,0 @@
1
- export declare function runEditor(command: string, file: string, cwd: string): Promise<void>;
2
- /** Edit one draft through the user's terminal editor and always remove its file. */
3
- export declare function editDraftExternally(text: string, cwd: string): Promise<string>;
@@ -1,39 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
- import { mkdtemp, readFile, rm, rmdir, writeFile } from 'node:fs/promises';
3
- import { tmpdir } from 'node:os';
4
- import { join } from 'node:path';
5
- export function runEditor(command, file, cwd) {
6
- return new Promise((resolve, reject) => {
7
- const child = spawn('/bin/sh', ['-c', `exec ${command} "$1"`, 'dashi-editor', file], {
8
- cwd, stdio: 'inherit',
9
- });
10
- child.once('error', reject);
11
- child.once('exit', (code, signal) => {
12
- if (code === 0)
13
- resolve();
14
- else
15
- reject(new Error(`editor exited with ${code === null ? signal ?? 'unknown status' : `code ${String(code)}`}`));
16
- });
17
- });
18
- }
19
- /** Edit one draft through the user's terminal editor and always remove its file. */
20
- export async function editDraftExternally(text, cwd) {
21
- const command = process.env.VISUAL?.trim() || process.env.EDITOR?.trim();
22
- if (command === undefined || command === '')
23
- throw new Error('set $VISUAL or $EDITOR to use Ctrl+G');
24
- const directory = await mkdtemp(join(tmpdir(), 'dashi-editor-'));
25
- const file = join(directory, 'draft.md');
26
- try {
27
- await writeFile(file, text, { encoding: 'utf8', mode: 0o600 });
28
- await runEditor(command, file, cwd);
29
- return await readFile(file, 'utf8');
30
- }
31
- finally {
32
- try {
33
- await rm(file, { force: true });
34
- }
35
- finally {
36
- await rmdir(directory);
37
- }
38
- }
39
- }
package/lib/help.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export declare const VERSION_LINE: string;
2
- export declare const FLAG_HELP: readonly ["Launch flags: --inline | --fullscreen · --accessible · --verbose · -r, --resume [NAME|UUID] · -c, --continue · --fork-session · --all", " -n, --name TITLE · --agent PRESET · --session-id UUID · --model ID [--provider ID] · --effort LEVEL", " --permission PRESET · --tools NAMES · --disallowedTools NAMES · --yolo | --dangerously-skip-permissions · --image PATH", " --system-prompt TEXT | --system-prompt-file PATH · --append-system-prompt TEXT | --append-system-prompt-file PATH · -h, --help"];
package/lib/help.js DELETED
@@ -1,6 +0,0 @@
1
- import dashi from '../package.json' with { type: 'json' };
2
- import dsh from '@deepseek-ai/dsh-cmdline/package.json' with { type: 'json' };
3
- export const VERSION_LINE = `dashi ${dashi.version} on DSH ${dsh.version}`;
4
- export const FLAG_HELP = [
5
- 'Launch flags: --inline | --fullscreen · --accessible · --verbose · -r, --resume [NAME|UUID] · -c, --continue · --fork-session · --all', ' -n, --name TITLE · --agent PRESET · --session-id UUID · --model ID [--provider ID] · --effort LEVEL', ' --permission PRESET · --tools NAMES · --disallowedTools NAMES · --yolo | --dangerously-skip-permissions · --image PATH', ' --system-prompt TEXT | --system-prompt-file PATH · --append-system-prompt TEXT | --append-system-prompt-file PATH · -h, --help'
6
- ];
@@ -1,4 +0,0 @@
1
- import type { SessionHistoryRecord } from '@deepseek-ai/dsh-api-session-controller';
2
- import type { SessionEvent } from '@deepseek-ai/dsh-session';
3
- /** Read the Controller's canonical Session event history. */
4
- export declare function eventsFromRecords(records: readonly SessionHistoryRecord[]): SessionEvent[];
@@ -1,4 +0,0 @@
1
- /** Read the Controller's canonical Session event history. */
2
- export function eventsFromRecords(records) {
3
- return records.map(record => record.event);
4
- }
@@ -1,8 +0,0 @@
1
- import type { AttachmentStore, EncodedImageAttachment, ImageAttachmentRef, ImageMediaType } from '@deepseek-ai/dsh-attachment';
2
- import type { DraftAttachment } from './state.js';
3
- export declare function isImagePath(path: string): boolean;
4
- export declare function draftImage(data: Uint8Array, mediaType: ImageMediaType, name: string, path: string): DraftAttachment;
5
- /** Snapshot explicit user paths into one disposable composer draft. */
6
- export declare function readDraftImages(cwd: string, paths: readonly string[]): Promise<DraftAttachment[]>;
7
- export declare function encodeDraftImages(images: readonly DraftAttachment[]): EncodedImageAttachment[];
8
- export declare function admitDraftImages(attachments: AttachmentStore, images: readonly DraftAttachment[]): Promise<readonly ImageAttachmentRef[]>;
@@ -1,37 +0,0 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { basename, extname, resolve } from 'node:path';
3
- const MEDIA_TYPES = {
4
- '.gif': 'image/gif',
5
- '.jpeg': 'image/jpeg',
6
- '.jpg': 'image/jpeg',
7
- '.png': 'image/png',
8
- '.webp': 'image/webp',
9
- };
10
- export function isImagePath(path) {
11
- return MEDIA_TYPES[extname(path).toLocaleLowerCase()] !== undefined;
12
- }
13
- export function draftImage(data, mediaType, name, path) {
14
- return { bytes: data.byteLength, data, mediaType, name, path };
15
- }
16
- /** Snapshot explicit user paths into one disposable composer draft. */
17
- export async function readDraftImages(cwd, paths) {
18
- return Promise.all(paths.map(async (path) => {
19
- const absolute = resolve(cwd, path);
20
- const mediaType = MEDIA_TYPES[extname(absolute).toLocaleLowerCase()];
21
- if (mediaType === undefined) {
22
- throw new Error(`unsupported image extension for ${path}; accepted: .png, .jpg, .jpeg, .webp, .gif`);
23
- }
24
- const data = new Uint8Array(await readFile(absolute));
25
- return draftImage(data, mediaType, basename(absolute), absolute);
26
- }));
27
- }
28
- export function encodeDraftImages(images) {
29
- return images.map(image => ({
30
- data: Buffer.from(image.data).toString('base64'), mediaType: image.mediaType, name: image.name,
31
- }));
32
- }
33
- export function admitDraftImages(attachments, images) {
34
- return attachments.saveImages(images.map(image => ({
35
- data: image.data, mediaType: image.mediaType, name: image.name,
36
- })));
37
- }
package/lib/index.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import type { Context } from '@deepseek-ai/cordis';
2
- export declare const name = "dashi";
3
- export declare const inject: string[];
4
- export declare function apply(ctx: Context): void;