@agi-fans/dsh-tui 0.16.0 → 0.17.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 +18 -1
- package/lib/chrome/tool-args.d.ts +9 -0
- package/lib/chrome/tool-args.js +20 -0
- package/lib/chrome/tool-args.js.map +1 -0
- package/lib/chrome/tool-renderers.js +4 -13
- package/lib/chrome/tool-renderers.js.map +1 -1
- package/lib/commands/session.js +2 -4
- package/lib/commands/session.js.map +1 -1
- package/lib/runtime/composer-images.d.ts +44 -0
- package/lib/runtime/composer-images.js +149 -0
- package/lib/runtime/composer-images.js.map +1 -0
- package/lib/runtime/herdr-agent.d.ts +95 -0
- package/lib/runtime/herdr-agent.js +258 -0
- package/lib/runtime/herdr-agent.js.map +1 -0
- package/lib/runtime/plain-tui.d.ts +34 -0
- package/lib/runtime/plain-tui.js +119 -0
- package/lib/runtime/plain-tui.js.map +1 -0
- package/lib/runtime/provider-local.d.ts +3 -0
- package/lib/runtime/provider-local.js +107 -268
- package/lib/runtime/provider-local.js.map +1 -1
- package/lib/runtime/tool-presentation.js +15 -0
- package/lib/runtime/tool-presentation.js.map +1 -1
- package/lib/session/content-text.d.ts +12 -0
- package/lib/session/content-text.js +13 -0
- package/lib/session/content-text.js.map +1 -0
- package/lib/session/history-store.js.map +1 -0
- package/lib/session/json-file.d.ts +5 -0
- package/lib/session/json-file.js +21 -0
- package/lib/session/json-file.js.map +1 -0
- package/lib/session/model-favorites.js +15 -25
- package/lib/session/model-favorites.js.map +1 -1
- package/lib/session/release-notes.js +1 -18
- package/lib/session/release-notes.js.map +1 -1
- package/lib/session/session-controller.js +64 -140
- package/lib/session/session-controller.js.map +1 -1
- package/lib/session/session-library.js +4 -14
- package/lib/session/session-library.js.map +1 -1
- package/lib/session/subagent-roster.js +13 -43
- package/lib/session/subagent-roster.js.map +1 -1
- package/lib/session/subagent-tracker.d.ts +58 -0
- package/lib/session/subagent-tracker.js +129 -0
- package/lib/session/subagent-tracker.js.map +1 -0
- package/lib/session/update-check.js +2 -15
- package/lib/session/update-check.js.map +1 -1
- package/lib/session/version-compare.d.ts +3 -0
- package/lib/session/version-compare.js +21 -0
- package/lib/session/version-compare.js.map +1 -0
- package/lib/views/event-views.d.ts +11 -270
- package/lib/views/event-views.js +12 -964
- package/lib/views/event-views.js.map +1 -1
- package/lib/views/settings-list.js +12 -11
- package/lib/views/settings-list.js.map +1 -1
- package/lib/views/transcript-render.d.ts +179 -0
- package/lib/views/transcript-render.js +916 -0
- package/lib/views/transcript-render.js.map +1 -0
- package/lib/views/transcript-types.d.ts +104 -0
- package/lib/views/transcript-types.js +53 -0
- package/lib/views/transcript-types.js.map +1 -0
- package/package.json +2 -1
- package/lib/views/history-store.js.map +0 -1
- /package/lib/{views → session}/history-store.d.ts +0 -0
- /package/lib/{views → session}/history-store.js +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/** Durable, product-owned model favorites used by keyboard model cycling. */
|
|
2
|
-
import {
|
|
3
|
-
import { dirname } from 'node:path';
|
|
2
|
+
import { readJsonFile, writeJsonAtomic } from "./json-file.js";
|
|
4
3
|
const MAX_FAVORITES = 16;
|
|
5
4
|
function favorite(value) {
|
|
6
5
|
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
@@ -22,33 +21,24 @@ function key(value) {
|
|
|
22
21
|
return `${value.provider}\0${value.model}`;
|
|
23
22
|
}
|
|
24
23
|
export function readModelFavorites(path) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (!Array.isArray(parsed))
|
|
28
|
-
return [];
|
|
29
|
-
const seen = new Set();
|
|
30
|
-
const result = [];
|
|
31
|
-
for (const value of parsed) {
|
|
32
|
-
const entry = favorite(value);
|
|
33
|
-
if (entry === undefined || seen.has(key(entry)))
|
|
34
|
-
continue;
|
|
35
|
-
seen.add(key(entry));
|
|
36
|
-
result.push(entry);
|
|
37
|
-
if (result.length >= MAX_FAVORITES)
|
|
38
|
-
break;
|
|
39
|
-
}
|
|
40
|
-
return result;
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
24
|
+
const parsed = readJsonFile(path);
|
|
25
|
+
if (!Array.isArray(parsed))
|
|
43
26
|
return [];
|
|
27
|
+
const seen = new Set();
|
|
28
|
+
const result = [];
|
|
29
|
+
for (const value of parsed) {
|
|
30
|
+
const entry = favorite(value);
|
|
31
|
+
if (entry === undefined || seen.has(key(entry)))
|
|
32
|
+
continue;
|
|
33
|
+
seen.add(key(entry));
|
|
34
|
+
result.push(entry);
|
|
35
|
+
if (result.length >= MAX_FAVORITES)
|
|
36
|
+
break;
|
|
44
37
|
}
|
|
38
|
+
return result;
|
|
45
39
|
}
|
|
46
40
|
export function writeModelFavorites(path, favorites) {
|
|
47
|
-
|
|
48
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
49
|
-
const temporary = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
50
|
-
writeFileSync(temporary, JSON.stringify(normalized, null, 2) + '\n', { encoding: 'utf8', mode: 0o600 });
|
|
51
|
-
renameSync(temporary, path);
|
|
41
|
+
writeJsonAtomic(path, readDistinct(favorites));
|
|
52
42
|
}
|
|
53
43
|
export function addModelFavorite(favorites, entry) {
|
|
54
44
|
return [...favorites.filter(item => key(item) !== key(entry)), entry].slice(-MAX_FAVORITES);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-favorites.js","sourceRoot":"","sources":["../../src/session/model-favorites.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"model-favorites.js","sourceRoot":"","sources":["../../src/session/model-favorites.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,23 +1,6 @@
|
|
|
1
1
|
/** Keep a Changelog parsing and startup release-note selection. */
|
|
2
|
+
import { compareVersions } from "./version-compare.js";
|
|
2
3
|
export const STARTUP_CHANGELOG_MODES = ['summary', 'expanded', 'hidden'];
|
|
3
|
-
function versionParts(version) {
|
|
4
|
-
const match = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/u.exec(version);
|
|
5
|
-
if (match?.[1] === undefined || match[2] === undefined || match[3] === undefined)
|
|
6
|
-
return undefined;
|
|
7
|
-
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
8
|
-
}
|
|
9
|
-
function compareVersions(left, right) {
|
|
10
|
-
const a = versionParts(left);
|
|
11
|
-
const b = versionParts(right);
|
|
12
|
-
if (a === undefined || b === undefined)
|
|
13
|
-
return 0;
|
|
14
|
-
for (let index = 0; index < a.length; index += 1) {
|
|
15
|
-
const difference = (a[index] ?? 0) - (b[index] ?? 0);
|
|
16
|
-
if (difference !== 0)
|
|
17
|
-
return difference;
|
|
18
|
-
}
|
|
19
|
-
return 0;
|
|
20
|
-
}
|
|
21
4
|
function countCategories(markdown) {
|
|
22
5
|
const counts = {};
|
|
23
6
|
let category;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-notes.js","sourceRoot":"","sources":["../../src/session/release-notes.ts"],"names":[],"mappings":"AAAA,mEAAmE;
|
|
1
|
+
{"version":3,"file":"release-notes.js","sourceRoot":"","sources":["../../src/session/release-notes.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,8 +15,10 @@ import { SessionId, SessionLogOffset } from '@deepseek-ai/dsh-session';
|
|
|
15
15
|
import { queueHostSubagentPrompt } from '@deepseek-ai/dsh-subagent/internal';
|
|
16
16
|
import { firstVisibleStreamTime } from "../views/stream-time.js";
|
|
17
17
|
import { LiveAttemptTracker } from "./live-attempt-tracker.js";
|
|
18
|
+
import { blocksText } from "./content-text.js";
|
|
18
19
|
import { jobNoticeFor } from "./job-notice.js";
|
|
19
|
-
import { descendantDepth, isSteerableSubagent
|
|
20
|
+
import { descendantDepth, isSteerableSubagent } from "./subagent-roster.js";
|
|
21
|
+
import { SubagentTracker } from "./subagent-tracker.js";
|
|
20
22
|
import { commandPermission } from "../commands/permission.js";
|
|
21
23
|
import { isBlankSession, toolPresentationForPreset, } from "./session-configuration.js";
|
|
22
24
|
import { stripComposerImageMarkers } from "../input/image-paste.js";
|
|
@@ -245,12 +247,7 @@ function explicitSessionTitle(events) {
|
|
|
245
247
|
function humanMessageText(event) {
|
|
246
248
|
if (event.type !== 'user/message' || event.data.source.kind !== 'user')
|
|
247
249
|
return undefined;
|
|
248
|
-
const text = event.data.content
|
|
249
|
-
.filter((block) => block.type === 'text')
|
|
250
|
-
.map(block => block.text)
|
|
251
|
-
.join(' ')
|
|
252
|
-
.replace(/\s+/gu, ' ')
|
|
253
|
-
.trim();
|
|
250
|
+
const text = blocksText(event.data.content, { collapse: true });
|
|
254
251
|
return text === '' ? undefined : text;
|
|
255
252
|
}
|
|
256
253
|
/** Find direct human messages whose preceding log prefix is safe to seed into a fork. */
|
|
@@ -270,12 +267,7 @@ export function conversationTurns(events) {
|
|
|
270
267
|
}
|
|
271
268
|
if (open === undefined || event.type !== 'user/message' || event.data.source.kind !== 'user')
|
|
272
269
|
continue;
|
|
273
|
-
const text = event.data.content
|
|
274
|
-
.filter((block) => block.type === 'text')
|
|
275
|
-
.map(block => block.text)
|
|
276
|
-
.join('\n')
|
|
277
|
-
.replace(/\s+/gu, ' ')
|
|
278
|
-
.trim();
|
|
270
|
+
const text = blocksText(event.data.content, { collapse: true });
|
|
279
271
|
const imageCount = event.data.content.filter(block => block.type === 'image').length;
|
|
280
272
|
if (text === '' && imageCount === 0)
|
|
281
273
|
continue;
|
|
@@ -364,10 +356,7 @@ export function encodeCommandAttachments(images) {
|
|
|
364
356
|
}
|
|
365
357
|
/** Rehydrate one durable human inbox message into an editable composer draft. */
|
|
366
358
|
export async function restoreSubmissionMessage(message, attachments) {
|
|
367
|
-
const text = message.content
|
|
368
|
-
.filter((block) => block.type === 'text')
|
|
369
|
-
.map(block => block.text)
|
|
370
|
-
.join('\n');
|
|
359
|
+
const text = blocksText(message.content);
|
|
371
360
|
const refs = message.content
|
|
372
361
|
.filter((block) => block.type === 'image')
|
|
373
362
|
.map(block => block.attachment);
|
|
@@ -401,19 +390,33 @@ export class SessionRuntime {
|
|
|
401
390
|
#releasedHandles = new WeakSet();
|
|
402
391
|
#disposed = false;
|
|
403
392
|
#off = [];
|
|
404
|
-
#
|
|
405
|
-
#publishedSubagents;
|
|
393
|
+
#tracker;
|
|
406
394
|
#streamAttempts = new LiveAttemptTracker();
|
|
407
395
|
#recentCache = new Map();
|
|
408
396
|
#refreshInFlight = null;
|
|
409
397
|
#refreshDirty = false;
|
|
410
|
-
#subagentEpoch = 0;
|
|
411
398
|
#inspectEpoch = 0;
|
|
412
399
|
#activationEpoch = 0;
|
|
413
400
|
#inspectedId;
|
|
414
401
|
constructor(ctx, tui) {
|
|
415
402
|
this.#ctx = ctx;
|
|
416
403
|
this.#tui = tui;
|
|
404
|
+
this.#tracker = new SubagentTracker({
|
|
405
|
+
rootId: () => this.#active?.handle.agent.id,
|
|
406
|
+
depth: (session) => {
|
|
407
|
+
const rootId = this.#active?.handle.agent.id;
|
|
408
|
+
return rootId === undefined ? undefined : descendantDepth(session, rootId, this.#lookupSession);
|
|
409
|
+
},
|
|
410
|
+
agentStatus: id => this.#ctx.get('agents')?.get(SessionId(id))?.status,
|
|
411
|
+
sessions: () => this.#ctx.get('sessions')?.list() ?? [],
|
|
412
|
+
listChildren: rootId => this.#ctx.get('subagents')?.listChildren(SessionId(rootId)),
|
|
413
|
+
publish: (roster) => {
|
|
414
|
+
this.#tui.setSubagents(roster);
|
|
415
|
+
if (this.#inspectedId === undefined)
|
|
416
|
+
return;
|
|
417
|
+
this.#tui.setInspectedSubagent(this.#inspectView(this.#inspectedId));
|
|
418
|
+
},
|
|
419
|
+
});
|
|
417
420
|
this.#off.push(tui.onInspectSubagent(id => { void this.#inspectSubagent(id); }));
|
|
418
421
|
this.#off.push(tui.onInspectClose(() => { this.#closeInspect(); }));
|
|
419
422
|
this.#off.push(tui.onInspectSubmit(submission => { void this.#steerInspected(submission); }));
|
|
@@ -457,16 +460,13 @@ export class SessionRuntime {
|
|
|
457
460
|
}
|
|
458
461
|
if (payload.agent.id === this.#inspectedId)
|
|
459
462
|
tui.setStatus(payload.status);
|
|
460
|
-
this.#
|
|
463
|
+
this.#tracker.noteStatus(payload.agent.session, payload.status);
|
|
461
464
|
}));
|
|
462
465
|
this.#off.push(ctx.on('session/created', (session) => {
|
|
463
|
-
this.#
|
|
466
|
+
this.#tracker.noteSession(session);
|
|
464
467
|
}));
|
|
465
468
|
this.#off.push(ctx.on('session/disposed', (session) => {
|
|
466
|
-
|
|
467
|
-
return;
|
|
468
|
-
this.#subagents.setAgentStatus(session.id, 'gone');
|
|
469
|
-
this.#pushSubagents();
|
|
469
|
+
this.#tracker.noteGone(session);
|
|
470
470
|
}));
|
|
471
471
|
this.#off.push(ctx.on('session/event', (session, event) => {
|
|
472
472
|
const active = this.#active;
|
|
@@ -475,7 +475,7 @@ export class SessionRuntime {
|
|
|
475
475
|
if (session.id === this.#inspectedId) {
|
|
476
476
|
const child = ctx.get('agents')?.get(session.id);
|
|
477
477
|
tui.event(event, child === undefined ? undefined : ctx.get('tuiToolPresentation')?.event(child, event));
|
|
478
|
-
this.#
|
|
478
|
+
this.#tracker.noteEvent(session, event);
|
|
479
479
|
return;
|
|
480
480
|
}
|
|
481
481
|
if (session === active.handle.agent.session) {
|
|
@@ -483,14 +483,14 @@ export class SessionRuntime {
|
|
|
483
483
|
tui.event(event, ctx.get('tuiToolPresentation')?.event(active.handle.agent, event));
|
|
484
484
|
}
|
|
485
485
|
if (event.type === 'subagent/catalog')
|
|
486
|
-
this.#
|
|
486
|
+
this.#tracker.observeCatalog(session, [event]);
|
|
487
487
|
if (shouldRefreshSessionInfoAfter(event))
|
|
488
488
|
this.#pushSessionInfo();
|
|
489
489
|
if (event.type === 'session/title')
|
|
490
490
|
void this.refreshRecent();
|
|
491
491
|
return;
|
|
492
492
|
}
|
|
493
|
-
this.#
|
|
493
|
+
this.#tracker.noteEvent(session, event);
|
|
494
494
|
}));
|
|
495
495
|
// Format v2 moved live assistant increments off the session log. The
|
|
496
496
|
// durable `session/event` firehose now carries only settlements; chunk
|
|
@@ -760,10 +760,7 @@ export class SessionRuntime {
|
|
|
760
760
|
if (message?.type !== 'user/message' || message.data.source.kind !== 'user') {
|
|
761
761
|
throw new Error('The selected conversation turn is no longer available.');
|
|
762
762
|
}
|
|
763
|
-
const text = message.data.content
|
|
764
|
-
.filter((block) => block.type === 'text')
|
|
765
|
-
.map(block => block.text)
|
|
766
|
-
.join('\n');
|
|
763
|
+
const text = blocksText(message.data.content);
|
|
767
764
|
const imageRefs = message.data.content
|
|
768
765
|
.filter((block) => block.type === 'image')
|
|
769
766
|
.map(block => block.attachment);
|
|
@@ -964,10 +961,9 @@ export class SessionRuntime {
|
|
|
964
961
|
if (this.#disposed)
|
|
965
962
|
return;
|
|
966
963
|
this.#disposed = true;
|
|
967
|
-
this.#subagentEpoch += 1;
|
|
968
964
|
this.#activationEpoch += 1;
|
|
969
965
|
this.#inspectedId = undefined;
|
|
970
|
-
this.#
|
|
966
|
+
this.#tracker.reset();
|
|
971
967
|
this.#tui.setInspectedSubagent(undefined);
|
|
972
968
|
this.#tui.setSubagents(undefined);
|
|
973
969
|
this.#tui.setSessionSearch();
|
|
@@ -1009,6 +1005,28 @@ export class SessionRuntime {
|
|
|
1009
1005
|
disposeToolPresentation: configuration.disposeToolPresentation,
|
|
1010
1006
|
};
|
|
1011
1007
|
}
|
|
1008
|
+
/**
|
|
1009
|
+
* Claim the activated session into the cwd workspace so grouped session
|
|
1010
|
+
* surfaces (the harness web sidebar) file it instead of leaving it
|
|
1011
|
+
* ungrouped. Best-effort like `#resolveModelInfo`: the registry is an
|
|
1012
|
+
* optional service and a failed claim must not disturb activation.
|
|
1013
|
+
*/
|
|
1014
|
+
async #claimWorkspace(active) {
|
|
1015
|
+
const registry = this.#ctx.get('workspaceRegistry');
|
|
1016
|
+
if (registry === undefined)
|
|
1017
|
+
return;
|
|
1018
|
+
try {
|
|
1019
|
+
const { session } = active.handle.agent;
|
|
1020
|
+
const cwd = session.header.cwd;
|
|
1021
|
+
if (cwd === undefined)
|
|
1022
|
+
return;
|
|
1023
|
+
const workspace = await registry.resolveByPath(cwd) ?? await registry.create(cwd);
|
|
1024
|
+
await workspace.attachSession(session.id);
|
|
1025
|
+
}
|
|
1026
|
+
catch {
|
|
1027
|
+
// The workspace claim is cosmetic interop; the session itself is fine.
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1012
1030
|
async #resolveModelInfo(selection) {
|
|
1013
1031
|
try {
|
|
1014
1032
|
return await this.#ctx.get('llm')?.resolveModelInfo(selection.provider, selection.model);
|
|
@@ -1026,6 +1044,7 @@ export class SessionRuntime {
|
|
|
1026
1044
|
const previous = this.#active;
|
|
1027
1045
|
const epoch = ++this.#activationEpoch;
|
|
1028
1046
|
this.#active = next;
|
|
1047
|
+
void this.#claimWorkspace(next);
|
|
1029
1048
|
try {
|
|
1030
1049
|
this.#presentAgent(next);
|
|
1031
1050
|
const selected = this.selection(next.handle.agent);
|
|
@@ -1093,7 +1112,7 @@ export class SessionRuntime {
|
|
|
1093
1112
|
this.#inspectedId = undefined;
|
|
1094
1113
|
this.#tui.setInspectedSubagent(undefined);
|
|
1095
1114
|
this.#tui.setStatus(agent.status);
|
|
1096
|
-
this.#
|
|
1115
|
+
this.#tracker.sync();
|
|
1097
1116
|
// Seed welcome metadata before replaceSession commits the startup header to
|
|
1098
1117
|
// native scrollback; later updates cannot rewrite that frozen first frame.
|
|
1099
1118
|
this.#pushSessionInfo();
|
|
@@ -1163,45 +1182,6 @@ export class SessionRuntime {
|
|
|
1163
1182
|
return list.find(skill => skill.name === name && isUserInvocable(skill));
|
|
1164
1183
|
}
|
|
1165
1184
|
#lookupSession = (id) => this.#ctx.get('sessions')?.get(SessionId(id));
|
|
1166
|
-
#subagentDepth(session) {
|
|
1167
|
-
const rootId = this.#active?.handle.agent.id;
|
|
1168
|
-
if (rootId === undefined)
|
|
1169
|
-
return undefined;
|
|
1170
|
-
return descendantDepth(session, rootId, this.#lookupSession);
|
|
1171
|
-
}
|
|
1172
|
-
#noteSubagentSession(session) {
|
|
1173
|
-
const depth = this.#subagentDepth(session);
|
|
1174
|
-
if (depth === undefined)
|
|
1175
|
-
return;
|
|
1176
|
-
const parentId = session.header.parentSession;
|
|
1177
|
-
this.#subagents.remember({
|
|
1178
|
-
id: session.id,
|
|
1179
|
-
...(parentId === undefined ? {} : { parentId }),
|
|
1180
|
-
depth,
|
|
1181
|
-
phase: this.#ctx.get('agents')?.get(session.id)?.status === 'running' ? 'running' : 'starting',
|
|
1182
|
-
});
|
|
1183
|
-
this.#pushSubagents();
|
|
1184
|
-
}
|
|
1185
|
-
#noteSubagentEvent(session, event) {
|
|
1186
|
-
const depth = this.#subagentDepth(session);
|
|
1187
|
-
if (depth === undefined)
|
|
1188
|
-
return;
|
|
1189
|
-
this.#subagents.apply(session, depth, event, this.#ctx.get('agents')?.get(session.id)?.status);
|
|
1190
|
-
this.#pushSubagents();
|
|
1191
|
-
}
|
|
1192
|
-
/**
|
|
1193
|
-
* Add the direct children a Session's durable catalog declares.
|
|
1194
|
-
*
|
|
1195
|
-
* The live roster is built from `session/created` and child events, so a
|
|
1196
|
-
* resumed parent would otherwise show nothing: its children are neither
|
|
1197
|
-
* loaded nor replayed. Catalog facts are durable, so a restored roster still
|
|
1198
|
-
* lists those children, and `#inspectSubagent` opens each transcript from
|
|
1199
|
-
* disk. Children the live path already knows keep their own state.
|
|
1200
|
-
*/
|
|
1201
|
-
#observeCatalogChildren(session, events) {
|
|
1202
|
-
if (this.#subagents.observeCatalog(session.id, events))
|
|
1203
|
-
this.#pushSubagents();
|
|
1204
|
-
}
|
|
1205
1185
|
/** Route live output only to the visible session; background frames remain buffered for inspection. */
|
|
1206
1186
|
#forwardLiveDelta(agent, delta) {
|
|
1207
1187
|
const active = this.#active;
|
|
@@ -1229,57 +1209,8 @@ export class SessionRuntime {
|
|
|
1229
1209
|
this.#tui.streamDelta(delta);
|
|
1230
1210
|
}
|
|
1231
1211
|
}
|
|
1232
|
-
#noteSubagentStatus(session, status) {
|
|
1233
|
-
if (this.#subagents.owns(session.id)) {
|
|
1234
|
-
this.#subagents.setAgentStatus(session.id, status);
|
|
1235
|
-
this.#pushSubagents();
|
|
1236
|
-
return;
|
|
1237
|
-
}
|
|
1238
|
-
const depth = this.#subagentDepth(session);
|
|
1239
|
-
if (depth === undefined)
|
|
1240
|
-
return;
|
|
1241
|
-
this.#subagents.hydrate(session, depth, this.#ctx.get('agents')?.get(session.id)?.status ?? status);
|
|
1242
|
-
this.#pushSubagents();
|
|
1243
|
-
}
|
|
1244
|
-
#syncSubagents() {
|
|
1245
|
-
const root = this.#active?.handle.agent;
|
|
1246
|
-
const epoch = this.#subagentEpoch + 1;
|
|
1247
|
-
this.#subagentEpoch = epoch;
|
|
1248
|
-
if (root === undefined) {
|
|
1249
|
-
this.#subagents.reset();
|
|
1250
|
-
this.#tui.setSubagents(undefined);
|
|
1251
|
-
return;
|
|
1252
|
-
}
|
|
1253
|
-
this.#subagents.reset(root.id);
|
|
1254
|
-
for (const session of this.#ctx.get('sessions')?.list() ?? []) {
|
|
1255
|
-
const depth = descendantDepth(session, root.id, this.#lookupSession);
|
|
1256
|
-
if (depth === undefined)
|
|
1257
|
-
continue;
|
|
1258
|
-
this.#subagents.hydrate(session, depth, this.#ctx.get('agents')?.get(session.id)?.status);
|
|
1259
|
-
}
|
|
1260
|
-
this.#pushSubagents();
|
|
1261
|
-
const listed = this.#ctx.get('subagents')?.listChildren(root.id);
|
|
1262
|
-
if (listed === undefined)
|
|
1263
|
-
return;
|
|
1264
|
-
void listed.then((entries) => {
|
|
1265
|
-
if (epoch !== this.#subagentEpoch || this.#active?.handle.agent !== root)
|
|
1266
|
-
return;
|
|
1267
|
-
for (const entry of entries) {
|
|
1268
|
-
if (entry.kind !== 'child')
|
|
1269
|
-
continue;
|
|
1270
|
-
this.#subagents.remember({
|
|
1271
|
-
id: entry.id,
|
|
1272
|
-
depth: 1,
|
|
1273
|
-
mode: entry.mode,
|
|
1274
|
-
...(entry.label === undefined ? {} : { label: entry.label }),
|
|
1275
|
-
phase: entry.activity === 'running' ? 'running' : 'waiting',
|
|
1276
|
-
});
|
|
1277
|
-
}
|
|
1278
|
-
this.#pushSubagents();
|
|
1279
|
-
}, () => undefined);
|
|
1280
|
-
}
|
|
1281
1212
|
#inspectView(id, fallbackPhase = 'waiting') {
|
|
1282
|
-
const view = this.#
|
|
1213
|
+
const view = this.#tracker.snapshot()?.agents.find(agent => agent.id === id);
|
|
1283
1214
|
const mode = view?.mode;
|
|
1284
1215
|
return {
|
|
1285
1216
|
id,
|
|
@@ -1289,28 +1220,21 @@ export class SessionRuntime {
|
|
|
1289
1220
|
writable: isSteerableSubagent(mode),
|
|
1290
1221
|
};
|
|
1291
1222
|
}
|
|
1292
|
-
#pushSubagents() {
|
|
1293
|
-
const roster = this.#subagents.snapshot();
|
|
1294
|
-
if (roster === this.#publishedSubagents)
|
|
1295
|
-
return;
|
|
1296
|
-
this.#publishedSubagents = roster;
|
|
1297
|
-
this.#tui.setSubagents(roster);
|
|
1298
|
-
if (this.#inspectedId === undefined)
|
|
1299
|
-
return;
|
|
1300
|
-
this.#tui.setInspectedSubagent(this.#inspectView(this.#inspectedId));
|
|
1301
|
-
}
|
|
1302
1223
|
#pushSessionInfo() {
|
|
1303
1224
|
const active = this.#active;
|
|
1304
1225
|
if (active === undefined)
|
|
1305
1226
|
return;
|
|
1306
1227
|
const agent = active.handle.agent;
|
|
1307
1228
|
const projection = this.#projection(active);
|
|
1308
|
-
|
|
1229
|
+
// One snapshot feeds both folds; each append invalidates the session's
|
|
1230
|
+
// cached snapshot, so a second call would pay another O(log) copy.
|
|
1231
|
+
const events = agent.session.snapshotEvents();
|
|
1232
|
+
const title = explicitSessionTitle(events);
|
|
1309
1233
|
this.#tui.setSession({
|
|
1310
1234
|
id: agent.id,
|
|
1311
1235
|
...(title === undefined ? {} : { title }),
|
|
1312
1236
|
recent: this.#recent.filter(row => row.id !== agent.id),
|
|
1313
|
-
stats:
|
|
1237
|
+
stats: sessionStats(events, active.contextWindow, projection),
|
|
1314
1238
|
controls: this.#sessionControls(active, projection),
|
|
1315
1239
|
});
|
|
1316
1240
|
}
|
|
@@ -1333,7 +1257,7 @@ export class SessionRuntime {
|
|
|
1333
1257
|
}
|
|
1334
1258
|
#replaceTranscript(agent) {
|
|
1335
1259
|
const events = agent.session.snapshotEvents();
|
|
1336
|
-
this.#
|
|
1260
|
+
this.#tracker.observeCatalog(agent.session, events);
|
|
1337
1261
|
this.#tui.replaceSession(events, this.#ctx.get('tuiToolPresentation')?.session(agent, events), agent.status);
|
|
1338
1262
|
this.#replayLivePrefix(agent.session.id);
|
|
1339
1263
|
}
|
|
@@ -1361,7 +1285,7 @@ export class SessionRuntime {
|
|
|
1361
1285
|
async #inspectSubagent(id) {
|
|
1362
1286
|
const request = this.#inspectEpoch + 1;
|
|
1363
1287
|
this.#inspectEpoch = request;
|
|
1364
|
-
if (!this.#
|
|
1288
|
+
if (!this.#tracker.owns(id)) {
|
|
1365
1289
|
this.#tui.notice('That subagent is no longer available.', { level: 'error' });
|
|
1366
1290
|
return;
|
|
1367
1291
|
}
|
|
@@ -1408,7 +1332,7 @@ export class SessionRuntime {
|
|
|
1408
1332
|
return;
|
|
1409
1333
|
}
|
|
1410
1334
|
const live = this.#ctx.get('sessions')?.get(SessionId(childId));
|
|
1411
|
-
const rosterParent = this.#
|
|
1335
|
+
const rosterParent = this.#tracker.snapshot()?.agents.find(agent => agent.id === childId)?.parentId;
|
|
1412
1336
|
const parentId = live?.header.parentSession ?? rosterParent;
|
|
1413
1337
|
const parent = parentId === undefined || parentId === root.id
|
|
1414
1338
|
? root
|