@antst/dashi 0.1.0-alpha.12 → 0.1.0-alpha.14
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/catalogs.d.ts +1 -1
- package/lib/catalogs.js +41 -6
- package/lib/completion-trigger.d.ts +4 -0
- package/lib/completion-trigger.js +13 -1
- package/lib/renderer.js +2 -2
- package/lib/rewind.d.ts +4 -2
- package/lib/rewind.js +33 -14
- package/lib/session-runtime.js +23 -20
- package/package.json +1 -1
package/lib/catalogs.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export declare function sessionOverlay(items: readonly SessionSummary[], current
|
|
|
14
14
|
export declare function modelOverlay(catalog: ModelCatalog, selected?: ModelSelection): Overlay;
|
|
15
15
|
/** Build the preset picker from the native preset service. */
|
|
16
16
|
export declare function permissionOverlay(ctx: Context, agent: Agent): Overlay;
|
|
17
|
-
export declare function sessionStatusLine(ctx: Context, agent: Agent, root: RootView,
|
|
17
|
+
export declare function sessionStatusLine(ctx: Context, agent: Agent, root: RootView, repo?: string): string;
|
|
18
18
|
/** Read DSH-owned root facts for /status in one projection cut. */
|
|
19
19
|
export declare function statusOverlay(ctx: Context, agent: Agent, root: RootView): Overlay;
|
|
20
20
|
/** Show DSH's heuristic next-request composition without treating it as an exact total. */
|
package/lib/catalogs.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
1
4
|
import { formatFileMention } from '@deepseek-ai/dsh-file-reference/grammar';
|
|
2
5
|
import { isUserInvocable } from '@deepseek-ai/dsh-skill';
|
|
3
6
|
import { detectAtTrigger } from './at-trigger.js';
|
|
4
|
-
import { slashCompletionQuery } from './completion-trigger.js';
|
|
7
|
+
import { pluginCompletionQuery, slashCompletionQuery } from './completion-trigger.js';
|
|
5
8
|
import { isImagePath } from './image-input.js';
|
|
6
9
|
import { sessionTitle } from './session-list.js';
|
|
7
10
|
function matchRank(name, query) {
|
|
@@ -15,6 +18,24 @@ function selectedModel(ctx, agent) {
|
|
|
15
18
|
}
|
|
16
19
|
/** Build command and skill completion rows for one exact root. */
|
|
17
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
|
+
}
|
|
18
39
|
const at = detectAtTrigger(input, caret);
|
|
19
40
|
if (at !== undefined) {
|
|
20
41
|
const service = ctx.get('fileReferences');
|
|
@@ -156,18 +177,32 @@ function number(value) {
|
|
|
156
177
|
function milliseconds(value) {
|
|
157
178
|
return typeof value === 'number' ? `${number(value)} ms` : 'unavailable';
|
|
158
179
|
}
|
|
159
|
-
|
|
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) {
|
|
160
184
|
const { modelSelection, permissions, tokenUsage, contextPressure } = ctx.sessionProjections
|
|
161
185
|
.snapshot(agent.session, ['modelSelection', 'permissions', 'tokenUsage', 'contextPressure']).values;
|
|
162
186
|
const model = modelSelection?.next ?? modelSelection?.lastUsed;
|
|
163
187
|
const input = tokenUsage === undefined ? 0 : tokenUsage.uncachedInputTokens + tokenUsage.cacheReadTokens + tokenUsage.cacheWriteTokens;
|
|
188
|
+
const total = input + (tokenUsage?.outputTokens ?? 0);
|
|
164
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;
|
|
165
195
|
return [
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
196
|
+
model?.model ?? root.model,
|
|
197
|
+
...(model?.reasoningEffort === undefined ? [] : [model.reasoningEffort]),
|
|
198
|
+
permissions?.currentValue ?? root.permission ?? 'unknown',
|
|
199
|
+
...(context === undefined ? [] : [context]),
|
|
169
200
|
...(input === 0 ? [] : [`cache ${String(Math.min(tokenUsage?.cacheReadTokens === input ? 100 : 99, Math.round((tokenUsage?.cacheReadTokens ?? 0) / input * 100)))}%`]),
|
|
170
|
-
...(
|
|
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]),
|
|
171
206
|
].join(' · ');
|
|
172
207
|
}
|
|
173
208
|
/** Read DSH-owned root facts for /status in one projection cut. */
|
|
@@ -1,2 +1,6 @@
|
|
|
1
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;
|
|
2
6
|
export declare function hasCompletionTrigger(input: string, caret: number): boolean;
|
|
@@ -2,6 +2,18 @@ import { detectAtTrigger } from './at-trigger.js';
|
|
|
2
2
|
export function slashCompletionQuery(input) {
|
|
3
3
|
return /^\/([a-z0-9_-]*)$/u.exec(input)?.[1];
|
|
4
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
|
+
}
|
|
5
16
|
export function hasCompletionTrigger(input, caret) {
|
|
6
|
-
return slashCompletionQuery(input) !== undefined ||
|
|
17
|
+
return slashCompletionQuery(input) !== undefined || pluginCompletionQuery(input, caret) !== undefined
|
|
18
|
+
|| detectAtTrigger(input, caret) !== undefined;
|
|
7
19
|
}
|
package/lib/renderer.js
CHANGED
|
@@ -401,8 +401,8 @@ export function createRenderer(options) {
|
|
|
401
401
|
: root === undefined
|
|
402
402
|
? `${DIM}no session · cards ${state.toolMode} · Ctrl+J newline · Ctrl+L redraw${RESET}`
|
|
403
403
|
: root.status === 'running'
|
|
404
|
-
? `${DIM}running · ${plain(root.model)} · Enter ${state.sendMode === 'steer' ? 'steer' : 'queue next turn'} · Ctrl+T toggle · cards ${state.toolMode} · Esc interrupt${RESET}`
|
|
405
|
-
: `${DIM}idle · ${plain(root.model)} · Enter send · cards ${state.toolMode}${RESET}`;
|
|
404
|
+
? `${DIM}running${accessible ? ` · ${plain(root.model)}` : ''} · Enter ${state.sendMode === 'steer' ? 'steer' : 'queue next turn'} · Ctrl+T toggle · cards ${state.toolMode} · Esc interrupt${RESET}`
|
|
405
|
+
: `${DIM}idle${accessible ? ` · ${plain(root.model)}` : ''} · Enter send · cards ${state.toolMode}${RESET}`;
|
|
406
406
|
const activityCount = activities(state).length;
|
|
407
407
|
const baseStatus = `${baseStatusText}${root?.contextPercent === undefined ? '' : ` · ${String(root.contextPercent)}% context`}${activityCount === 0 ? '' : ' · Ctrl+B activity'}`;
|
|
408
408
|
const status = state.newOutput === 0 ? baseStatus
|
package/lib/rewind.d.ts
CHANGED
|
@@ -7,8 +7,10 @@ export interface RewindBoundary {
|
|
|
7
7
|
}
|
|
8
8
|
/** Return the text of a direct human message, excluding injected context. */
|
|
9
9
|
export declare function humanPrompt(event: SessionEvent): string | undefined;
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
/** Recover one composer input from DSH's durable log. */
|
|
11
|
+
export declare function historyInput(event: SessionEvent): string | undefined;
|
|
12
|
+
export declare function historyInputs(events: readonly SessionEvent[]): readonly string[];
|
|
13
|
+
/** Derive each recalled input and its controller-valid preceding-turn cut. */
|
|
12
14
|
export declare function rewindBoundaries(events: readonly SessionEvent[]): readonly RewindBoundary[];
|
|
13
15
|
export declare function rewindOverlay(events: readonly SessionEvent[], roller: boolean): Overlay;
|
|
14
16
|
export declare function rewindActionOverlay(boundary: Extract<OverlayValue, {
|
package/lib/rewind.js
CHANGED
|
@@ -7,10 +7,29 @@ export function humanPrompt(event) {
|
|
|
7
7
|
.map(block => block.text).join('');
|
|
8
8
|
return text === '' ? undefined : text;
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
function shellInput(message) {
|
|
11
|
+
if (message.source.kind !== 'plugin' || message.source.plugin !== 'dashi'
|
|
12
|
+
|| message.source.form !== 'notice')
|
|
13
|
+
return undefined;
|
|
14
|
+
const first = message.content.find(block => block.type === 'text')?.text.split(/\r?\n/u)[0];
|
|
15
|
+
return first?.startsWith('$ ') === true ? `!${first.slice(2)}` : undefined;
|
|
16
|
+
}
|
|
17
|
+
/** Recover one composer input from DSH's durable log. */
|
|
18
|
+
export function historyInput(event) {
|
|
19
|
+
const prompt = humanPrompt(event);
|
|
20
|
+
if (prompt !== undefined)
|
|
21
|
+
return prompt;
|
|
22
|
+
if (event.type === 'command/run' && event.data.args !== undefined) {
|
|
23
|
+
return `/${event.data.name}${event.data.args}`;
|
|
24
|
+
}
|
|
25
|
+
if (event.type !== 'agent/inbox/spliced')
|
|
26
|
+
return undefined;
|
|
27
|
+
return event.data.inserted.map(shellInput).find(input => input !== undefined);
|
|
28
|
+
}
|
|
29
|
+
export function historyInputs(events) {
|
|
30
|
+
return events.flatMap(event => historyInput(event) ?? []);
|
|
12
31
|
}
|
|
13
|
-
/** Derive each
|
|
32
|
+
/** Derive each recalled input and its controller-valid preceding-turn cut. */
|
|
14
33
|
export function rewindBoundaries(events) {
|
|
15
34
|
const boundaries = [];
|
|
16
35
|
let previousEnd;
|
|
@@ -21,22 +40,22 @@ export function rewindBoundaries(events) {
|
|
|
21
40
|
openTurn = event.data.turn;
|
|
22
41
|
prompted = false;
|
|
23
42
|
}
|
|
24
|
-
else if (event.type === 'user/message' && openTurn !== undefined) {
|
|
25
|
-
const prompt = humanPrompt(event);
|
|
26
|
-
if (prompt !== undefined) {
|
|
27
|
-
boundaries.push({
|
|
28
|
-
...(previousEnd === undefined ? {} : { atSeq: previousEnd.seq }),
|
|
29
|
-
label: `${prompt.replaceAll(/\s+/gu, ' ')}${prompted ? ' · mid-turn' : ''}`,
|
|
30
|
-
prompt,
|
|
31
|
-
});
|
|
32
|
-
prompted = true;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
43
|
else if (event.type === 'turn/end') {
|
|
36
44
|
previousEnd = event;
|
|
37
45
|
openTurn = undefined;
|
|
38
46
|
prompted = false;
|
|
39
47
|
}
|
|
48
|
+
const prompt = historyInput(event);
|
|
49
|
+
if (prompt === undefined)
|
|
50
|
+
continue;
|
|
51
|
+
const human = humanPrompt(event) !== undefined;
|
|
52
|
+
boundaries.push({
|
|
53
|
+
...(previousEnd === undefined ? {} : { atSeq: previousEnd.seq }),
|
|
54
|
+
label: `${prompt.replaceAll(/\s+/gu, ' ')}${human && prompted ? ' · mid-turn' : ''}`,
|
|
55
|
+
prompt,
|
|
56
|
+
});
|
|
57
|
+
if (human && openTurn !== undefined)
|
|
58
|
+
prompted = true;
|
|
40
59
|
}
|
|
41
60
|
return boundaries;
|
|
42
61
|
}
|
package/lib/session-runtime.js
CHANGED
|
@@ -9,7 +9,7 @@ import { diffOverlay } from './diff-view.js';
|
|
|
9
9
|
import { eventsFromRecords } from './history-records.js';
|
|
10
10
|
import { admitDraftImages, encodeDraftImages, readDraftImages } from './image-input.js';
|
|
11
11
|
import { contextPercent, jobViews, subagentViews } from './presentation.js';
|
|
12
|
-
import {
|
|
12
|
+
import { historyInput, historyInputs, humanPrompt, inheritedTurn, rewindActionOverlay, rewindOverlay, } from './rewind.js';
|
|
13
13
|
import { createToolPresenter } from './tool-presentation.js';
|
|
14
14
|
import { quoteShellWord, runHumanShell } from './shell-command.js';
|
|
15
15
|
import { markdownTranscript } from './session-export.js';
|
|
@@ -80,16 +80,18 @@ async function firstControl(iterator) {
|
|
|
80
80
|
}
|
|
81
81
|
return first.value;
|
|
82
82
|
}
|
|
83
|
-
async function
|
|
83
|
+
async function gitRepo(ctx, agent, signal) {
|
|
84
|
+
const fallback = basename(agent.session.header.cwd ?? '');
|
|
84
85
|
try {
|
|
85
86
|
const result = await ctx.shell.run(ctx.shell.resolve({
|
|
86
|
-
command: 'git branch --show-current', sandboxPolicy: ctx.sandboxPolicy.resolve({ mode: 'read-only' }),
|
|
87
|
-
signal, stdoutMaxBytes:
|
|
87
|
+
command: 'git rev-parse --show-toplevel && git branch --show-current', sandboxPolicy: ctx.sandboxPolicy.resolve({ mode: 'read-only' }),
|
|
88
|
+
signal, stdoutMaxBytes: 1_024, timeoutMs: 2_000, workdir: agent.session.header.cwd,
|
|
88
89
|
}));
|
|
89
|
-
|
|
90
|
+
const [root, branch] = result.stdout.text.trim().split(/\r?\n/u);
|
|
91
|
+
return result.exitCode === 0 && root !== undefined && branch !== undefined ? `${basename(root)}/${branch}` : fallback;
|
|
90
92
|
}
|
|
91
93
|
catch {
|
|
92
|
-
return
|
|
94
|
+
return fallback;
|
|
93
95
|
}
|
|
94
96
|
}
|
|
95
97
|
function usage(raw, expected) {
|
|
@@ -165,9 +167,9 @@ export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, deci
|
|
|
165
167
|
address: { kind: 'session', sessionId }, maxMessages: 50,
|
|
166
168
|
}, abort.signal)[Symbol.asyncIterator]();
|
|
167
169
|
const controlIterator = ctx.sessionController.control(abort.signal)[Symbol.asyncIterator]();
|
|
168
|
-
const [opening, controlOpening, subagents,
|
|
170
|
+
const [opening, controlOpening, subagents, repo] = await Promise.all([
|
|
169
171
|
firstSnapshot(iterator), firstControl(controlIterator), subagentViews(ctx, sessionId, abort.signal),
|
|
170
|
-
|
|
172
|
+
gitRepo(ctx, agent, abort.signal),
|
|
171
173
|
]);
|
|
172
174
|
title ??= projectionString(opening.projections, 'title');
|
|
173
175
|
const selected = projectionModel(opening.projections);
|
|
@@ -179,7 +181,7 @@ export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, deci
|
|
|
179
181
|
return {
|
|
180
182
|
abort,
|
|
181
183
|
agent,
|
|
182
|
-
|
|
184
|
+
repo,
|
|
183
185
|
controlIterator,
|
|
184
186
|
cursor: opening.cursor,
|
|
185
187
|
disposers,
|
|
@@ -289,11 +291,11 @@ export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, deci
|
|
|
289
291
|
});
|
|
290
292
|
}, 34);
|
|
291
293
|
};
|
|
292
|
-
const
|
|
293
|
-
const
|
|
294
|
-
if (bound.abort.signal.aborted || current() !== bound || bound.
|
|
294
|
+
const refreshRepo = async (bound) => {
|
|
295
|
+
const repo = await gitRepo(ctx, bound.agent, bound.abort.signal);
|
|
296
|
+
if (bound.abort.signal.aborted || current() !== bound || bound.repo === repo)
|
|
295
297
|
return;
|
|
296
|
-
bound.
|
|
298
|
+
bound.repo = repo;
|
|
297
299
|
dispatch({ type: 'redraw' });
|
|
298
300
|
};
|
|
299
301
|
const consume = (bound, frame) => {
|
|
@@ -302,7 +304,7 @@ export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, deci
|
|
|
302
304
|
return;
|
|
303
305
|
bound.events.push(event);
|
|
304
306
|
if (event.type === 'turn/end') {
|
|
305
|
-
void
|
|
307
|
+
void refreshRepo(bound);
|
|
306
308
|
const startedAt = turnStartTime(bound.events, event.data.turn);
|
|
307
309
|
if (startedAt !== undefined) {
|
|
308
310
|
dispatch({
|
|
@@ -327,7 +329,7 @@ export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, deci
|
|
|
327
329
|
...(model.reasoningEffort === undefined ? {} : { effort: model.reasoningEffort }),
|
|
328
330
|
});
|
|
329
331
|
}
|
|
330
|
-
const prompt =
|
|
332
|
+
const prompt = event.type === 'agent/inbox/spliced' ? undefined : historyInput(event);
|
|
331
333
|
if (prompt !== undefined)
|
|
332
334
|
dispatch({ type: 'prompt-recorded', rootId: bound.root.id, text: prompt });
|
|
333
335
|
schedule(bound);
|
|
@@ -406,7 +408,7 @@ export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, deci
|
|
|
406
408
|
tuiRoot.bind(candidate.agent);
|
|
407
409
|
dispatch({
|
|
408
410
|
type: 'root-bound', cells: transcriptCells(candidate),
|
|
409
|
-
hasMore: candidate.hasMore, prompts:
|
|
411
|
+
hasMore: candidate.hasMore, prompts: historyInputs(candidate.events), root: candidate.root,
|
|
410
412
|
});
|
|
411
413
|
if (started) {
|
|
412
414
|
candidate.pump = follow(candidate);
|
|
@@ -505,7 +507,7 @@ export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, deci
|
|
|
505
507
|
const roller = ctx.commands.list(bound.agent).some(command => command.name === 'roller-restore');
|
|
506
508
|
const overlay = rewindOverlay(bound.agent.session.snapshotEvents(), roller);
|
|
507
509
|
if (overlay.kind !== 'list' || overlay.options.length === 0) {
|
|
508
|
-
throw new Error('the current session has no
|
|
510
|
+
throw new Error('the current session has no input to rewind');
|
|
509
511
|
}
|
|
510
512
|
dispatch({ type: 'open-overlay', overlay });
|
|
511
513
|
return;
|
|
@@ -795,7 +797,7 @@ export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, deci
|
|
|
795
797
|
if (invocation.rawInput.trim() === '')
|
|
796
798
|
return { kind: 'error', text: 'usage: /plugin ARGS' };
|
|
797
799
|
const command = `dsh plugin --profile ${quoteShellWord(decodeURIComponent(new URL(ctx.baseUrl).pathname).split('/').at(-2))}${invocation.rawInput}`;
|
|
798
|
-
const [message, result] = await bound.agent.runMaintenance(signal => runHumanShell(ctx, bound.agent, command, signal, '
|
|
800
|
+
const [message, result] = await bound.agent.runMaintenance(signal => runHumanShell(ctx, bound.agent, command, signal, 'bundles load on the next launch; plain plugins need a patch row', false));
|
|
799
801
|
bound.agent.inject(message);
|
|
800
802
|
await ctx.sessions.flush(bound.agent.session);
|
|
801
803
|
publish(bound);
|
|
@@ -1277,9 +1279,9 @@ export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, deci
|
|
|
1277
1279
|
initialAttachments,
|
|
1278
1280
|
get initialCells() { return transcriptCells(current()); },
|
|
1279
1281
|
get initialHasMore() { return current().hasMore; },
|
|
1280
|
-
get initialPrompts() { return
|
|
1282
|
+
get initialPrompts() { return historyInputs(current().events); },
|
|
1281
1283
|
get root() { return current().root; },
|
|
1282
|
-
get statusLine() { const bound = current(); return sessionStatusLine(ctx, bound.agent, bound.root, bound.
|
|
1284
|
+
get statusLine() { const bound = current(); return sessionStatusLine(ctx, bound.agent, bound.root, bound.repo); },
|
|
1283
1285
|
get summary() { return `Resume with: dsh --profile dashi --resume ${current().root.id}`; },
|
|
1284
1286
|
activate,
|
|
1285
1287
|
async attach(path) {
|
|
@@ -1428,6 +1430,7 @@ export async function createSessionRuntime(ctx, options, tuiRoot, dispatch, deci
|
|
|
1428
1430
|
bound.agent.inject(message);
|
|
1429
1431
|
await ctx.sessions.flush(bound.agent.session);
|
|
1430
1432
|
});
|
|
1433
|
+
dispatch({ type: 'prompt-recorded', rootId: bound.root.id, text: `!${command}` });
|
|
1431
1434
|
publish(bound);
|
|
1432
1435
|
return;
|
|
1433
1436
|
}
|