@antst/dashi 0.1.0-alpha.7 → 0.1.0-alpha.8
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/lib/application.js +9 -1
- package/lib/diff-view.d.ts +5 -0
- package/lib/diff-view.js +23 -0
- package/lib/external-editor.d.ts +1 -0
- package/lib/external-editor.js +1 -1
- package/lib/help.d.ts +2 -0
- package/lib/help.js +6 -0
- package/lib/index.js +8 -2
- package/lib/input.js +2 -0
- package/lib/memory.d.ts +3 -0
- package/lib/memory.js +27 -0
- package/lib/renderer.js +3 -1
- package/lib/session-runtime.js +92 -2
- package/lib/shell-command.d.ts +2 -1
- package/lib/shell-command.js +11 -8
- package/lib/state.d.ts +5 -1
- package/lib/state.js +5 -2
- package/lib/transcript.js +2 -1
- package/package.json +6 -1
package/lib/application.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createRenderer } from './renderer.js';
|
|
2
|
+
import { runEditor } from './external-editor.js';
|
|
2
3
|
import { initialViewState, reduce, } from './state.js';
|
|
3
4
|
import { createTerminalGuard } from './terminal-guard.js';
|
|
4
5
|
function suspendProcess() {
|
|
@@ -44,7 +45,14 @@ export function createTerminalShell(options) {
|
|
|
44
45
|
async function run(effect) {
|
|
45
46
|
switch (effect.type) {
|
|
46
47
|
case 'activate-overlay':
|
|
47
|
-
|
|
48
|
+
if (effect.value.kind === 'open-file') {
|
|
49
|
+
const path = effect.value.path;
|
|
50
|
+
await guard.withCookedTerminal(() => runEditor(process.env.EDITOR?.trim() || 'vi', path, options.cwd)).catch(error => {
|
|
51
|
+
dispatch({ type: 'runtime-error', message: error instanceof Error ? error.message : String(error) });
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else
|
|
55
|
+
await options.activateOverlay?.(effect.value);
|
|
48
56
|
return;
|
|
49
57
|
case 'attach': {
|
|
50
58
|
try {
|
|
@@ -0,0 +1,5 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { boundedBody } from './tool-presentation.js';
|
|
2
|
+
import { foldCells } from './transcript.js';
|
|
3
|
+
export async function diffOverlay(ctx, agent, presenter, mode, signal) {
|
|
4
|
+
if (mode === 'turn') {
|
|
5
|
+
const events = agent.session.snapshotEvents();
|
|
6
|
+
const start = events.map(event => event.type).lastIndexOf('turn/start');
|
|
7
|
+
const cells = (start < 0 ? [] : foldCells(events.slice(start), presenter)).filter(cell => cell.pending !== true && cell.tool?.card === 'diff' && (cell.tool.diffs?.length ?? 0) > 0);
|
|
8
|
+
return { cells, kind: 'info', lines: cells.length === 0 ? ['No write/edit changes in the last turn.'] : [], title: 'Last turn diff' };
|
|
9
|
+
}
|
|
10
|
+
const command = 'git diff --no-ext-diff --no-color HEAD --';
|
|
11
|
+
const result = await ctx.shell.run(ctx.shell.resolve({
|
|
12
|
+
command, sandboxPolicy: ctx.sandboxPolicy.resolve({ session: agent.session }), signal,
|
|
13
|
+
stdoutMaxBytes: 64 * 1024, timeoutMs: 30_000, workdir: agent.session.header.cwd,
|
|
14
|
+
}));
|
|
15
|
+
const output = [result.stdout.text, result.stderr.text].filter(Boolean).join('\n');
|
|
16
|
+
const cell = {
|
|
17
|
+
key: 'diff:working', kind: result.exitCode === 0 ? 'tool' : 'error', text: 'git diff',
|
|
18
|
+
tool: { card: 'terminal', title: 'git diff', status: result.exitCode === 0 ? output === '' ? 'clean' : 'changed'
|
|
19
|
+
: result.exitCode === null ? result.signal ?? 'failed' : `exit ${String(result.exitCode)}`,
|
|
20
|
+
...(output === '' ? {} : { body: boundedBody(output) }) },
|
|
21
|
+
};
|
|
22
|
+
return { cells: [cell], kind: 'info', lines: [], title: 'Working tree diff' };
|
|
23
|
+
}
|
package/lib/external-editor.d.ts
CHANGED
package/lib/external-editor.js
CHANGED
|
@@ -2,7 +2,7 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import { mkdtemp, readFile, rm, rmdir, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
function runEditor(command, file, cwd) {
|
|
5
|
+
export function runEditor(command, file, cwd) {
|
|
6
6
|
return new Promise((resolve, reject) => {
|
|
7
7
|
const child = spawn('/bin/sh', ['-c', `exec ${command} "$1"`, 'dashi-editor', file], {
|
|
8
8
|
cwd, stdio: 'inherit',
|
package/lib/help.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const VERSION_LINE: string;
|
|
2
|
+
export declare const FLAG_HELP: readonly ["Launch flags: --inline | --fullscreen · --accessible · -r, --resume [NAME|UUID] · -c, --continue · --all · --name TITLE", " --model ID [--provider ID] · --effort LEVEL · --permission PRESET", " --yolo | --dangerously-skip-permissions · --image PATH · -h, --help"];
|
package/lib/help.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
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 · -r, --resume [NAME|UUID] · -c, --continue · --all · --name TITLE', ' --model ID [--provider ID] · --effort LEVEL · --permission PRESET', ' --yolo | --dangerously-skip-permissions · --image PATH · -h, --help'
|
|
6
|
+
];
|
package/lib/index.js
CHANGED
|
@@ -6,13 +6,14 @@ import { createTerminalShell } from './application.js';
|
|
|
6
6
|
import { sessionOverlay } from './catalogs.js';
|
|
7
7
|
import { readClipboardImage } from './clipboard-image.js';
|
|
8
8
|
import { editDraftExternally } from './external-editor.js';
|
|
9
|
+
import { FLAG_HELP, VERSION_LINE } from './help.js';
|
|
9
10
|
import { formatSessionList, isSessionId, parseSessionListArgs, sessionMatches, sessionNotFound, } from './session-list.js';
|
|
10
11
|
import { createSessionRuntime } from './session-runtime.js';
|
|
11
12
|
import { TuiRoot } from './tui-root.js';
|
|
12
13
|
export const name = 'dashi';
|
|
13
14
|
export const inject = [
|
|
14
|
-
'agentPresets', 'agents', 'attachments', 'cmdlineArgs', 'commands', 'fs', '
|
|
15
|
-
'sandboxPolicy', 'sessionProjections', 'sessionQuery', 'sessions', 'shell', 'skills', 'tools',
|
|
15
|
+
'agentPresets', 'agents', 'attachments', 'cmdlineArgs', 'commands', 'fs', 'loader', 'permissionPresets',
|
|
16
|
+
'pluginInventory', 'sessionController', 'sandboxPolicy', 'sessionProjections', 'sessionQuery', 'sessions', 'settings', 'shell', 'skills', 'tools',
|
|
16
17
|
];
|
|
17
18
|
const validatedVersions = JSON.parse(readFileSync(new URL('../validated-dsh-versions.json', import.meta.url), 'utf8'));
|
|
18
19
|
function parseArgs(args) {
|
|
@@ -154,6 +155,11 @@ export function apply(ctx) {
|
|
|
154
155
|
throw new Error('dashi: the launcher must provide ctx.appExit, ctx.appReady, and ctx.cmdlineArgs');
|
|
155
156
|
}
|
|
156
157
|
const args = cmdline.get();
|
|
158
|
+
if (args.length === 1 && (args[0] === '--help' || args[0] === '-h')) {
|
|
159
|
+
process.stdout.write(`${VERSION_LINE}\n\nUsage: dashi [options] [prompt]\n\n${FLAG_HELP.join('\n')}\n`);
|
|
160
|
+
exit(0);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
157
163
|
if (args[0] === 'sessions') {
|
|
158
164
|
const options = parseSessionListArgs(args);
|
|
159
165
|
if (options === undefined) {
|
package/lib/input.js
CHANGED
|
@@ -102,6 +102,8 @@ export function installInput(tui, bindings) {
|
|
|
102
102
|
bindings.dispatch({ type: 'overlay-move', offset: -1 });
|
|
103
103
|
else if (matchesKey(data, 'down'))
|
|
104
104
|
bindings.dispatch({ type: 'overlay-move', offset: 1 });
|
|
105
|
+
else if (matchesKey(data, 'ctrl+o'))
|
|
106
|
+
bindings.dispatch({ type: 'toggle-tool-mode' });
|
|
105
107
|
else if (matchesKey(data, 'enter'))
|
|
106
108
|
bindings.dispatch({ type: 'overlay-submit', execute: true });
|
|
107
109
|
else if (matchesKey(data, 'tab'))
|
package/lib/memory.d.ts
ADDED
package/lib/memory.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths';
|
|
3
|
+
export function memoryOverlay(agent) {
|
|
4
|
+
const cwd = agent.session.header.cwd ?? process.cwd();
|
|
5
|
+
let root = cwd;
|
|
6
|
+
const active = new Map();
|
|
7
|
+
for (const seq of agent.session.surface.nodes) {
|
|
8
|
+
const event = agent.session.eventAt(seq);
|
|
9
|
+
if (event?.type !== 'user/message' || event.data.source.kind !== 'agent-instructions')
|
|
10
|
+
continue;
|
|
11
|
+
const source = event.data.source, identity = source.baselineIdentity === undefined
|
|
12
|
+
? undefined : JSON.parse(source.baselineIdentity);
|
|
13
|
+
if (typeof identity?.projectRoot === 'string')
|
|
14
|
+
root = resolve(cwd, identity.projectRoot);
|
|
15
|
+
for (const change of source.changes) {
|
|
16
|
+
if (change.action === 'remove')
|
|
17
|
+
active.delete(change.scope);
|
|
18
|
+
else
|
|
19
|
+
active.set(change.scope, { path: change.path, scope: change.scope.split('\0')[0] ?? change.scope });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return { cursor: 0, kind: 'list', options: [...active.values()].map(item => {
|
|
23
|
+
const homePath = /^(?:~\/\.dsh|\$DSH_HOME)\/(.*)$/u.exec(item.path)?.[1];
|
|
24
|
+
return { detail: `scope ${item.scope}`, label: item.path,
|
|
25
|
+
value: { kind: 'open-file', path: resolve(homePath === undefined ? root : resolveDshHome(), homePath ?? item.path) } };
|
|
26
|
+
}), purpose: 'memory', title: 'Memory' };
|
|
27
|
+
}
|
package/lib/renderer.js
CHANGED
|
@@ -268,9 +268,11 @@ export function createRenderer(options) {
|
|
|
268
268
|
if (overlay.kind === 'details')
|
|
269
269
|
return detailsPanel(overlay, state, width, rows);
|
|
270
270
|
if (overlay.kind === 'info') {
|
|
271
|
+
const cards = overlay.cells?.flatMap(cell => wrapTextWithAnsi(cellText(cell, state.toolMode, accessible), width)) ?? [];
|
|
271
272
|
return [
|
|
272
|
-
`${BOLD_CYAN}${announcement(plain(overlay.title), overlay.lines.length)}${RESET}`,
|
|
273
|
+
`${BOLD_CYAN}${announcement(plain(overlay.title), overlay.lines.length + (overlay.cells?.length ?? 0))}${RESET}`,
|
|
273
274
|
...overlay.lines.flatMap(value => wrapTextWithAnsi(plain(value, true), width)),
|
|
275
|
+
...cards,
|
|
274
276
|
`${DIM}Enter or Esc to close${RESET}`,
|
|
275
277
|
].slice(0, Math.max(2, rows - 3));
|
|
276
278
|
}
|
package/lib/session-runtime.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
2
2
|
import { SessionId, SessionSeq } from '@deepseek-ai/dsh-session';
|
|
3
3
|
import { agentPresetOverlay, completionOptions, contextOverlay, currentModel, modelOverlay, permissionOverlay, searchOverlay, sessionOverlay, statusOverlay, } from './catalogs.js';
|
|
4
|
+
import { diffOverlay } from './diff-view.js';
|
|
4
5
|
import { eventsFromRecords } from './history-records.js';
|
|
5
6
|
import { admitDraftImages, encodeDraftImages, readDraftImages } from './image-input.js';
|
|
6
7
|
import { contextPercent, jobViews, subagentViews } from './presentation.js';
|
|
7
8
|
import { humanPrompt, humanPrompts, inheritedTurn, rewindActionOverlay, rewindOverlay, } from './rewind.js';
|
|
8
9
|
import { createToolPresenter } from './tool-presentation.js';
|
|
9
|
-
import { runHumanShell } from './shell-command.js';
|
|
10
|
+
import { quoteShellWord, runHumanShell } from './shell-command.js';
|
|
10
11
|
import { markdownTranscript } from './session-export.js';
|
|
11
12
|
import { isSessionId, sessionMatches, sessionNotFound } from './session-list.js';
|
|
13
|
+
import { memoryOverlay } from './memory.js';
|
|
12
14
|
import { foldCells, pendingShellCells } from './transcript.js';
|
|
13
15
|
function detail(error) {
|
|
14
16
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -71,6 +73,17 @@ async function firstControl(iterator) {
|
|
|
71
73
|
function usage(raw, expected) {
|
|
72
74
|
return raw.trim() === '' ? undefined : { kind: 'error', text: `usage: ${expected}` };
|
|
73
75
|
}
|
|
76
|
+
function configValue(raw) {
|
|
77
|
+
try {
|
|
78
|
+
return JSON.parse(raw);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return raw;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function configLayer(value) {
|
|
85
|
+
return value === undefined ? '—' : JSON.stringify(value);
|
|
86
|
+
}
|
|
74
87
|
/** Create or resume the exact current root and own its replaceable terminal binding. */
|
|
75
88
|
export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, decisions) {
|
|
76
89
|
const lifetime = new AbortController();
|
|
@@ -491,6 +504,82 @@ export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, deci
|
|
|
491
504
|
return { kind: 'success' };
|
|
492
505
|
},
|
|
493
506
|
},
|
|
507
|
+
{
|
|
508
|
+
name: 'memory', description: 'Open an instruction file loaded by DSH',
|
|
509
|
+
handler: (invocation) => {
|
|
510
|
+
const invalid = ensureCurrent(invocation) ?? usage(invocation.rawInput, '/memory');
|
|
511
|
+
if (invalid !== undefined)
|
|
512
|
+
return invalid;
|
|
513
|
+
dispatch({ type: 'open-overlay', overlay: memoryOverlay(bound.agent) });
|
|
514
|
+
return { kind: 'success' };
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
name: 'config', description: 'Show or update native DSH settings', input: { hint: '[NAMESPACE KEY=VALUE]' },
|
|
519
|
+
handler: async (invocation) => {
|
|
520
|
+
const stale = ensureCurrent(invocation);
|
|
521
|
+
if (stale !== undefined)
|
|
522
|
+
return stale;
|
|
523
|
+
const raw = invocation.rawInput.trim();
|
|
524
|
+
if (raw === '')
|
|
525
|
+
return { kind: 'success', text: ctx.settings.describe({ redactSecrets: true }).map(item => `${String(item.ns)}\n value: ${configLayer(item.value)}\n base: ${configLayer(item.base)}\n user: ${configLayer(item.user)}`).join('\n') };
|
|
526
|
+
const match = /^(\S+)\s+([^\s=]+)=(.*)$/su.exec(raw);
|
|
527
|
+
if (match?.[1] === undefined || match[2] === undefined || match[3] === undefined) {
|
|
528
|
+
return { kind: 'error', text: 'usage: /config [NAMESPACE KEY=VALUE]' };
|
|
529
|
+
}
|
|
530
|
+
const value = configValue(match[3]);
|
|
531
|
+
if (match[2].includes('.'))
|
|
532
|
+
await ctx.settings.mutate(match[1], [{ op: 'set', path: match[2].split('.'), value }]);
|
|
533
|
+
else
|
|
534
|
+
await ctx.settings.update(match[1], { [match[2]]: value });
|
|
535
|
+
return { kind: 'success', text: `updated ${match[1]}.${match[2]}` };
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
name: 'diff', description: 'Show working tree or last-turn file changes', input: { hint: '[turn]' }, handler: async (invocation) => {
|
|
540
|
+
const invalid = ensureCurrent(invocation);
|
|
541
|
+
if (invalid !== undefined)
|
|
542
|
+
return invalid;
|
|
543
|
+
const mode = invocation.rawInput.trim();
|
|
544
|
+
if (mode !== '' && mode !== 'turn')
|
|
545
|
+
return { kind: 'error', text: 'usage: /diff [turn]' };
|
|
546
|
+
dispatch({ type: 'open-overlay', overlay: await diffOverlay(ctx, bound.agent, bound.presenter, mode, lifetime.signal) });
|
|
547
|
+
return { kind: 'success' };
|
|
548
|
+
},
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
name: 'plugins', description: 'List the running profile plugins',
|
|
552
|
+
handler: async (invocation) => {
|
|
553
|
+
const stale = ensureCurrent(invocation);
|
|
554
|
+
if (stale !== undefined)
|
|
555
|
+
return stale;
|
|
556
|
+
if (invocation.rawInput.trim() !== '')
|
|
557
|
+
return { kind: 'error', text: 'usage: /plugins' };
|
|
558
|
+
const servers = new Map();
|
|
559
|
+
for (const entry of ctx.loader.entries())
|
|
560
|
+
if (entry.options.name === '@deepseek-ai/dsh-mcp-client'
|
|
561
|
+
&& typeof entry.options.config?.serverName === 'string')
|
|
562
|
+
servers.set(entry.id, entry.options.config.serverName);
|
|
563
|
+
const snapshot = await ctx.get('pluginInventory').list();
|
|
564
|
+
return { kind: 'success', text: snapshot.entries.map(entry => `${String(entry.entryId)} · ${entry.moduleName}${servers.has(String(entry.entryId)) ? ` · ${servers.get(String(entry.entryId))}` : ''} · ${entry.enabled ? 'enabled' : 'disabled'} · ${entry.fiberPhase ?? 'inactive'}`).join('\n') };
|
|
565
|
+
},
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
name: 'plugin', description: 'Run DSH profile plugin management', input: { hint: 'ARGS' },
|
|
569
|
+
handler: async (invocation) => {
|
|
570
|
+
const stale = ensureCurrent(invocation);
|
|
571
|
+
if (stale !== undefined)
|
|
572
|
+
return stale;
|
|
573
|
+
if (invocation.rawInput.trim() === '')
|
|
574
|
+
return { kind: 'error', text: 'usage: /plugin ARGS' };
|
|
575
|
+
const command = `dsh plugin --profile ${quoteShellWord(decodeURIComponent(new URL(ctx.baseUrl).pathname).split('/').at(-2))}${invocation.rawInput}`;
|
|
576
|
+
const [message, result] = await bound.agent.runMaintenance(signal => runHumanShell(ctx, bound.agent, command, signal, 'changes load on the next launch; exit and run dashi again'));
|
|
577
|
+
bound.agent.inject(message);
|
|
578
|
+
await ctx.sessions.flush(bound.agent.session);
|
|
579
|
+
publish(bound);
|
|
580
|
+
return result.exitCode === 0 ? { kind: 'success' } : { kind: 'error', text: `dsh plugin exited ${String(result.exitCode ?? result.signal ?? 'without status')}` };
|
|
581
|
+
},
|
|
582
|
+
},
|
|
494
583
|
{
|
|
495
584
|
name: 'new', description: 'Start a new session', input: { hint: '[--name TITLE]' },
|
|
496
585
|
handler: async (invocation) => {
|
|
@@ -1027,7 +1116,8 @@ export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, deci
|
|
|
1027
1116
|
if (attachments.length > 0)
|
|
1028
1117
|
throw new Error('!command does not accept image attachments');
|
|
1029
1118
|
await bound.agent.runMaintenance(async (signal) => {
|
|
1030
|
-
|
|
1119
|
+
const [message] = await runHumanShell(ctx, bound.agent, command, signal);
|
|
1120
|
+
bound.agent.inject(message);
|
|
1031
1121
|
await ctx.sessions.flush(bound.agent.session);
|
|
1032
1122
|
});
|
|
1033
1123
|
publish(bound);
|
package/lib/shell-command.d.ts
CHANGED
|
@@ -5,5 +5,6 @@ import type { ShellRunResult } from '@deepseek-ai/dsh-shell';
|
|
|
5
5
|
export declare const HUMAN_SHELL_TIMEOUT_MS = 30000;
|
|
6
6
|
export declare const HUMAN_SHELL_STREAM_BYTES: number;
|
|
7
7
|
export declare function shellResultText(command: string, result: ShellRunResult): string;
|
|
8
|
+
export declare function quoteShellWord(value: string): string;
|
|
8
9
|
/** Run an explicit human command through DSH and identify its next-step context. */
|
|
9
|
-
export declare function runHumanShell(ctx: Context, agent: Agent, command: string, signal: AbortSignal): Promise<UserMessage>;
|
|
10
|
+
export declare function runHumanShell(ctx: Context, agent: Agent, command: string, signal: AbortSignal, success?: string): Promise<readonly [UserMessage, ShellRunResult]>;
|
package/lib/shell-command.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { boundContextSummary, createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths';
|
|
2
3
|
export const HUMAN_SHELL_TIMEOUT_MS = 30_000;
|
|
3
4
|
export const HUMAN_SHELL_STREAM_BYTES = 32 * 1024;
|
|
4
5
|
function tail(output) {
|
|
@@ -42,21 +43,23 @@ export function shellResultText(command, result) {
|
|
|
42
43
|
}
|
|
43
44
|
return parts.join('\n');
|
|
44
45
|
}
|
|
46
|
+
export function quoteShellWord(value) { return `'${value.replaceAll("'", "'\\''")}'`; }
|
|
45
47
|
/** Run an explicit human command through DSH and identify its next-step context. */
|
|
46
|
-
export async function runHumanShell(ctx, agent, command, signal) {
|
|
48
|
+
export async function runHumanShell(ctx, agent, command, signal, success) {
|
|
47
49
|
const result = await ctx.shell.run(ctx.shell.resolve({
|
|
48
50
|
command,
|
|
51
|
+
env: { DSH_HOME: resolveDshHome() },
|
|
49
52
|
sandboxPolicy: ctx.sandboxPolicy.resolve({ session: agent.session }),
|
|
50
53
|
signal,
|
|
51
54
|
stdoutMaxBytes: HUMAN_SHELL_STREAM_BYTES,
|
|
52
55
|
timeoutMs: HUMAN_SHELL_TIMEOUT_MS,
|
|
53
56
|
workdir: agent.session.header.cwd,
|
|
54
57
|
}));
|
|
55
|
-
return createUserMessage({
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
return [createUserMessage({
|
|
59
|
+
content: [{ type: 'text', text: shellResultText(command, result) + (result.exitCode === 0 && success ? `\n${success}` : '') }],
|
|
60
|
+
source: {
|
|
61
|
+
form: 'notice', kind: 'plugin', plugin: 'dashi',
|
|
62
|
+
summary: boundContextSummary(`Shell: ${command.replace(/\s+/gu, ' ').trim()}`),
|
|
63
|
+
},
|
|
64
|
+
}), result];
|
|
62
65
|
}
|
package/lib/state.d.ts
CHANGED
|
@@ -137,6 +137,9 @@ export type OverlayValue = {
|
|
|
137
137
|
readonly effort?: string;
|
|
138
138
|
readonly model: string;
|
|
139
139
|
readonly provider: string;
|
|
140
|
+
} | {
|
|
141
|
+
readonly kind: 'open-file';
|
|
142
|
+
readonly path: string;
|
|
140
143
|
} | {
|
|
141
144
|
readonly interrupt?: true;
|
|
142
145
|
readonly kind: 'fork';
|
|
@@ -197,9 +200,10 @@ export type Overlay = {
|
|
|
197
200
|
readonly kind: 'list';
|
|
198
201
|
readonly notice?: string;
|
|
199
202
|
readonly options: readonly OverlayOption[];
|
|
200
|
-
readonly purpose: 'agents' | 'completion' | 'model' | 'permission' | 'resume' | 'rewind' | 'rewind-action' | 'search';
|
|
203
|
+
readonly purpose: 'agents' | 'completion' | 'memory' | 'model' | 'permission' | 'resume' | 'rewind' | 'rewind-action' | 'search';
|
|
201
204
|
readonly title: string;
|
|
202
205
|
} | {
|
|
206
|
+
readonly cells?: readonly TerminalCell[];
|
|
203
207
|
readonly kind: 'info';
|
|
204
208
|
readonly lines: readonly string[];
|
|
205
209
|
readonly title: string;
|
package/lib/state.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { FLAG_HELP, VERSION_LINE } from './help.js';
|
|
1
2
|
export function initialViewState(cwd, inline, root, cells = [], prompts = [], historyHasMore = false, attachments = []) {
|
|
2
3
|
return {
|
|
3
4
|
attachments, cells, composer: '', cwd, decisions: [], exitArmed: false, historyHasMore, inline,
|
|
@@ -31,6 +32,7 @@ function help() {
|
|
|
31
32
|
kind: 'info',
|
|
32
33
|
title: 'Help',
|
|
33
34
|
lines: [
|
|
35
|
+
VERSION_LINE,
|
|
34
36
|
'Enter send · Ctrl+J newline · Ctrl+T steer/next turn',
|
|
35
37
|
'Esc interrupt · Ctrl+C clear/interrupt · Ctrl+C/D again within 2s to exit',
|
|
36
38
|
'/ and @ complete live · Tab insert · Shift+Tab permission · Ctrl+O cards',
|
|
@@ -39,8 +41,9 @@ function help() {
|
|
|
39
41
|
'Ctrl+B activity details for jobs and subagents',
|
|
40
42
|
'@ paths require DSH file-reference · Ctrl+V pastes an image · Backspace removes it',
|
|
41
43
|
'Ctrl+S stash · Ctrl+G editor · F1 help · Ctrl+L redraw · Ctrl+Z suspend',
|
|
42
|
-
'/new /clear /resume [--all] [NAME|UUID] /fork /rewind /rename /model /permission /agents /queue
|
|
43
|
-
'/status /context /tasks /history /export /copy /exit',
|
|
44
|
+
'/new /clear /resume [--all] [NAME|UUID] /fork /rewind /rename /model /permission /agents /queue',
|
|
45
|
+
'/status /context /memory /config /diff /plugins /plugin /tasks /history /export /copy /exit',
|
|
46
|
+
...FLAG_HELP,
|
|
44
47
|
],
|
|
45
48
|
};
|
|
46
49
|
}
|
package/lib/transcript.js
CHANGED
|
@@ -29,7 +29,8 @@ function shellCell(message, pending) {
|
|
|
29
29
|
function collapsedContextCell(message, key) {
|
|
30
30
|
const source = message.source;
|
|
31
31
|
const form = source.form;
|
|
32
|
-
if (source.kind !== '
|
|
32
|
+
if (source.kind !== 'agent-instructions'
|
|
33
|
+
&& (source.kind !== 'plugin' || !['instructions', 'catalog', 'snapshot', 'notice', 'recall'].includes(String(form)))) {
|
|
33
34
|
return undefined;
|
|
34
35
|
}
|
|
35
36
|
const text = messageText(message.content);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antst/dashi",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.8",
|
|
4
4
|
"description": "A terminal UI for DeepSeek Harness",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -37,7 +37,9 @@
|
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@deepseek-ai/cordis": "4.0.2",
|
|
40
|
+
"@deepseek-ai/cordis-plugin-loader": "1.0.3",
|
|
40
41
|
"@deepseek-ai/dsh-agent": "0.1.2-rc.1",
|
|
42
|
+
"@deepseek-ai/dsh-agent-instructions": "0.1.2-rc.1",
|
|
41
43
|
"@deepseek-ai/dsh-agent-presets": "0.1.2-rc.1",
|
|
42
44
|
"@deepseek-ai/dsh-api-session-controller": "0.1.2-rc.1",
|
|
43
45
|
"@deepseek-ai/dsh-attachment": "0.1.2-rc.1",
|
|
@@ -46,6 +48,8 @@
|
|
|
46
48
|
"@deepseek-ai/dsh-compaction": "0.1.2-rc.1",
|
|
47
49
|
"@deepseek-ai/dsh-file-reference": "0.1.2-rc.1",
|
|
48
50
|
"@deepseek-ai/dsh-fs": "0.1.2-rc.1",
|
|
51
|
+
"@deepseek-ai/dsh-home-paths": "0.1.2-rc.1",
|
|
52
|
+
"@deepseek-ai/dsh-host-plugin-inventory": "0.1.2-rc.1",
|
|
49
53
|
"@deepseek-ai/dsh-llm": "0.1.2-rc.1",
|
|
50
54
|
"@deepseek-ai/dsh-permission-presets": "0.1.2-rc.1",
|
|
51
55
|
"@deepseek-ai/dsh-plan-mode": "0.1.2-rc.1",
|
|
@@ -53,6 +57,7 @@
|
|
|
53
57
|
"@deepseek-ai/dsh-session": "0.1.2-rc.1",
|
|
54
58
|
"@deepseek-ai/dsh-session-projection": "0.1.2-rc.1",
|
|
55
59
|
"@deepseek-ai/dsh-session-query": "0.1.2-rc.1",
|
|
60
|
+
"@deepseek-ai/dsh-settings": "0.1.2-rc.1",
|
|
56
61
|
"@deepseek-ai/dsh-shell": "0.1.2-rc.1",
|
|
57
62
|
"@deepseek-ai/dsh-skill": "0.1.2-rc.1",
|
|
58
63
|
"@deepseek-ai/dsh-subagent": "0.1.2-rc.1",
|