@agi-fans/dsh-tui 0.18.0 → 0.19.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 +31 -0
- package/lib/chrome/box.d.ts +2 -0
- package/lib/chrome/box.js +5 -1
- package/lib/chrome/box.js.map +1 -1
- package/lib/chrome/main-screen-renderer.d.ts +61 -11
- package/lib/chrome/main-screen-renderer.js +1674 -71
- package/lib/chrome/main-screen-renderer.js.map +1 -1
- package/lib/chrome/markdown.js +21 -13
- package/lib/chrome/markdown.js.map +1 -1
- package/lib/chrome/renderer.d.ts +75 -0
- package/lib/chrome/renderer.js.map +1 -1
- package/lib/chrome/theme.d.ts +18 -0
- package/lib/chrome/theme.js +18 -0
- package/lib/chrome/theme.js.map +1 -1
- package/lib/chrome/tool-args.d.ts +24 -1
- package/lib/chrome/tool-args.js +40 -1
- package/lib/chrome/tool-args.js.map +1 -1
- package/lib/chrome/tool-renderers.d.ts +11 -0
- package/lib/chrome/tool-renderers.js +55 -5
- package/lib/chrome/tool-renderers.js.map +1 -1
- package/lib/chrome/welcome-tips.js +1 -1
- package/lib/chrome/welcome-tips.js.map +1 -1
- package/lib/definition.d.ts +59 -7
- package/lib/definition.js.map +1 -1
- package/lib/input/keybindings-config.d.ts +1 -1
- package/lib/input/keybindings-config.js +2 -1
- package/lib/input/keybindings-config.js.map +1 -1
- package/lib/input/keys.d.ts +7 -0
- package/lib/input/keys.js +11 -4
- package/lib/input/keys.js.map +1 -1
- package/lib/runtime/provider-local.d.ts +20 -4
- package/lib/runtime/provider-local.js +435 -63
- package/lib/runtime/provider-local.js.map +1 -1
- package/lib/runtime/tool-presentation.js +43 -30
- package/lib/runtime/tool-presentation.js.map +1 -1
- package/lib/session/feature-toggles.d.ts +100 -0
- package/lib/session/feature-toggles.js +170 -0
- package/lib/session/feature-toggles.js.map +1 -0
- package/lib/session/fold-policy.d.ts +21 -0
- package/lib/session/fold-policy.js +15 -0
- package/lib/session/fold-policy.js.map +1 -0
- package/lib/session/job-notice.d.ts +4 -0
- package/lib/session/job-notice.js +44 -3
- package/lib/session/job-notice.js.map +1 -1
- package/lib/session/session-controller.js +51 -13
- package/lib/session/session-controller.js.map +1 -1
- package/lib/session/tui-settings.d.ts +6 -1
- package/lib/session/tui-settings.js +3 -1
- package/lib/session/tui-settings.js.map +1 -1
- package/lib/views/event-views.d.ts +26 -2
- package/lib/views/event-views.js +160 -43
- package/lib/views/event-views.js.map +1 -1
- package/lib/views/hotkeys.d.ts +2 -0
- package/lib/views/hotkeys.js +7 -3
- package/lib/views/hotkeys.js.map +1 -1
- package/lib/views/settings-list.d.ts +10 -4
- package/lib/views/settings-list.js +41 -18
- package/lib/views/settings-list.js.map +1 -1
- package/lib/views/transcript-render.d.ts +133 -18
- package/lib/views/transcript-render.js +1179 -112
- package/lib/views/transcript-render.js.map +1 -1
- package/lib/views/transcript-types.d.ts +79 -1
- package/lib/views/transcript-types.js +11 -0
- package/lib/views/transcript-types.js.map +1 -1
- package/lib/views/workspace-changes.d.ts +27 -0
- package/lib/views/workspace-changes.js +128 -0
- package/lib/views/workspace-changes.js.map +1 -0
- package/package.json +36 -35
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-presentation.js","sourceRoot":"","sources":["../../src/runtime/tool-presentation.ts"],"names":[],"mappings":"AAAA,6EAA6E;
|
|
1
|
+
{"version":3,"file":"tool-presentation.js","sourceRoot":"","sources":["../../src/runtime/tool-presentation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional product features and the Profile-patch block that turns them off.
|
|
3
|
+
*
|
|
4
|
+
* A feature is a composition row a deployment may not want: it costs context,
|
|
5
|
+
* runtime, or transcript noise. The row's `disabled` field is a Loader option
|
|
6
|
+
* rather than plugin config, so the settings service cannot write it — the
|
|
7
|
+
* Loader does read a Profile patch's `disabled`, and that patch is the
|
|
8
|
+
* documented, user-authored surface for exactly this.
|
|
9
|
+
*
|
|
10
|
+
* The writes therefore maintain one clearly delimited block in the Profile
|
|
11
|
+
* patch and touch nothing else in the file, so hand-written rows, `!!js`
|
|
12
|
+
* expressions, and comments all survive a toggle. Toggling takes effect on the
|
|
13
|
+
* next launch: the Harness reads the patch once while composing the tree.
|
|
14
|
+
* @module @agi-fans/dsh-tui
|
|
15
|
+
*/
|
|
16
|
+
/** One optional product feature, addressed by the row id it disables. */
|
|
17
|
+
export interface FeatureToggle {
|
|
18
|
+
/** Composition row id; the key a Profile patch keys its override by. */
|
|
19
|
+
id: string;
|
|
20
|
+
/** Short row label for the settings overlay. */
|
|
21
|
+
label: string;
|
|
22
|
+
/** What the feature does, and what turning it off costs. */
|
|
23
|
+
description: string;
|
|
24
|
+
/** Whether the shipped composition mounts it. */
|
|
25
|
+
enabledByDefault: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Features this build can turn off.
|
|
29
|
+
*
|
|
30
|
+
* Rows that make the agent non-functional (`tool-fs`, `tool-bash`, `todo`), rows
|
|
31
|
+
* that back a command (`session-query` backs `/sessions`, `workspace` backs
|
|
32
|
+
* `@` mentions), and rows that are already conditional at no cost
|
|
33
|
+
* (`mcp-resources` appears only with a connected MCP server) are deliberately
|
|
34
|
+
* absent. `tool-web` is absent for a different reason: `web_search` and
|
|
35
|
+
* `web_fetch` share one row, so no row-level toggle can express "search off,
|
|
36
|
+
* fetch on".
|
|
37
|
+
*/
|
|
38
|
+
export declare const FEATURE_TOGGLES: readonly FeatureToggle[];
|
|
39
|
+
/** Opening delimiter of the block this module owns. */
|
|
40
|
+
export declare const FEATURE_BLOCK_BEGIN = "# >>> omdsh feature toggles >>>";
|
|
41
|
+
/** Closing delimiter of the block this module owns. */
|
|
42
|
+
export declare const FEATURE_BLOCK_END = "# <<< omdsh feature toggles <<<";
|
|
43
|
+
/** Current on/off state of every feature, keyed by row id. */
|
|
44
|
+
export type FeatureStates = Readonly<Record<string, boolean>>;
|
|
45
|
+
/** The shipped composition's state, before any Profile patch override. */
|
|
46
|
+
export declare function defaultFeatureStates(features?: readonly FeatureToggle[]): Record<string, boolean>;
|
|
47
|
+
/**
|
|
48
|
+
* Apply the `disabled` rows a Profile patch declares on top of the defaults.
|
|
49
|
+
*
|
|
50
|
+
* Only rows this build knows a feature for are read: a patch may disable any
|
|
51
|
+
* row for its own reasons, and an unknown id is not a feature toggle.
|
|
52
|
+
*
|
|
53
|
+
* @param states - the shipped defaults.
|
|
54
|
+
* @param disabled - row ids the patch marks `disabled: true`.
|
|
55
|
+
* @returns a new state map with those features off.
|
|
56
|
+
*/
|
|
57
|
+
export declare function applyDisabledRows(states: Record<string, boolean>, disabled: readonly string[]): Record<string, boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* Row ids that must be disabled to make `states` true, ignoring rows already
|
|
60
|
+
* off in the shipped composition.
|
|
61
|
+
*
|
|
62
|
+
* @param states - desired feature state.
|
|
63
|
+
* @returns the row ids a patch has to mark `disabled: true`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function rowsToDisable(states: FeatureStates): string[];
|
|
66
|
+
/**
|
|
67
|
+
* Render the managed block for the features that are off.
|
|
68
|
+
*
|
|
69
|
+
* The block is written unconditionally so it always states the full set the
|
|
70
|
+
* build manages; re-enabling a feature is removing its row from here.
|
|
71
|
+
*
|
|
72
|
+
* @param states - desired feature state.
|
|
73
|
+
* @returns the block text, including a trailing newline.
|
|
74
|
+
*/
|
|
75
|
+
export declare function renderFeatureBlock(states: FeatureStates): string;
|
|
76
|
+
/**
|
|
77
|
+
* Replace the managed block, leaving every other byte of the patch untouched.
|
|
78
|
+
*
|
|
79
|
+
* A patch that carries no block is simply appended to, so a file the user has
|
|
80
|
+
* been editing by hand keeps its formatting, comments, and `!!js` expressions.
|
|
81
|
+
*
|
|
82
|
+
* @param text - current patch file contents.
|
|
83
|
+
* @param block - the block to install.
|
|
84
|
+
* @returns the new patch file contents.
|
|
85
|
+
*/
|
|
86
|
+
export declare function replaceFeatureBlock(text: string, block: string): string;
|
|
87
|
+
/**
|
|
88
|
+
* Read the feature state a patch file currently declares.
|
|
89
|
+
*
|
|
90
|
+
* Only the managed block is parsed, by row id, so a hand-written
|
|
91
|
+
* `disabled: true` elsewhere in the file is left for the composition to honour
|
|
92
|
+
* and is not double-counted as a feature toggle.
|
|
93
|
+
*
|
|
94
|
+
* @param text - patch file contents.
|
|
95
|
+
* @param features - known features; defaults to the shipped registry.
|
|
96
|
+
* @returns the state the block declares over the shipped defaults.
|
|
97
|
+
*/
|
|
98
|
+
export declare function featureStatesFromPatch(text: string, features?: readonly FeatureToggle[]): Record<string, boolean>;
|
|
99
|
+
/** Absolute path of the Profile patch this build edits. */
|
|
100
|
+
export declare function featurePatchPath(dshHome: string): string;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional product features and the Profile-patch block that turns them off.
|
|
3
|
+
*
|
|
4
|
+
* A feature is a composition row a deployment may not want: it costs context,
|
|
5
|
+
* runtime, or transcript noise. The row's `disabled` field is a Loader option
|
|
6
|
+
* rather than plugin config, so the settings service cannot write it — the
|
|
7
|
+
* Loader does read a Profile patch's `disabled`, and that patch is the
|
|
8
|
+
* documented, user-authored surface for exactly this.
|
|
9
|
+
*
|
|
10
|
+
* The writes therefore maintain one clearly delimited block in the Profile
|
|
11
|
+
* patch and touch nothing else in the file, so hand-written rows, `!!js`
|
|
12
|
+
* expressions, and comments all survive a toggle. Toggling takes effect on the
|
|
13
|
+
* next launch: the Harness reads the patch once while composing the tree.
|
|
14
|
+
* @module @agi-fans/dsh-tui
|
|
15
|
+
*/
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
/**
|
|
18
|
+
* Features this build can turn off.
|
|
19
|
+
*
|
|
20
|
+
* Rows that make the agent non-functional (`tool-fs`, `tool-bash`, `todo`), rows
|
|
21
|
+
* that back a command (`session-query` backs `/sessions`, `workspace` backs
|
|
22
|
+
* `@` mentions), and rows that are already conditional at no cost
|
|
23
|
+
* (`mcp-resources` appears only with a connected MCP server) are deliberately
|
|
24
|
+
* absent. `tool-web` is absent for a different reason: `web_search` and
|
|
25
|
+
* `web_fetch` share one row, so no row-level toggle can express "search off,
|
|
26
|
+
* fetch on".
|
|
27
|
+
*/
|
|
28
|
+
export const FEATURE_TOGGLES = [
|
|
29
|
+
{
|
|
30
|
+
id: 'workspace-changes',
|
|
31
|
+
label: 'Changed-file summary',
|
|
32
|
+
description: 'End every turn with the files it changed and their line counts. Off skips two Git snapshots per turn and the transcript row.',
|
|
33
|
+
enabledByDefault: true,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'tool-session-query',
|
|
37
|
+
label: 'Session history tools',
|
|
38
|
+
description: 'Five tools that let the model search, trace and read its own earlier sessions. Off removes five tool schemas from every request.',
|
|
39
|
+
enabledByDefault: true,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 'tool-ralph',
|
|
43
|
+
label: 'Ralph loop',
|
|
44
|
+
description: 'Let the model re-run a task until it reports completion. Off by default because the tool is a self-report, not an evaluation.',
|
|
45
|
+
enabledByDefault: false,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'repeat-tool-reminder',
|
|
49
|
+
label: 'Repeat-tool reminder',
|
|
50
|
+
description: 'Nudge the model out of identical tool-call loops. Off removes the advisory text those nudges add to the context.',
|
|
51
|
+
enabledByDefault: true,
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
/** Opening delimiter of the block this module owns. */
|
|
55
|
+
export const FEATURE_BLOCK_BEGIN = '# >>> omdsh feature toggles >>>';
|
|
56
|
+
/** Closing delimiter of the block this module owns. */
|
|
57
|
+
export const FEATURE_BLOCK_END = '# <<< omdsh feature toggles <<<';
|
|
58
|
+
/** The shipped composition's state, before any Profile patch override. */
|
|
59
|
+
export function defaultFeatureStates(features = FEATURE_TOGGLES) {
|
|
60
|
+
return Object.fromEntries(features.map(feature => [feature.id, feature.enabledByDefault]));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Apply the `disabled` rows a Profile patch declares on top of the defaults.
|
|
64
|
+
*
|
|
65
|
+
* Only rows this build knows a feature for are read: a patch may disable any
|
|
66
|
+
* row for its own reasons, and an unknown id is not a feature toggle.
|
|
67
|
+
*
|
|
68
|
+
* @param states - the shipped defaults.
|
|
69
|
+
* @param disabled - row ids the patch marks `disabled: true`.
|
|
70
|
+
* @returns a new state map with those features off.
|
|
71
|
+
*/
|
|
72
|
+
export function applyDisabledRows(states, disabled) {
|
|
73
|
+
const known = new Set(FEATURE_TOGGLES.map(feature => feature.id));
|
|
74
|
+
const next = { ...states };
|
|
75
|
+
for (const id of disabled)
|
|
76
|
+
if (known.has(id))
|
|
77
|
+
next[id] = false;
|
|
78
|
+
return next;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Row ids that must be disabled to make `states` true, ignoring rows already
|
|
82
|
+
* off in the shipped composition.
|
|
83
|
+
*
|
|
84
|
+
* @param states - desired feature state.
|
|
85
|
+
* @returns the row ids a patch has to mark `disabled: true`.
|
|
86
|
+
*/
|
|
87
|
+
export function rowsToDisable(states) {
|
|
88
|
+
return FEATURE_TOGGLES
|
|
89
|
+
.filter(feature => feature.enabledByDefault && states[feature.id] === false)
|
|
90
|
+
.map(feature => feature.id);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Render the managed block for the features that are off.
|
|
94
|
+
*
|
|
95
|
+
* The block is written unconditionally so it always states the full set the
|
|
96
|
+
* build manages; re-enabling a feature is removing its row from here.
|
|
97
|
+
*
|
|
98
|
+
* @param states - desired feature state.
|
|
99
|
+
* @returns the block text, including a trailing newline.
|
|
100
|
+
*/
|
|
101
|
+
export function renderFeatureBlock(states) {
|
|
102
|
+
const off = FEATURE_TOGGLES
|
|
103
|
+
.filter(feature => feature.enabledByDefault && states[feature.id] === false)
|
|
104
|
+
.map(feature => feature.id);
|
|
105
|
+
const lines = [FEATURE_BLOCK_BEGIN];
|
|
106
|
+
for (const id of off)
|
|
107
|
+
lines.push(`- id: ${id}`, ' disabled: true');
|
|
108
|
+
lines.push(FEATURE_BLOCK_END, '');
|
|
109
|
+
return lines.join('\n');
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Replace the managed block, leaving every other byte of the patch untouched.
|
|
113
|
+
*
|
|
114
|
+
* A patch that carries no block is simply appended to, so a file the user has
|
|
115
|
+
* been editing by hand keeps its formatting, comments, and `!!js` expressions.
|
|
116
|
+
*
|
|
117
|
+
* @param text - current patch file contents.
|
|
118
|
+
* @param block - the block to install.
|
|
119
|
+
* @returns the new patch file contents.
|
|
120
|
+
*/
|
|
121
|
+
export function replaceFeatureBlock(text, block) {
|
|
122
|
+
const begin = text.indexOf(FEATURE_BLOCK_BEGIN);
|
|
123
|
+
const end = text.indexOf(FEATURE_BLOCK_END);
|
|
124
|
+
if (begin < 0 || end < 0 || end < begin) {
|
|
125
|
+
const head = text.trimEnd();
|
|
126
|
+
return head === '' ? block : `${head}\n\n${block}`;
|
|
127
|
+
}
|
|
128
|
+
const before = text.slice(0, begin).trimEnd();
|
|
129
|
+
const after = text.slice(end + FEATURE_BLOCK_END.length).replace(/^\n+/, '');
|
|
130
|
+
const head = before === '' ? '' : `${before}\n\n`;
|
|
131
|
+
const tail = after.trim() === '' ? '' : `\n${after}`;
|
|
132
|
+
return `${head}${block.trimEnd()}${tail}\n`;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Read the feature state a patch file currently declares.
|
|
136
|
+
*
|
|
137
|
+
* Only the managed block is parsed, by row id, so a hand-written
|
|
138
|
+
* `disabled: true` elsewhere in the file is left for the composition to honour
|
|
139
|
+
* and is not double-counted as a feature toggle.
|
|
140
|
+
*
|
|
141
|
+
* @param text - patch file contents.
|
|
142
|
+
* @param features - known features; defaults to the shipped registry.
|
|
143
|
+
* @returns the state the block declares over the shipped defaults.
|
|
144
|
+
*/
|
|
145
|
+
export function featureStatesFromPatch(text, features = FEATURE_TOGGLES) {
|
|
146
|
+
const begin = text.indexOf(FEATURE_BLOCK_BEGIN);
|
|
147
|
+
const end = text.indexOf(FEATURE_BLOCK_END);
|
|
148
|
+
const states = Object.fromEntries(features.map(f => [f.id, f.enabledByDefault]));
|
|
149
|
+
if (begin < 0 || end < 0 || end < begin)
|
|
150
|
+
return states;
|
|
151
|
+
let current;
|
|
152
|
+
for (const raw of text.slice(begin, end).split('\n')) {
|
|
153
|
+
const id = raw.match(/^\s*-\s*id:\s*(\S+)\s*$/u);
|
|
154
|
+
if (id !== null) {
|
|
155
|
+
current = id[1];
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (/^\s*disabled:\s*true\s*$/u.test(raw) && current !== undefined) {
|
|
159
|
+
if (Object.hasOwn(states, current))
|
|
160
|
+
states[current] = false;
|
|
161
|
+
current = undefined;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return states;
|
|
165
|
+
}
|
|
166
|
+
/** Absolute path of the Profile patch this build edits. */
|
|
167
|
+
export function featurePatchPath(dshHome) {
|
|
168
|
+
return join(dshHome, 'profiles', 'omdsh', 'cordis.patch.yml');
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=feature-toggles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-toggles.js","sourceRoot":"","sources":["../../src/session/feature-toggles.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Compatibility for stored transcript preferences from earlier versions. */
|
|
2
|
+
export declare const FOLD_DENSITIES: readonly ["compact", "standard", "detailed", "verbose"];
|
|
3
|
+
export type FoldDensity = typeof FOLD_DENSITIES[number];
|
|
4
|
+
/** @deprecated Turns now use one presentation policy. */
|
|
5
|
+
export interface FoldPolicy {
|
|
6
|
+
groups: boolean;
|
|
7
|
+
tools: boolean;
|
|
8
|
+
reasoning: boolean;
|
|
9
|
+
detail: boolean;
|
|
10
|
+
subject: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const DEFAULT_FOLD_DENSITY: FoldDensity;
|
|
13
|
+
/** All legacy values resolve to the current turn presentation. */
|
|
14
|
+
export declare function foldPolicy(_density: FoldDensity): FoldPolicy;
|
|
15
|
+
export declare function isFoldDensity(value: string): value is FoldDensity;
|
|
16
|
+
/** Old preferences remain readable but no longer select a different layout. */
|
|
17
|
+
export declare function resolveFoldDensity(_prefs: {
|
|
18
|
+
foldDensity?: FoldDensity;
|
|
19
|
+
expandTools?: boolean;
|
|
20
|
+
}): FoldDensity;
|
|
21
|
+
export declare function foldPolicyKey(_policy: FoldPolicy): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Compatibility for stored transcript preferences from earlier versions. */
|
|
2
|
+
export const FOLD_DENSITIES = ['compact', 'standard', 'detailed', 'verbose'];
|
|
3
|
+
export const DEFAULT_FOLD_DENSITY = 'standard';
|
|
4
|
+
const TURN_POLICY = { groups: true, tools: true, reasoning: false, detail: false, subject: true };
|
|
5
|
+
/** All legacy values resolve to the current turn presentation. */
|
|
6
|
+
export function foldPolicy(_density) { return TURN_POLICY; }
|
|
7
|
+
export function isFoldDensity(value) {
|
|
8
|
+
return FOLD_DENSITIES.includes(value);
|
|
9
|
+
}
|
|
10
|
+
/** Old preferences remain readable but no longer select a different layout. */
|
|
11
|
+
export function resolveFoldDensity(_prefs) {
|
|
12
|
+
return DEFAULT_FOLD_DENSITY;
|
|
13
|
+
}
|
|
14
|
+
export function foldPolicyKey(_policy) { return 'turn'; }
|
|
15
|
+
//# sourceMappingURL=fold-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fold-policy.js","sourceRoot":"","sources":["../../src/session/fold-policy.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,CAAU,CAAA;AAYrF,MAAM,CAAC,MAAM,oBAAoB,GAAgB,UAAU,CAAA;AAC3D,MAAM,WAAW,GAAe,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAE7G,kEAAkE;AAClE,MAAM,UAAU,UAAU,CAAC,QAAqB,IAAgB,OAAO,WAAW,CAAA,CAAC,CAAC;AAEpF,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAQ,cAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AAC9D,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,kBAAkB,CAAC,MAA4D;IAC7F,OAAO,oBAAoB,CAAA;AAC7B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAmB,IAAY,OAAO,MAAM,CAAA,CAAC,CAAC"}
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
7
7
|
import type { JobStatus, JobView } from '@deepseek-ai/dsh-jobs';
|
|
8
|
+
import type { TuiNoticeOptions } from '../definition.ts';
|
|
9
|
+
import type { TranscriptState } from '../views/transcript-types.ts';
|
|
10
|
+
/** Merge only an identified job or an unambiguous command still awaiting its result. */
|
|
11
|
+
export declare function mergeJobSettlement(state: TranscriptState, job: NonNullable<TuiNoticeOptions['job']>): TranscriptState | undefined;
|
|
8
12
|
/** Past- or present-tense word for one lifecycle status. */
|
|
9
13
|
export declare const JOB_STATUS_WORD: Record<JobStatus, string>;
|
|
10
14
|
/** One human-facing completion line for a background job. */
|
|
@@ -3,6 +3,45 @@
|
|
|
3
3
|
* notice, so one job reads the same in both surfaces.
|
|
4
4
|
* @module @agi-fans/dsh-tui/job-notice
|
|
5
5
|
*/
|
|
6
|
+
import { toolArgsObject } from "../chrome/tool-args.js";
|
|
7
|
+
import { truncateToWidth, visibleWidth } from "../chrome/width.js";
|
|
8
|
+
/** Merge only an identified job or an unambiguous command still awaiting its result. */
|
|
9
|
+
export function mergeJobSettlement(state, job) {
|
|
10
|
+
const identified = [];
|
|
11
|
+
const pending = [];
|
|
12
|
+
state.blocks.forEach((block, index) => {
|
|
13
|
+
if (block.kind !== 'tool')
|
|
14
|
+
return;
|
|
15
|
+
if (!/^(bash|shell|pwsh|exec)$/u.test(block.name) && block.presentation?.call?.card !== 'terminal')
|
|
16
|
+
return;
|
|
17
|
+
const explicitId = /^started background job (\S+)\s*$/u.exec(block.output)?.[1]
|
|
18
|
+
?? /\[still running after \d+ms; moved to background job ([^\s\]]+)\]/u.exec(block.output)?.[1];
|
|
19
|
+
const id = block.job?.id ?? explicitId;
|
|
20
|
+
if (id !== undefined) {
|
|
21
|
+
if (id === job.id)
|
|
22
|
+
identified.push(index);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const args = toolArgsObject(block.args);
|
|
26
|
+
if (block.status === 'running' && block.startedAt !== undefined && block.startedAt <= job.startedAt
|
|
27
|
+
&& typeof args?.['command'] === 'string' && args['command'] === job.label)
|
|
28
|
+
pending.push(index);
|
|
29
|
+
});
|
|
30
|
+
const matches = identified.length > 0 ? identified : pending;
|
|
31
|
+
if (matches.length !== 1)
|
|
32
|
+
return undefined;
|
|
33
|
+
const index = matches[0];
|
|
34
|
+
const block = state.blocks[index];
|
|
35
|
+
if (block.kind !== 'tool')
|
|
36
|
+
return undefined;
|
|
37
|
+
const blocks = [...state.blocks];
|
|
38
|
+
blocks[index] = {
|
|
39
|
+
...block,
|
|
40
|
+
status: job.status === 'completed' && block.status !== 'error' ? 'ok' : 'error',
|
|
41
|
+
job: { id: job.id, status: job.status, detail: job.detail?.trim() || JOB_STATUS_WORD[job.status] },
|
|
42
|
+
};
|
|
43
|
+
return { ...state, blocks };
|
|
44
|
+
}
|
|
6
45
|
/** Past- or present-tense word for one lifecycle status. */
|
|
7
46
|
export const JOB_STATUS_WORD = {
|
|
8
47
|
running: 'running',
|
|
@@ -13,9 +52,11 @@ export const JOB_STATUS_WORD = {
|
|
|
13
52
|
};
|
|
14
53
|
/** One human-facing completion line for a background job. */
|
|
15
54
|
export function formatJobNotice(snapshot) {
|
|
16
|
-
const
|
|
17
|
-
const detail = snapshot.detail
|
|
18
|
-
|
|
55
|
+
const head = `Background job ${snapshot.id} ${JOB_STATUS_WORD[snapshot.status]}`;
|
|
56
|
+
const detail = truncateToWidth(snapshot.detail?.trim().split('\n')[0] ?? '', 28);
|
|
57
|
+
const room = Math.max(0, 76 - visibleWidth(head) - (detail === '' ? 0 : visibleWidth(detail) + 3) - 3);
|
|
58
|
+
const label = room < 8 ? '' : truncateToWidth(snapshot.label.trim().split('\n')[0] ?? '', room);
|
|
59
|
+
return head
|
|
19
60
|
+ (label === '' ? '' : ` · ${label}`)
|
|
20
61
|
+ (detail === '' ? '' : ` · ${detail}`);
|
|
21
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"job-notice.js","sourceRoot":"","sources":["../../src/session/job-notice.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"job-notice.js","sourceRoot":"","sources":["../../src/session/job-notice.ts"],"names":[],"mappings":"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"}
|
|
@@ -460,8 +460,16 @@ export class SessionRuntime {
|
|
|
460
460
|
return;
|
|
461
461
|
const owner = event.job.owner === undefined ? undefined : this.#ctx.get('agents')?.get(event.job.owner);
|
|
462
462
|
const notice = jobNoticeFor(event.job, owner, this.#active?.handle.agent);
|
|
463
|
-
if (notice !== undefined)
|
|
464
|
-
|
|
463
|
+
if (notice !== undefined) {
|
|
464
|
+
const job = event.job;
|
|
465
|
+
tui.notice(notice, {
|
|
466
|
+
process: true, processSource: `job:${job.id}`,
|
|
467
|
+
...(/^(bash|pwsh)$/u.test(job.kind) && (job.status === 'completed' || job.status === 'failed' || job.status === 'killed')
|
|
468
|
+
? { job: { id: job.id, label: job.label, status: job.status, startedAt: job.startedAt, ...(job.detail === undefined ? {} : { detail: job.detail }) } }
|
|
469
|
+
: {}),
|
|
470
|
+
...(job.status === 'failed' || job.status === 'killed' ? { level: 'error' } : {}),
|
|
471
|
+
});
|
|
472
|
+
}
|
|
465
473
|
}));
|
|
466
474
|
}
|
|
467
475
|
this.#off.push(ctx.on('agent/status', (payload) => {
|
|
@@ -494,6 +502,8 @@ export class SessionRuntime {
|
|
|
494
502
|
if (this.#inspectedId === undefined) {
|
|
495
503
|
tui.event(event, ctx.get('tuiToolPresentation')?.event(active.handle.agent, event));
|
|
496
504
|
}
|
|
505
|
+
if (event.type === 'workspace/changes')
|
|
506
|
+
this.#serveWorkspaceSummary(ctx, tui, session, event);
|
|
497
507
|
if (event.type === 'subagent/catalog')
|
|
498
508
|
this.#tracker.observeCatalog(session, [event]);
|
|
499
509
|
if (shouldRefreshSessionInfoAfter(event))
|
|
@@ -579,7 +589,7 @@ export class SessionRuntime {
|
|
|
579
589
|
if (defaults === undefined)
|
|
580
590
|
throw new Error('agent default model is unavailable');
|
|
581
591
|
await this.refreshRecent();
|
|
582
|
-
await this.#activate(await this.#create(defaults));
|
|
592
|
+
await this.#activate(await this.#create(defaults), 'initial');
|
|
583
593
|
}
|
|
584
594
|
/** Submit one human composer value; active turns retain it as a later follow-up. */
|
|
585
595
|
async send(input, agent = this.#requiredAgent()) {
|
|
@@ -640,9 +650,9 @@ export class SessionRuntime {
|
|
|
640
650
|
this.#tui.restoreInput({ text: line, images });
|
|
641
651
|
if (result.text !== undefined) {
|
|
642
652
|
if (result.kind === 'error')
|
|
643
|
-
this.#tui.notice(result.text, { level: 'error' });
|
|
653
|
+
this.#tui.notice(result.text, { level: 'error', focus: true });
|
|
644
654
|
else
|
|
645
|
-
this.#tui.commandOutput(parsed.name, result.text);
|
|
655
|
+
this.#tui.commandOutput(parsed.name, result.text, { focus: true });
|
|
646
656
|
}
|
|
647
657
|
return true;
|
|
648
658
|
}
|
|
@@ -681,7 +691,7 @@ export class SessionRuntime {
|
|
|
681
691
|
/** Start a new top-level session with the current model selection. */
|
|
682
692
|
async newSession(agent) {
|
|
683
693
|
this.assertActive(agent);
|
|
684
|
-
await this.#activate(await this.#create(this.selection(agent)));
|
|
694
|
+
await this.#activate(await this.#create(this.selection(agent)), 'new');
|
|
685
695
|
await this.refreshRecent();
|
|
686
696
|
}
|
|
687
697
|
/** Replace the active top-level session with one durable session. */
|
|
@@ -901,6 +911,34 @@ export class SessionRuntime {
|
|
|
901
911
|
this.#pushSessionInfo();
|
|
902
912
|
return outcome;
|
|
903
913
|
}
|
|
914
|
+
/**
|
|
915
|
+
* Resolve and attach the changed-file summary a `workspace/changes` event
|
|
916
|
+
* announces.
|
|
917
|
+
*
|
|
918
|
+
* The Harness appends the event and only then files the summary under its
|
|
919
|
+
* sequence, so a listener running inside that append always reads
|
|
920
|
+
* `undefined`. The lookup is therefore deferred by one microtask, which runs
|
|
921
|
+
* after the recorder's own synchronous store, and enriches the turn-only
|
|
922
|
+
* block the transcript already rendered. A session without the plugin, or a
|
|
923
|
+
* recorder that has already been disposed, simply keeps the fallback.
|
|
924
|
+
*
|
|
925
|
+
* @param ctx - host context carrying the optional service.
|
|
926
|
+
* @param tui - the mounted presentation service.
|
|
927
|
+
* @param session - the Session that appended the event.
|
|
928
|
+
* @param event - the `workspace/changes` event.
|
|
929
|
+
*/
|
|
930
|
+
#serveWorkspaceSummary(ctx, tui, session, event) {
|
|
931
|
+
const service = ctx.get('workspaceChanges');
|
|
932
|
+
if (service === undefined)
|
|
933
|
+
return;
|
|
934
|
+
const { id } = session;
|
|
935
|
+
const { seq, data } = event;
|
|
936
|
+
queueMicrotask(() => {
|
|
937
|
+
const summary = service.summary(id, seq);
|
|
938
|
+
if (summary !== undefined)
|
|
939
|
+
tui.setWorkspaceSummary(data.turn, summary);
|
|
940
|
+
});
|
|
941
|
+
}
|
|
904
942
|
/**
|
|
905
943
|
* Publish a current-format generation for every stored session an earlier
|
|
906
944
|
* release wrote. A read open never upgrades a log, so without this pass
|
|
@@ -1106,7 +1144,7 @@ export class SessionRuntime {
|
|
|
1106
1144
|
return undefined;
|
|
1107
1145
|
}
|
|
1108
1146
|
}
|
|
1109
|
-
async #activate(next) {
|
|
1147
|
+
async #activate(next, reason = 'open') {
|
|
1110
1148
|
// Reject a late create before it publishes UI on a disposed tree.
|
|
1111
1149
|
if (this.#disposed) {
|
|
1112
1150
|
this.#releaseHandle(next.handle);
|
|
@@ -1117,7 +1155,7 @@ export class SessionRuntime {
|
|
|
1117
1155
|
this.#active = next;
|
|
1118
1156
|
void this.#claimWorkspace(next);
|
|
1119
1157
|
try {
|
|
1120
|
-
this.#presentAgent(next);
|
|
1158
|
+
this.#presentAgent(next, reason);
|
|
1121
1159
|
const selected = this.selection(next.handle.agent);
|
|
1122
1160
|
const info = await this.#resolveModelInfo(selected);
|
|
1123
1161
|
if (this.#disposed || this.#activationEpoch !== epoch) {
|
|
@@ -1178,7 +1216,7 @@ export class SessionRuntime {
|
|
|
1178
1216
|
this.#releaseHandle(previous.handle);
|
|
1179
1217
|
}
|
|
1180
1218
|
/** Show one active session on the terminal: transcript, tools, controls, model. */
|
|
1181
|
-
#presentAgent(active) {
|
|
1219
|
+
#presentAgent(active, reason = 'open') {
|
|
1182
1220
|
const agent = active.handle.agent;
|
|
1183
1221
|
this.#inspectedId = undefined;
|
|
1184
1222
|
this.#tui.setInspectedSubagent(undefined);
|
|
@@ -1187,7 +1225,7 @@ export class SessionRuntime {
|
|
|
1187
1225
|
// Seed welcome metadata before replaceSession commits the startup header to
|
|
1188
1226
|
// native scrollback; later updates cannot rewrite that frozen first frame.
|
|
1189
1227
|
this.#pushSessionInfo();
|
|
1190
|
-
this.#replaceTranscript(agent);
|
|
1228
|
+
this.#replaceTranscript(agent, reason);
|
|
1191
1229
|
this.#pushTools();
|
|
1192
1230
|
this.#pushCommands();
|
|
1193
1231
|
const selected = this.selection(agent);
|
|
@@ -1309,10 +1347,10 @@ export class SessionRuntime {
|
|
|
1309
1347
|
controls: this.#sessionControls(active, projection),
|
|
1310
1348
|
});
|
|
1311
1349
|
}
|
|
1312
|
-
#replaceTranscript(agent) {
|
|
1350
|
+
#replaceTranscript(agent, reason = 'refresh') {
|
|
1313
1351
|
const events = agent.session.snapshotEvents();
|
|
1314
1352
|
this.#tracker.observeCatalog(agent.session, events);
|
|
1315
|
-
this.#tui.replaceSession(events, this.#ctx.get('tuiToolPresentation')?.session(agent, events), agent.status);
|
|
1353
|
+
this.#tui.replaceSession(events, this.#ctx.get('tuiToolPresentation')?.session(agent, events), agent.status, reason);
|
|
1316
1354
|
this.#replayLivePrefix(agent.session.id);
|
|
1317
1355
|
}
|
|
1318
1356
|
#replaceVisibleTranscript() {
|
|
@@ -1367,7 +1405,7 @@ export class SessionRuntime {
|
|
|
1367
1405
|
return;
|
|
1368
1406
|
this.#inspectedId = id;
|
|
1369
1407
|
const child = this.#ctx.get('agents')?.get(SessionId(id));
|
|
1370
|
-
this.#tui.replaceSession(events, child === undefined ? undefined : this.#ctx.get('tuiToolPresentation')?.session(child, events), child?.status ?? 'idle');
|
|
1408
|
+
this.#tui.replaceSession(events, child === undefined ? undefined : this.#ctx.get('tuiToolPresentation')?.session(child, events), child?.status ?? 'idle', 'refresh');
|
|
1371
1409
|
this.#replayLivePrefix(id);
|
|
1372
1410
|
this.#tui.setInspectedSubagent(this.#inspectView(id, child?.status === 'running' ? 'running' : 'waiting'));
|
|
1373
1411
|
this.#tui.setStatus(child?.status ?? 'idle');
|