@agi-fans/dsh-tui 0.20.0 → 0.22.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.
- package/lib/CHANGELOG.md +249 -3
- package/lib/chrome/box.d.ts +47 -16
- package/lib/chrome/box.js +172 -130
- package/lib/chrome/box.js.map +1 -1
- package/lib/chrome/code-highlight.d.ts +15 -0
- package/lib/chrome/code-highlight.js +60 -4
- package/lib/chrome/code-highlight.js.map +1 -1
- package/lib/chrome/command-output.d.ts +29 -2
- package/lib/chrome/command-output.js +100 -4
- package/lib/chrome/command-output.js.map +1 -1
- package/lib/chrome/main-screen-renderer.d.ts +18 -0
- package/lib/chrome/main-screen-renderer.js +58 -5
- package/lib/chrome/main-screen-renderer.js.map +1 -1
- package/lib/chrome/markdown.js +30 -10
- package/lib/chrome/markdown.js.map +1 -1
- package/lib/chrome/relative-time.d.ts +17 -0
- package/lib/chrome/relative-time.js +36 -0
- package/lib/chrome/relative-time.js.map +1 -1
- package/lib/chrome/renderer.d.ts +9 -0
- package/lib/chrome/renderer.js +1 -1
- package/lib/chrome/renderer.js.map +1 -1
- package/lib/chrome/secret-mask.d.ts +35 -0
- package/lib/chrome/secret-mask.js +180 -0
- package/lib/chrome/secret-mask.js.map +1 -0
- package/lib/chrome/status-config.d.ts +161 -51
- package/lib/chrome/status-config.js +237 -126
- package/lib/chrome/status-config.js.map +1 -1
- package/lib/chrome/status-line.d.ts +3 -2
- package/lib/chrome/status-line.js +105 -63
- package/lib/chrome/status-line.js.map +1 -1
- package/lib/chrome/terminal-colors.d.ts +85 -0
- package/lib/chrome/terminal-colors.js +230 -0
- package/lib/chrome/terminal-colors.js.map +1 -0
- package/lib/chrome/terminal-images.d.ts +9 -1
- package/lib/chrome/terminal-images.js +27 -4
- package/lib/chrome/terminal-images.js.map +1 -1
- package/lib/chrome/theme.d.ts +32 -9
- package/lib/chrome/theme.js +616 -520
- package/lib/chrome/theme.js.map +1 -1
- package/lib/chrome/tool-args.d.ts +1 -1
- package/lib/chrome/tool-args.js +3 -1
- package/lib/chrome/tool-args.js.map +1 -1
- package/lib/chrome/tool-renderers.d.ts +2 -0
- package/lib/chrome/tool-renderers.js +69 -3
- package/lib/chrome/tool-renderers.js.map +1 -1
- package/lib/chrome/tools-list.d.ts +1 -4
- package/lib/chrome/tools-list.js +1 -41
- package/lib/chrome/tools-list.js.map +1 -1
- package/lib/chrome/welcome-tips.d.ts +20 -7
- package/lib/chrome/welcome-tips.js +22 -41
- package/lib/chrome/welcome-tips.js.map +1 -1
- package/lib/commands/auth-ids.d.ts +25 -0
- package/lib/commands/auth-ids.js +27 -0
- package/lib/commands/auth-ids.js.map +1 -0
- package/lib/commands/auth-input.d.ts +34 -0
- package/lib/commands/auth-input.js +96 -0
- package/lib/commands/auth-input.js.map +1 -0
- package/lib/commands/auth-providers.d.ts +39 -0
- package/lib/commands/auth-providers.js +125 -0
- package/lib/commands/auth-providers.js.map +1 -0
- package/lib/commands/auth.d.ts +16 -22
- package/lib/commands/auth.js +346 -299
- package/lib/commands/auth.js.map +1 -1
- package/lib/commands/btw.d.ts +27 -0
- package/lib/commands/btw.js +59 -0
- package/lib/commands/btw.js.map +1 -0
- package/lib/commands/diff.js +30 -5
- package/lib/commands/diff.js.map +1 -1
- package/lib/commands/export.d.ts +1 -1
- package/lib/commands/export.js +5 -3
- package/lib/commands/export.js.map +1 -1
- package/lib/commands/files.d.ts +17 -1
- package/lib/commands/files.js +69 -61
- package/lib/commands/files.js.map +1 -1
- package/lib/commands/integrations.js +18 -6
- package/lib/commands/integrations.js.map +1 -1
- package/lib/commands/jobs.d.ts +19 -4
- package/lib/commands/jobs.js +50 -7
- package/lib/commands/jobs.js.map +1 -1
- package/lib/commands/model.js +109 -76
- package/lib/commands/model.js.map +1 -1
- package/lib/commands/permission.js +46 -13
- package/lib/commands/permission.js.map +1 -1
- package/lib/commands/plugins.js +196 -42
- package/lib/commands/plugins.js.map +1 -1
- package/lib/commands/schedule.d.ts +29 -0
- package/lib/commands/schedule.js +228 -0
- package/lib/commands/schedule.js.map +1 -0
- package/lib/commands/session-configuration.d.ts +1 -1
- package/lib/commands/session-configuration.js +29 -28
- package/lib/commands/session-configuration.js.map +1 -1
- package/lib/commands/session.js +75 -80
- package/lib/commands/session.js.map +1 -1
- package/lib/commands/terminal.d.ts +24 -4
- package/lib/commands/terminal.js +38 -94
- package/lib/commands/terminal.js.map +1 -1
- package/lib/commands/trajectory.js +4 -1
- package/lib/commands/trajectory.js.map +1 -1
- package/lib/definition.d.ts +150 -11
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/input/actions.d.ts +51 -0
- package/lib/input/actions.js +120 -0
- package/lib/input/actions.js.map +1 -0
- package/lib/input/editor-discovery.js +2 -2
- package/lib/input/editor-discovery.js.map +1 -1
- package/lib/input/editor.d.ts +0 -10
- package/lib/input/editor.js +11 -9
- package/lib/input/editor.js.map +1 -1
- package/lib/input/image-paste.d.ts +19 -1
- package/lib/input/image-paste.js +82 -1
- package/lib/input/image-paste.js.map +1 -1
- package/lib/input/keybindings-config.d.ts +15 -4
- package/lib/input/keybindings-config.js +57 -35
- package/lib/input/keybindings-config.js.map +1 -1
- package/lib/input/keys.d.ts +18 -0
- package/lib/input/keys.js +48 -3
- package/lib/input/keys.js.map +1 -1
- package/lib/input/wheel-scroll.d.ts +46 -0
- package/lib/input/wheel-scroll.js +69 -0
- package/lib/input/wheel-scroll.js.map +1 -0
- package/lib/prompt-intents.d.ts +182 -0
- package/lib/prompt-intents.js +127 -0
- package/lib/prompt-intents.js.map +1 -0
- package/lib/runtime/agent-profile.d.ts +5 -0
- package/lib/runtime/agent-profile.js +12 -0
- package/lib/runtime/agent-profile.js.map +1 -1
- package/lib/runtime/approval-rules.d.ts +59 -0
- package/lib/runtime/approval-rules.js +179 -0
- package/lib/runtime/approval-rules.js.map +1 -0
- package/lib/runtime/btw-policy.d.ts +7 -0
- package/lib/runtime/btw-policy.js +18 -0
- package/lib/runtime/btw-policy.js.map +1 -0
- package/lib/runtime/btw.d.ts +47 -0
- package/lib/runtime/btw.js +200 -0
- package/lib/runtime/btw.js.map +1 -0
- package/lib/runtime/cancellable.d.ts +75 -0
- package/lib/runtime/cancellable.js +76 -0
- package/lib/runtime/cancellable.js.map +1 -0
- package/lib/runtime/composer-images.js +5 -4
- package/lib/runtime/composer-images.js.map +1 -1
- package/lib/runtime/composer-shell.d.ts +30 -0
- package/lib/runtime/composer-shell.js +150 -0
- package/lib/runtime/composer-shell.js.map +1 -0
- package/lib/runtime/file-recovery-local.d.ts +73 -0
- package/lib/runtime/file-recovery-local.js +351 -0
- package/lib/runtime/file-recovery-local.js.map +1 -0
- package/lib/runtime/file-recovery-recording.d.ts +23 -0
- package/lib/runtime/file-recovery-recording.js +131 -0
- package/lib/runtime/file-recovery-recording.js.map +1 -0
- package/lib/runtime/file-recovery-review.d.ts +3 -0
- package/lib/runtime/file-recovery-review.js +130 -0
- package/lib/runtime/file-recovery-review.js.map +1 -0
- package/lib/runtime/file-recovery-store.d.ts +83 -0
- package/lib/runtime/file-recovery-store.js +329 -0
- package/lib/runtime/file-recovery-store.js.map +1 -0
- package/lib/runtime/file-recovery-worker.d.ts +22 -0
- package/lib/runtime/file-recovery-worker.js +153 -0
- package/lib/runtime/file-recovery-worker.js.map +1 -0
- package/lib/runtime/file-review.d.ts +6 -3
- package/lib/runtime/file-review.js +44 -7
- package/lib/runtime/file-review.js.map +1 -1
- package/lib/runtime/herdr-agent.d.ts +4 -13
- package/lib/runtime/herdr-agent.js +19 -63
- package/lib/runtime/herdr-agent.js.map +1 -1
- package/lib/runtime/plain-tui.d.ts +2 -0
- package/lib/runtime/plain-tui.js +7 -1
- package/lib/runtime/plain-tui.js.map +1 -1
- package/lib/runtime/plugin-settings.d.ts +25 -2
- package/lib/runtime/plugin-settings.js +329 -31
- package/lib/runtime/plugin-settings.js.map +1 -1
- package/lib/runtime/provider-local.d.ts +81 -24
- package/lib/runtime/provider-local.js +1807 -608
- package/lib/runtime/provider-local.js.map +1 -1
- package/lib/runtime/runner.js +52 -12
- package/lib/runtime/runner.js.map +1 -1
- package/lib/runtime/session-archive.d.ts +6 -0
- package/lib/runtime/session-archive.js +129 -3
- package/lib/runtime/session-archive.js.map +1 -1
- package/lib/runtime/session-runtime.js +1 -1
- package/lib/runtime/session-runtime.js.map +1 -1
- package/lib/runtime/settings-preferences.d.ts +5 -0
- package/lib/runtime/settings-preferences.js +34 -0
- package/lib/runtime/settings-preferences.js.map +1 -0
- package/lib/runtime/startup-notices.js +2 -0
- package/lib/runtime/startup-notices.js.map +1 -1
- package/lib/runtime/terminal-modes.d.ts +47 -0
- package/lib/runtime/terminal-modes.js +86 -0
- package/lib/runtime/terminal-modes.js.map +1 -0
- package/lib/runtime/terminal-notifications.d.ts +3 -5
- package/lib/runtime/terminal-notifications.js +4 -8
- package/lib/runtime/terminal-notifications.js.map +1 -1
- package/lib/runtime/terminal-probe.d.ts +36 -0
- package/lib/runtime/terminal-probe.js +37 -0
- package/lib/runtime/terminal-probe.js.map +1 -0
- package/lib/runtime/terminal-session.d.ts +57 -0
- package/lib/runtime/terminal-session.js +164 -0
- package/lib/runtime/terminal-session.js.map +1 -0
- package/lib/runtime/terminal-state.d.ts +29 -0
- package/lib/runtime/terminal-state.js +62 -0
- package/lib/runtime/terminal-state.js.map +1 -0
- package/lib/runtime/tool-presentation.js +50 -14
- package/lib/runtime/tool-presentation.js.map +1 -1
- package/lib/session/external-agents.d.ts +5 -0
- package/lib/session/external-agents.js +27 -0
- package/lib/session/external-agents.js.map +1 -0
- package/lib/session/feature-toggles.d.ts +1 -1
- package/lib/session/feature-toggles.js +1 -1
- package/lib/session/interaction-adapter.d.ts +1 -6
- package/lib/session/interaction-adapter.js +95 -18
- package/lib/session/interaction-adapter.js.map +1 -1
- package/lib/session/message-queue.js +1 -1
- package/lib/session/message-queue.js.map +1 -1
- package/lib/session/model-readiness.d.ts +16 -0
- package/lib/session/model-readiness.js +43 -0
- package/lib/session/model-readiness.js.map +1 -0
- package/lib/session/package-metadata.d.ts +8 -0
- package/lib/session/package-metadata.js +8 -0
- package/lib/session/package-metadata.js.map +1 -1
- package/lib/session/project-context.d.ts +5 -0
- package/lib/session/project-context.js +36 -0
- package/lib/session/project-context.js.map +1 -1
- package/lib/session/session-controller.d.ts +10 -13
- package/lib/session/session-controller.js +183 -98
- package/lib/session/session-controller.js.map +1 -1
- package/lib/session/session-library.js +2 -0
- package/lib/session/session-library.js.map +1 -1
- package/lib/session/session-tree.d.ts +3 -0
- package/lib/session/session-tree.js +3 -1
- package/lib/session/session-tree.js.map +1 -1
- package/lib/session/subagent-roster.d.ts +2 -1
- package/lib/session/subagent-roster.js +24 -3
- package/lib/session/subagent-roster.js.map +1 -1
- package/lib/session/subagent-tracker.d.ts +6 -2
- package/lib/session/subagent-tracker.js +49 -2
- package/lib/session/subagent-tracker.js.map +1 -1
- package/lib/session/tui-settings.d.ts +47 -13
- package/lib/session/tui-settings.js +76 -34
- package/lib/session/tui-settings.js.map +1 -1
- package/lib/session/working-directory.d.ts +4 -0
- package/lib/session/working-directory.js +4 -0
- package/lib/session/working-directory.js.map +1 -0
- package/lib/session/worktrees.d.ts +13 -0
- package/lib/session/worktrees.js +49 -0
- package/lib/session/worktrees.js.map +1 -0
- package/lib/views/approval-rule.d.ts +3 -0
- package/lib/views/approval-rule.js +4 -0
- package/lib/views/approval-rule.js.map +1 -0
- package/lib/views/at-complete.d.ts +8 -0
- package/lib/views/at-complete.js +64 -2
- package/lib/views/at-complete.js.map +1 -1
- package/lib/views/autocomplete.d.ts +22 -2
- package/lib/views/autocomplete.js +70 -40
- package/lib/views/autocomplete.js.map +1 -1
- package/lib/views/copy-targets.d.ts +13 -14
- package/lib/views/copy-targets.js +42 -54
- package/lib/views/copy-targets.js.map +1 -1
- package/lib/views/document-reader.js +18 -5
- package/lib/views/document-reader.js.map +1 -1
- package/lib/views/event-views.d.ts +1 -1
- package/lib/views/event-views.js +60 -6
- package/lib/views/event-views.js.map +1 -1
- package/lib/views/file-actions.d.ts +12 -0
- package/lib/views/file-actions.js +72 -0
- package/lib/views/file-actions.js.map +1 -0
- package/lib/views/history-search.js +15 -21
- package/lib/views/history-search.js.map +1 -1
- package/lib/views/hotkeys.d.ts +8 -1
- package/lib/views/hotkeys.js +53 -26
- package/lib/views/hotkeys.js.map +1 -1
- package/lib/views/list-navigation.d.ts +62 -0
- package/lib/views/list-navigation.js +73 -0
- package/lib/views/list-navigation.js.map +1 -0
- package/lib/views/list-view.d.ts +99 -0
- package/lib/views/list-view.js +165 -0
- package/lib/views/list-view.js.map +1 -0
- package/lib/views/prompt-selector.d.ts +34 -4
- package/lib/views/prompt-selector.js +270 -134
- package/lib/views/prompt-selector.js.map +1 -1
- package/lib/views/session-files.d.ts +1 -2
- package/lib/views/session-files.js +1 -11
- package/lib/views/session-files.js.map +1 -1
- package/lib/views/settings-list.d.ts +51 -10
- package/lib/views/settings-list.js +267 -315
- package/lib/views/settings-list.js.map +1 -1
- package/lib/views/trajectory-timeline.d.ts +72 -0
- package/lib/views/trajectory-timeline.js +133 -0
- package/lib/views/trajectory-timeline.js.map +1 -0
- package/lib/views/trajectory.d.ts +15 -4
- package/lib/views/trajectory.js +557 -123
- package/lib/views/trajectory.js.map +1 -1
- package/lib/views/transcript-export.js +9 -0
- package/lib/views/transcript-export.js.map +1 -1
- package/lib/views/transcript-render.d.ts +97 -25
- package/lib/views/transcript-render.js +542 -170
- package/lib/views/transcript-render.js.map +1 -1
- package/lib/views/transcript-search.d.ts +39 -6
- package/lib/views/transcript-search.js +46 -11
- package/lib/views/transcript-search.js.map +1 -1
- package/lib/views/transcript-types.d.ts +63 -5
- package/lib/views/transcript-types.js +23 -11
- package/lib/views/transcript-types.js.map +1 -1
- package/package.json +95 -65
- package/lib/commands/loop.d.ts +0 -52
- package/lib/commands/loop.js +0 -307
- package/lib/commands/loop.js.map +0 -1
- package/lib/commands/steer.d.ts +0 -5
- package/lib/commands/steer.js +0 -24
- package/lib/commands/steer.js.map +0 -1
- package/lib/runtime/terminal-reader.d.ts +0 -11
- package/lib/runtime/terminal-reader.js +0 -87
- package/lib/runtime/terminal-reader.js.map +0 -1
- package/lib/views/agent-hub.d.ts +0 -32
- package/lib/views/agent-hub.js +0 -206
- package/lib/views/agent-hub.js.map +0 -1
- package/lib/views/copy-selector.d.ts +0 -51
- package/lib/views/copy-selector.js +0 -139
- package/lib/views/copy-selector.js.map +0 -1
|
@@ -11,12 +11,10 @@ import { steerAgent } from "./steering.js";
|
|
|
11
11
|
import { openMessageQueue } from "./message-queue.js";
|
|
12
12
|
import { WorkflowProjection } from "./workflow-projection.js";
|
|
13
13
|
import { join } from 'node:path';
|
|
14
|
-
import { installModelSelection, } from '@deepseek-ai/dsh-agent';
|
|
15
14
|
import { createUserMessage, } from '@deepseek-ai/dsh-llm';
|
|
16
15
|
import { isUserInvocable } from '@deepseek-ai/dsh-skill';
|
|
17
|
-
import { SessionAlreadyOwnedError } from '@deepseek-ai/dsh-session-persistence';
|
|
18
16
|
import { readColdSessionLog } from '@deepseek-ai/dsh-session-query';
|
|
19
|
-
import {
|
|
17
|
+
import { appendPluginRecord, pluginRecordOf, SessionId, SessionLogOffset } from '@deepseek-ai/dsh-session';
|
|
20
18
|
import { queueHostSubagentPrompt } from '@deepseek-ai/dsh-subagent/internal';
|
|
21
19
|
import { firstVisibleStreamTime } from "../views/stream-time.js";
|
|
22
20
|
import { LiveAttemptTracker } from "./live-attempt-tracker.js";
|
|
@@ -27,22 +25,18 @@ export { conversationTurns } from "./conversation-turns.js";
|
|
|
27
25
|
import { jobNoticeFor } from "./job-notice.js";
|
|
28
26
|
import { descendantDepth, isSteerableSubagent } from "./subagent-roster.js";
|
|
29
27
|
import { readRecentRows, writeRecentRows, readSessionLibrary, sessionLibraryPath, setSessionLabel } from "./session-library.js";
|
|
30
|
-
import {
|
|
28
|
+
import { currentWorkingDirectory } from "./working-directory.js";
|
|
31
29
|
import { SubagentTracker } from "./subagent-tracker.js";
|
|
32
30
|
import { commandPermission } from "../commands/permission.js";
|
|
31
|
+
import { configureAgentContext } from "../runtime/agent-profile.js";
|
|
32
|
+
import { BTW_PRESET } from "../runtime/btw-policy.js";
|
|
33
|
+
import { reviewFileRecovery } from "../runtime/file-recovery-review.js";
|
|
33
34
|
import { isBlankSession, } from "./session-configuration.js";
|
|
34
35
|
import { stripComposerImageMarkers } from "../input/image-paste.js";
|
|
35
36
|
async function setupAgentContext(agentCtx, agent, selection) {
|
|
36
|
-
|
|
37
|
-
const agentPresets = agentCtx.get('agentPresets');
|
|
38
|
-
const sessionProjections = agentCtx.get('sessionProjections');
|
|
39
|
-
if (agentPresets === undefined || sessionProjections === undefined) {
|
|
40
|
-
throw new Error('agent configuration services are unavailable');
|
|
41
|
-
}
|
|
42
|
-
const agentPreset = sessionProjections.stateOf(agent.session, 'agentPreset') ?? agentPresets.defaultId;
|
|
43
|
-
const mounted = await agentPresets.mount(agentCtx, agentPreset);
|
|
37
|
+
const configured = await configureAgentContext(agentCtx, agent, selection);
|
|
44
38
|
await agentCtx.plugin(commandPermission(agent));
|
|
45
|
-
return
|
|
39
|
+
return configured;
|
|
46
40
|
}
|
|
47
41
|
function parseControl(line) {
|
|
48
42
|
const match = /^\/([a-z][a-z0-9_-]*(?::[a-z0-9][a-z0-9_-]*)?)(?:\s+(.*))?$/su.exec(line.trim());
|
|
@@ -317,11 +311,38 @@ export async function createSubmissionMessage(submission, attachments) {
|
|
|
317
311
|
const refs = inputs.length === 0 || attachments === undefined
|
|
318
312
|
? []
|
|
319
313
|
: [...await attachments.saveImages(inputs)];
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
314
|
+
// A recorded order keeps the picture where the reader put it; without one the
|
|
315
|
+
// message falls back to text followed by its attachments.
|
|
316
|
+
const content = [];
|
|
317
|
+
if (submission.segments === undefined || submission.segments.length === 0) {
|
|
318
|
+
if (submission.text !== '')
|
|
319
|
+
content.push({ type: 'text', text: submission.text });
|
|
320
|
+
for (const attachment of refs)
|
|
321
|
+
content.push({ type: 'image', attachment });
|
|
322
|
+
for (const attachment of submission.files ?? [])
|
|
323
|
+
content.push({ type: 'file', attachment });
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
for (const segment of submission.segments) {
|
|
327
|
+
if (segment.kind === 'text') {
|
|
328
|
+
if (segment.text !== '')
|
|
329
|
+
content.push({ type: 'text', text: segment.text });
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
const attachment = refs[segment.index];
|
|
333
|
+
if (attachment !== undefined)
|
|
334
|
+
content.push({ type: 'image', attachment });
|
|
335
|
+
}
|
|
336
|
+
// An attachment the composer did not mark in the text still belongs to the
|
|
337
|
+
// message: keep it rather than dropping it with the marker.
|
|
338
|
+
const placedImages = new Set(submission.segments.flatMap(segment => segment.kind === 'image' ? [segment.index] : []));
|
|
339
|
+
for (const [index, attachment] of refs.entries()) {
|
|
340
|
+
if (!placedImages.has(index))
|
|
341
|
+
content.push({ type: 'image', attachment });
|
|
342
|
+
}
|
|
343
|
+
for (const attachment of submission.files ?? [])
|
|
344
|
+
content.push({ type: 'file', attachment });
|
|
345
|
+
}
|
|
325
346
|
if (content.length === 0)
|
|
326
347
|
throw new Error('Cannot submit an empty message.');
|
|
327
348
|
return createUserMessage({ content, source: { kind: 'user' } });
|
|
@@ -368,6 +389,14 @@ export class SessionRuntime {
|
|
|
368
389
|
#recent = [];
|
|
369
390
|
#archivedSessions = new Set();
|
|
370
391
|
#skillCommands = [];
|
|
392
|
+
/**
|
|
393
|
+
* Live argument vocabularies, keyed by command.
|
|
394
|
+
*
|
|
395
|
+
* A snapshot rather than a callback into the services: completion runs on every
|
|
396
|
+
* keystroke and must not await a catalog. It is rebuilt whenever the commands
|
|
397
|
+
* are pushed, which is also when a model or provider list can have changed.
|
|
398
|
+
*/
|
|
399
|
+
#argumentOptions = new Map();
|
|
371
400
|
#started = false;
|
|
372
401
|
#retired = [];
|
|
373
402
|
// Weak: deduplication must not retain disposed session graphs.
|
|
@@ -380,7 +409,6 @@ export class SessionRuntime {
|
|
|
380
409
|
#recentCache = new Map();
|
|
381
410
|
#libraryPath;
|
|
382
411
|
#recentRowsPath;
|
|
383
|
-
#upgradeMarkerPath;
|
|
384
412
|
#recentRowsLoaded = false;
|
|
385
413
|
#refreshInFlight = null;
|
|
386
414
|
#refreshDirty = false;
|
|
@@ -392,7 +420,6 @@ export class SessionRuntime {
|
|
|
392
420
|
this.#tui = tui;
|
|
393
421
|
this.#libraryPath = sessionLibraryPath(options.stateDir);
|
|
394
422
|
this.#recentRowsPath = options.stateDir === undefined ? undefined : join(options.stateDir, 'recent-sessions.json');
|
|
395
|
-
this.#upgradeMarkerPath = options.stateDir === undefined ? undefined : join(options.stateDir, 'sessions-upgraded.json');
|
|
396
423
|
this.#tracker = new SubagentTracker({
|
|
397
424
|
rootId: () => this.#active?.handle.agent.id,
|
|
398
425
|
depth: (session) => {
|
|
@@ -424,7 +451,7 @@ export class SessionRuntime {
|
|
|
424
451
|
const fileReferences = this.#ctx.get('fileReferences');
|
|
425
452
|
if (fileReferences !== undefined) {
|
|
426
453
|
tui.setFileSearch(async (query, signal) => {
|
|
427
|
-
const agent = this.#active?.handle.agent;
|
|
454
|
+
const agent = this.#inspectedId === undefined ? this.#active?.handle.agent : this.#ctx.get('agents')?.get(SessionId(this.#inspectedId));
|
|
428
455
|
if (agent === undefined)
|
|
429
456
|
return [];
|
|
430
457
|
return fileReferences.list(agent, query, signal ?? new AbortController().signal);
|
|
@@ -471,6 +498,9 @@ export class SessionRuntime {
|
|
|
471
498
|
this.#off.push(ctx.on('session/created', (session) => {
|
|
472
499
|
this.#tracker.noteSession(session);
|
|
473
500
|
}));
|
|
501
|
+
this.#off.push(ctx.on('subagent/start', info => { this.#tracker.noteExternalRun(info); }));
|
|
502
|
+
this.#off.push(ctx.on('subagent/end', info => { this.#tracker.noteExternalRun(info); }));
|
|
503
|
+
this.#off.push(ctx.on('subagent/external-activity', info => { this.#tracker.noteExternalActivity(info.id, info.activity); }));
|
|
474
504
|
this.#off.push(ctx.on('session/disposed', (session) => {
|
|
475
505
|
this.#tracker.noteGone(session);
|
|
476
506
|
}));
|
|
@@ -478,6 +508,13 @@ export class SessionRuntime {
|
|
|
478
508
|
const active = this.#active;
|
|
479
509
|
if (active === undefined)
|
|
480
510
|
return;
|
|
511
|
+
if (event.type === 'working-directory/change') {
|
|
512
|
+
if (session.id === (this.#inspectedId ?? active.handle.agent.id)) {
|
|
513
|
+
tui.setWorkingDirectory?.(currentWorkingDirectory(ctx, session));
|
|
514
|
+
}
|
|
515
|
+
if (session === active.handle.agent.session)
|
|
516
|
+
void this.#refreshSkills().catch(error => { ctx.logger.warn(error); });
|
|
517
|
+
}
|
|
481
518
|
if (session.id === this.#inspectedId) {
|
|
482
519
|
const child = ctx.get('agents')?.get(session.id);
|
|
483
520
|
tui.event(event, child === undefined ? undefined : ctx.get('tuiToolPresentation')?.event(child, event));
|
|
@@ -485,6 +522,8 @@ export class SessionRuntime {
|
|
|
485
522
|
return;
|
|
486
523
|
}
|
|
487
524
|
if (session === active.handle.agent.session) {
|
|
525
|
+
if (event.type === 'turn/end')
|
|
526
|
+
tui.setStatus(active.handle.agent.status, { root: true, outcome: event.data.reason.kind });
|
|
488
527
|
if (this.#workflows.apply(event))
|
|
489
528
|
tui.setSubagents(this.#workflows.roster(this.#tracker.snapshot()));
|
|
490
529
|
if (this.#inspectedId === undefined) {
|
|
@@ -545,13 +584,6 @@ export class SessionRuntime {
|
|
|
545
584
|
this.#pushSessionInfo();
|
|
546
585
|
}));
|
|
547
586
|
}
|
|
548
|
-
// One-time per session format, off the first render: stored logs an earlier
|
|
549
|
-
// release wrote get their current-format generation here rather than on the
|
|
550
|
-
// next listing or search that has to decode them.
|
|
551
|
-
ctx.inject(['sessionPersistence'], (persistenceCtx) => {
|
|
552
|
-
void this.#upgradeStoredSessions(persistenceCtx.sessionPersistence)
|
|
553
|
-
.catch((error) => { persistenceCtx.logger.warn(error); });
|
|
554
|
-
});
|
|
555
587
|
}
|
|
556
588
|
get agent() {
|
|
557
589
|
return this.#active?.handle.agent;
|
|
@@ -685,11 +717,11 @@ export class SessionRuntime {
|
|
|
685
717
|
active.contextWindow = resolved?.context?.contextWindow;
|
|
686
718
|
const status = modelStatus(selection, resolved);
|
|
687
719
|
active.reasoningEffort = status.reasoningEffort;
|
|
688
|
-
this.#tui.setModel(status.model, status.reasoningEffort);
|
|
689
|
-
this.#pushSessionInfo();
|
|
690
720
|
if (options?.persist !== false) {
|
|
691
721
|
await this.#ctx.get('agentDefaultModel')?.saveSelection(selection);
|
|
692
722
|
}
|
|
723
|
+
this.#tui.setModel(status.model, status.reasoningEffort);
|
|
724
|
+
this.#pushSessionInfo();
|
|
693
725
|
}
|
|
694
726
|
/** Start a new top-level session with the current model selection. */
|
|
695
727
|
async newSession(agent) {
|
|
@@ -806,7 +838,7 @@ export class SessionRuntime {
|
|
|
806
838
|
return {
|
|
807
839
|
label: label === undefined ? node.label : `◆ ${label} · ${node.label}`,
|
|
808
840
|
value: node.id, ...(node.parentId === undefined ? {} : { parentValue: node.parentId }),
|
|
809
|
-
preview: node.preview, description: node.description,
|
|
841
|
+
preview: node.preview, previewFormat: node.previewFormat, description: node.description,
|
|
810
842
|
submitLabel: node.kind === 'turn' ? 'edit from here' : 'continue branch',
|
|
811
843
|
...(node.current ? { badge: { label: 'Current', tone: 'success' } } : {}),
|
|
812
844
|
};
|
|
@@ -816,8 +848,9 @@ export class SessionRuntime {
|
|
|
816
848
|
{ key: 'Alt+L', label: 'label', valuePrefix: 'label:' },
|
|
817
849
|
{ key: 'Alt+U', label: 'clear label', valuePrefix: 'unlabel:' },
|
|
818
850
|
{ key: 'Alt+B', label: markedOnly ? 'full tree' : 'marked nodes', valuePrefix: 'marked:', scope: 'list' },
|
|
851
|
+
...(this.#ctx.get('omdshFileRecovery') === undefined ? [] : [{ key: 'Alt+R', label: 'restore Turn files', valuePrefix: 'restore:' }]),
|
|
819
852
|
],
|
|
820
|
-
...(selectedId === undefined ? {} : { initialValue: selectedId }), presentation: '
|
|
853
|
+
...(selectedId === undefined ? {} : { initialValue: selectedId }), presentation: 'tree', filterable: true, allowCustom: false, signal,
|
|
821
854
|
});
|
|
822
855
|
if (answer === null)
|
|
823
856
|
return;
|
|
@@ -829,6 +862,17 @@ export class SessionRuntime {
|
|
|
829
862
|
markedOnly = !markedOnly;
|
|
830
863
|
continue;
|
|
831
864
|
}
|
|
865
|
+
if (answer.startsWith('restore:')) {
|
|
866
|
+
const restoreId = answer.slice('restore:'.length);
|
|
867
|
+
const node = visible.find(item => item.id === restoreId);
|
|
868
|
+
if (node?.kind !== 'turn' || node.turn === undefined) {
|
|
869
|
+
this.#tui.notice('Select a Turn to restore its files.');
|
|
870
|
+
continue;
|
|
871
|
+
}
|
|
872
|
+
selectedId = node.id;
|
|
873
|
+
await reviewFileRecovery(this.#ctx, agent, node.sessionId, node.turn, signal, () => this.assertActive(agent));
|
|
874
|
+
continue;
|
|
875
|
+
}
|
|
832
876
|
const clear = answer.startsWith('unlabel:');
|
|
833
877
|
if (clear || answer.startsWith('label:')) {
|
|
834
878
|
const id = answer.slice(clear ? 'unlabel:'.length : 'label:'.length);
|
|
@@ -846,7 +890,7 @@ export class SessionRuntime {
|
|
|
846
890
|
const label = await this.#tui.prompt({
|
|
847
891
|
title: 'Label Conversation Node', question: `Label for ${node.label}`,
|
|
848
892
|
initialInput: draft, detail: error ?? 'Up to 120 characters. Alt+U in the tree clears a label.',
|
|
849
|
-
|
|
893
|
+
signal,
|
|
850
894
|
});
|
|
851
895
|
if (label === null)
|
|
852
896
|
break;
|
|
@@ -982,7 +1026,7 @@ export class SessionRuntime {
|
|
|
982
1026
|
}
|
|
983
1027
|
/** Agent presets available from the live Harness roster. */
|
|
984
1028
|
async agentPresets() {
|
|
985
|
-
return (await this.#ctx.agentPresets.list()).sort((left, right) => (left.order ?? Number.MAX_SAFE_INTEGER) - (right.order ?? Number.MAX_SAFE_INTEGER)
|
|
1029
|
+
return (await this.#ctx.agentPresets.list()).filter(preset => preset.id !== BTW_PRESET).sort((left, right) => (left.order ?? Number.MAX_SAFE_INTEGER) - (right.order ?? Number.MAX_SAFE_INTEGER)
|
|
986
1030
|
|| left.id.localeCompare(right.id));
|
|
987
1031
|
}
|
|
988
1032
|
/** Recompose one blank session, including the preset's fixed tool exposure. */
|
|
@@ -1004,16 +1048,6 @@ export class SessionRuntime {
|
|
|
1004
1048
|
this.#pushSessionInfo();
|
|
1005
1049
|
return active.agentPreset;
|
|
1006
1050
|
}
|
|
1007
|
-
/** Select the Harness Plan Mode controller and immediately refresh terminal state. */
|
|
1008
|
-
changeWorkflow(agent, active) {
|
|
1009
|
-
this.assertActive(agent);
|
|
1010
|
-
const planMode = this.#ctx.get('planMode');
|
|
1011
|
-
if (planMode === undefined)
|
|
1012
|
-
throw new Error('Plan workflow is not configured.');
|
|
1013
|
-
const outcome = planMode.set(agent, active);
|
|
1014
|
-
this.#pushSessionInfo();
|
|
1015
|
-
return outcome;
|
|
1016
|
-
}
|
|
1017
1051
|
/**
|
|
1018
1052
|
* Resolve and attach the changed-file summary a `workspace/changes` event
|
|
1019
1053
|
* announces.
|
|
@@ -1038,53 +1072,57 @@ export class SessionRuntime {
|
|
|
1038
1072
|
const { seq, data } = event;
|
|
1039
1073
|
queueMicrotask(() => {
|
|
1040
1074
|
const summary = service.summary(id, seq);
|
|
1041
|
-
if (summary
|
|
1042
|
-
|
|
1075
|
+
if (summary === undefined)
|
|
1076
|
+
return;
|
|
1077
|
+
tui.setWorkspaceSummary(data.turn, summary);
|
|
1078
|
+
const recorded = session.snapshotEvents().some(candidate => {
|
|
1079
|
+
const record = pluginRecordOf(candidate);
|
|
1080
|
+
return record?.type === 'plugin:omdsh/workspace-changes'
|
|
1081
|
+
&& typeof record.data === 'object'
|
|
1082
|
+
&& record.data !== null
|
|
1083
|
+
&& record.data.turn === data.turn;
|
|
1084
|
+
});
|
|
1085
|
+
if (!recorded) {
|
|
1086
|
+
try {
|
|
1087
|
+
appendPluginRecord(session, 'plugin:omdsh/workspace-changes', { turn: data.turn, summary });
|
|
1088
|
+
}
|
|
1089
|
+
catch {
|
|
1090
|
+
// A read-only or closed session log still keeps the in-memory summary.
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1043
1093
|
});
|
|
1044
1094
|
}
|
|
1045
1095
|
/**
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1049
|
-
*
|
|
1050
|
-
*
|
|
1096
|
+
* Rebuild the argument vocabularies the composer completes.
|
|
1097
|
+
*
|
|
1098
|
+
* A snapshot, because completion runs per keystroke: `/model provider/model`,
|
|
1099
|
+
* `/resume <id>` and `/login <provider>` are all names that already exist in
|
|
1100
|
+
* this process, so the reader types toward them instead of opening a picker.
|
|
1051
1101
|
*/
|
|
1052
|
-
async #
|
|
1053
|
-
const
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
continue;
|
|
1067
|
-
try {
|
|
1068
|
-
const handle = await persistence.open(snapshot.header.id, 'write');
|
|
1069
|
-
await handle.close();
|
|
1070
|
-
}
|
|
1071
|
-
catch (error) {
|
|
1072
|
-
// Another process owns it, or the log is unreadable: leave it alone.
|
|
1073
|
-
if (!(error instanceof SessionAlreadyOwnedError))
|
|
1074
|
-
this.#ctx.logger.debug(error);
|
|
1102
|
+
async #refreshArgumentOptions() {
|
|
1103
|
+
const options = new Map();
|
|
1104
|
+
const llm = this.#ctx.get('llm');
|
|
1105
|
+
if (llm !== undefined) {
|
|
1106
|
+
const models = [];
|
|
1107
|
+
const providers = [];
|
|
1108
|
+
for (const provider of llm.listProviders()) {
|
|
1109
|
+
providers.push({ value: provider.id, ...(provider.name === undefined ? {} : { description: provider.name }) });
|
|
1110
|
+
for (const model of await llm.listModels(provider.id)) {
|
|
1111
|
+
models.push({
|
|
1112
|
+
value: `${provider.id}/${model.id}`,
|
|
1113
|
+
...(model.name === undefined ? {} : { description: model.name }),
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1075
1116
|
}
|
|
1117
|
+
options.set('model', models);
|
|
1118
|
+
options.set('login', providers);
|
|
1076
1119
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
}
|
|
1084
|
-
writeJsonAtomic(markerPath, { sessionFormat: SESSION_FORMAT_VERSION });
|
|
1085
|
-
if (upgraded > 0) {
|
|
1086
|
-
this.#tui.notice(`Upgraded ${upgraded} stored session${upgraded === 1 ? '' : 's'} to the current format.`);
|
|
1087
|
-
}
|
|
1120
|
+
options.set('resume', this.#recent.map(row => ({
|
|
1121
|
+
value: row.id,
|
|
1122
|
+
...(row.title === undefined ? {} : { description: row.title }),
|
|
1123
|
+
})));
|
|
1124
|
+
this.#argumentOptions = options;
|
|
1125
|
+
this.#pushCommands();
|
|
1088
1126
|
}
|
|
1089
1127
|
async refreshRecent() {
|
|
1090
1128
|
// Coalesce concurrent callers: the recent list is one snapshot, and a
|
|
@@ -1108,6 +1146,9 @@ export class SessionRuntime {
|
|
|
1108
1146
|
}
|
|
1109
1147
|
async #refreshRecentNow() {
|
|
1110
1148
|
this.#archivedSessions = new Set(readSessionLibrary(this.#libraryPath).archived);
|
|
1149
|
+
// The recent list is what `/resume` completes from, so a refresh of one is a
|
|
1150
|
+
// refresh of the other. Deferred to avoid recursing through #pushCommands.
|
|
1151
|
+
queueMicrotask(() => { void this.#refreshArgumentOptions().catch(() => { }); });
|
|
1111
1152
|
const persistence = this.#ctx.get('sessionPersistence');
|
|
1112
1153
|
if (persistence === undefined) {
|
|
1113
1154
|
this.#recent = [];
|
|
@@ -1136,9 +1177,15 @@ export class SessionRuntime {
|
|
|
1136
1177
|
for (const snapshot of snapshots) {
|
|
1137
1178
|
const header = snapshot.header;
|
|
1138
1179
|
const cached = this.#recentCache.get(header.id);
|
|
1180
|
+
if (snapshot.formatStatus === 'migration-required') {
|
|
1181
|
+
// Do not open the log merely to browse it. A previous label is a hint;
|
|
1182
|
+
// the stored format classification always comes from this listing.
|
|
1183
|
+
rows.push({ ...(cached?.row ?? { id: header.id, title: header.id, createdAt: header.createdAt }), formatStatus: 'migration-required' });
|
|
1184
|
+
continue;
|
|
1185
|
+
}
|
|
1139
1186
|
if (cached?.revision === snapshot.revision) {
|
|
1140
1187
|
if (cached.row !== null)
|
|
1141
|
-
rows.push(cached.row);
|
|
1188
|
+
rows.push({ ...cached.row, ...(snapshot.formatStatus === undefined ? {} : { formatStatus: snapshot.formatStatus }) });
|
|
1142
1189
|
continue;
|
|
1143
1190
|
}
|
|
1144
1191
|
try {
|
|
@@ -1194,7 +1241,7 @@ export class SessionRuntime {
|
|
|
1194
1241
|
// Own every handle here so a late activation cannot double-release it.
|
|
1195
1242
|
for (const handle of handles)
|
|
1196
1243
|
this.#releasedHandles.add(handle);
|
|
1197
|
-
await
|
|
1244
|
+
await this.#disposeHandles(handles);
|
|
1198
1245
|
}
|
|
1199
1246
|
async #create(selection) {
|
|
1200
1247
|
const ref = { current: selection, assembled: undefined };
|
|
@@ -1330,15 +1377,15 @@ export class SessionRuntime {
|
|
|
1330
1377
|
this.#tui.setStatus(agent.status);
|
|
1331
1378
|
this.#tracker.sync();
|
|
1332
1379
|
this.#tui.setSubagents(this.#workflows.roster(this.#tracker.snapshot()));
|
|
1380
|
+
const selected = this.selection(agent);
|
|
1381
|
+
const status = modelStatus(selected, undefined);
|
|
1382
|
+
this.#tui.setModel(status.model, status.reasoningEffort ?? active.reasoningEffort);
|
|
1333
1383
|
// Seed welcome metadata before replaceSession commits the startup header to
|
|
1334
1384
|
// native scrollback; later updates cannot rewrite that frozen first frame.
|
|
1335
1385
|
this.#pushSessionInfo();
|
|
1336
1386
|
this.#replaceTranscript(agent, reason);
|
|
1337
1387
|
this.#pushTools();
|
|
1338
1388
|
this.#pushCommands();
|
|
1339
|
-
const selected = this.selection(agent);
|
|
1340
|
-
const status = modelStatus(selected, undefined);
|
|
1341
|
-
this.#tui.setModel(status.model, status.reasoningEffort ?? active.reasoningEffort);
|
|
1342
1389
|
}
|
|
1343
1390
|
/** Retire one agent handle once; a raced dispose takes it directly. */
|
|
1344
1391
|
#releaseHandle(handle) {
|
|
@@ -1354,11 +1401,15 @@ export class SessionRuntime {
|
|
|
1354
1401
|
#pushCommands() {
|
|
1355
1402
|
const agent = this.agent;
|
|
1356
1403
|
const runtime = agent === undefined ? [] : (this.#ctx.get('commands')?.list(agent) ?? []);
|
|
1357
|
-
const commands = runtime.map(command =>
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1404
|
+
const commands = runtime.map(command => {
|
|
1405
|
+
const options = this.#argumentOptions.get(command.name);
|
|
1406
|
+
return {
|
|
1407
|
+
name: command.name,
|
|
1408
|
+
description: command.description,
|
|
1409
|
+
...(command.input?.hint === undefined ? {} : { inputHint: command.input.hint }),
|
|
1410
|
+
...(options === undefined ? {} : { complete: (prefix) => matchArgumentOptions(options, prefix) }),
|
|
1411
|
+
};
|
|
1412
|
+
});
|
|
1362
1413
|
const names = new Set(commands.map(command => command.name));
|
|
1363
1414
|
for (const skill of this.#skillCommands) {
|
|
1364
1415
|
if (names.has(skill.name))
|
|
@@ -1385,7 +1436,10 @@ export class SessionRuntime {
|
|
|
1385
1436
|
this.#skillCommands = [];
|
|
1386
1437
|
}
|
|
1387
1438
|
else {
|
|
1388
|
-
const
|
|
1439
|
+
const cwd = currentWorkingDirectory(this.#ctx, agent.session);
|
|
1440
|
+
const list = await skills.list({ cwd, scope: agent, signal });
|
|
1441
|
+
if (this.#disposed || this.agent !== agent || currentWorkingDirectory(this.#ctx, agent.session) !== cwd)
|
|
1442
|
+
return;
|
|
1389
1443
|
this.#skillCommands = userSkillCommands(list);
|
|
1390
1444
|
}
|
|
1391
1445
|
this.#pushCommands();
|
|
@@ -1395,7 +1449,7 @@ export class SessionRuntime {
|
|
|
1395
1449
|
const skills = this.#ctx.get('skills');
|
|
1396
1450
|
if (skills === undefined)
|
|
1397
1451
|
return undefined;
|
|
1398
|
-
const list = await skills.list({ cwd: agent.session
|
|
1452
|
+
const list = await skills.list({ cwd: currentWorkingDirectory(this.#ctx, agent.session), scope: agent, signal });
|
|
1399
1453
|
return list.find(skill => skill.name === name && isUserInvocable(skill));
|
|
1400
1454
|
}
|
|
1401
1455
|
#lookupSession = (id) => this.#ctx.get('sessions')?.get(SessionId(id));
|
|
@@ -1456,6 +1510,7 @@ export class SessionRuntime {
|
|
|
1456
1510
|
});
|
|
1457
1511
|
}
|
|
1458
1512
|
#replaceTranscript(agent, reason = 'refresh') {
|
|
1513
|
+
this.#tui.setWorkingDirectory?.(currentWorkingDirectory(this.#ctx, agent.session));
|
|
1459
1514
|
const events = agent.session.snapshotEvents();
|
|
1460
1515
|
this.#tracker.observeCatalog(agent.session, events);
|
|
1461
1516
|
this.#tui.replaceSession(events, this.#ctx.get('tuiToolPresentation')?.session(agent, events), agent.status, reason);
|
|
@@ -1489,7 +1544,12 @@ export class SessionRuntime {
|
|
|
1489
1544
|
this.#tui.notice('That subagent is no longer available.', { level: 'error' });
|
|
1490
1545
|
return;
|
|
1491
1546
|
}
|
|
1547
|
+
if (this.#tracker.snapshot()?.agents.find(agent => agent.id === id)?.mode === 'external') {
|
|
1548
|
+
this.#tui.notice('External executions have no local transcript. Their results appear in the parent session.');
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1492
1551
|
const live = this.#ctx.get('sessions')?.get(SessionId(id));
|
|
1552
|
+
let cwd = live === undefined ? undefined : currentWorkingDirectory(this.#ctx, live);
|
|
1493
1553
|
let events;
|
|
1494
1554
|
if (live !== undefined) {
|
|
1495
1555
|
events = live.ownEvents();
|
|
@@ -1501,6 +1561,8 @@ export class SessionRuntime {
|
|
|
1501
1561
|
if (log === undefined)
|
|
1502
1562
|
throw new Error('subagent transcript is unavailable');
|
|
1503
1563
|
events = log.events.slice(log.inheritedEventCount);
|
|
1564
|
+
const change = log.events.findLast(event => event.type === 'working-directory/change');
|
|
1565
|
+
cwd = change?.type === 'working-directory/change' ? change.data.cwd : log.header.cwd;
|
|
1504
1566
|
}
|
|
1505
1567
|
catch {
|
|
1506
1568
|
if (request === this.#inspectEpoch) {
|
|
@@ -1512,6 +1574,8 @@ export class SessionRuntime {
|
|
|
1512
1574
|
if (request !== this.#inspectEpoch)
|
|
1513
1575
|
return;
|
|
1514
1576
|
this.#inspectedId = id;
|
|
1577
|
+
if (cwd !== undefined)
|
|
1578
|
+
this.#tui.setWorkingDirectory?.(cwd);
|
|
1515
1579
|
const child = this.#ctx.get('agents')?.get(SessionId(id));
|
|
1516
1580
|
this.#tui.replaceSession(events, child === undefined ? undefined : this.#ctx.get('tuiToolPresentation')?.session(child, events), child?.status ?? 'idle', 'refresh');
|
|
1517
1581
|
this.#replayLivePrefix(id);
|
|
@@ -1586,7 +1650,28 @@ export class SessionRuntime {
|
|
|
1586
1650
|
return this.#requiredActive().handle.agent;
|
|
1587
1651
|
}
|
|
1588
1652
|
async #disposeRetired() {
|
|
1589
|
-
await
|
|
1653
|
+
await this.#disposeHandles(this.#retired.splice(0));
|
|
1654
|
+
}
|
|
1655
|
+
async #disposeHandles(handles) {
|
|
1656
|
+
if (handles.length === 0)
|
|
1657
|
+
return;
|
|
1658
|
+
try {
|
|
1659
|
+
await this.#ctx.get('subagents')?.drainDescendants(handles.map(handle => handle.agent));
|
|
1660
|
+
}
|
|
1661
|
+
catch (error) {
|
|
1662
|
+
this.#ctx.logger.warn(error);
|
|
1663
|
+
}
|
|
1664
|
+
finally {
|
|
1665
|
+
await Promise.allSettled(handles.map(handle => handle.dispose()));
|
|
1666
|
+
}
|
|
1590
1667
|
}
|
|
1591
1668
|
}
|
|
1669
|
+
/** Candidates for an argument prefix, matched the way the command list matches. */
|
|
1670
|
+
export function matchArgumentOptions(options, prefix) {
|
|
1671
|
+
const lower = prefix.trim().toLowerCase();
|
|
1672
|
+
if (lower === '')
|
|
1673
|
+
return options;
|
|
1674
|
+
return options.filter(option => option.value.toLowerCase().includes(lower)
|
|
1675
|
+
|| (option.description ?? '').toLowerCase().includes(lower));
|
|
1676
|
+
}
|
|
1592
1677
|
//# sourceMappingURL=session-controller.js.map
|