@astralyn/pi 0.84.6 → 0.84.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/dist/core/compaction/compaction.d.ts +2 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +7 -7
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/extensions/background/index.d.ts.map +1 -1
- package/dist/extensions/background/index.js +48 -72
- package/dist/extensions/background/index.js.map +1 -1
- package/dist/extensions/background/manager.d.ts.map +1 -1
- package/dist/extensions/background/manager.js +5 -3
- package/dist/extensions/background/manager.js.map +1 -1
- package/dist/extensions/background/registry.d.ts +11 -13
- package/dist/extensions/background/registry.d.ts.map +1 -1
- package/dist/extensions/background/registry.js +71 -80
- package/dist/extensions/background/registry.js.map +1 -1
- package/dist/extensions/background/render.d.ts.map +1 -1
- package/dist/extensions/background/render.js +17 -4
- package/dist/extensions/background/render.js.map +1 -1
- package/dist/extensions/deepwiki/constants.d.ts +2 -2
- package/dist/extensions/deepwiki/constants.d.ts.map +1 -1
- package/dist/extensions/deepwiki/constants.js +5 -5
- package/dist/extensions/deepwiki/constants.js.map +1 -1
- package/dist/extensions/deepwiki/schema.js +1 -1
- package/dist/extensions/deepwiki/schema.js.map +1 -1
- package/dist/extensions/question/constants.d.ts +2 -2
- package/dist/extensions/question/constants.d.ts.map +1 -1
- package/dist/extensions/question/constants.js +5 -2
- package/dist/extensions/question/constants.js.map +1 -1
- package/dist/extensions/router/dialog-host.d.ts +60 -0
- package/dist/extensions/router/dialog-host.d.ts.map +1 -0
- package/dist/extensions/router/dialog-host.js +196 -0
- package/dist/extensions/router/dialog-host.js.map +1 -0
- package/dist/extensions/router/probe.d.ts.map +1 -1
- package/dist/extensions/router/probe.js +2 -0
- package/dist/extensions/router/probe.js.map +1 -1
- package/dist/extensions/router/ui.d.ts.map +1 -1
- package/dist/extensions/router/ui.js +117 -67
- package/dist/extensions/router/ui.js.map +1 -1
- package/dist/extensions/subagent/activity.d.ts +9 -0
- package/dist/extensions/subagent/activity.d.ts.map +1 -1
- package/dist/extensions/subagent/activity.js +21 -0
- package/dist/extensions/subagent/activity.js.map +1 -1
- package/dist/extensions/subagent/agents-command.d.ts.map +1 -1
- package/dist/extensions/subagent/agents-command.js +355 -71
- package/dist/extensions/subagent/agents-command.js.map +1 -1
- package/dist/extensions/subagent/agents.d.ts.map +1 -1
- package/dist/extensions/subagent/agents.js +7 -3
- package/dist/extensions/subagent/agents.js.map +1 -1
- package/dist/extensions/subagent/constants.d.ts +1 -0
- package/dist/extensions/subagent/constants.d.ts.map +1 -1
- package/dist/extensions/subagent/constants.js +4 -0
- package/dist/extensions/subagent/constants.js.map +1 -1
- package/dist/extensions/subagent/index.js +2 -2
- package/dist/extensions/subagent/index.js.map +1 -1
- package/dist/extensions/subagent/render.d.ts.map +1 -1
- package/dist/extensions/subagent/render.js +1 -7
- package/dist/extensions/subagent/render.js.map +1 -1
- package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
- package/dist/extensions/subagent/sdk-runner.js +19 -0
- package/dist/extensions/subagent/sdk-runner.js.map +1 -1
- package/dist/extensions/subagent/settings.d.ts.map +1 -1
- package/dist/extensions/subagent/settings.js +11 -4
- package/dist/extensions/subagent/settings.js.map +1 -1
- package/dist/extensions/subagent/state.d.ts +9 -0
- package/dist/extensions/subagent/state.d.ts.map +1 -1
- package/dist/extensions/subagent/state.js +33 -2
- package/dist/extensions/subagent/state.js.map +1 -1
- package/dist/extensions/subagent/ui/model-list.d.ts +1 -0
- package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -1
- package/dist/extensions/subagent/ui/model-list.js +5 -0
- package/dist/extensions/subagent/ui/model-list.js.map +1 -1
- package/dist/extensions/todo/constants.d.ts +1 -1
- package/dist/extensions/todo/constants.d.ts.map +1 -1
- package/dist/extensions/todo/constants.js +10 -27
- package/dist/extensions/todo/constants.js.map +1 -1
- package/dist/extensions/todo/state.d.ts.map +1 -1
- package/dist/extensions/todo/state.js +27 -16
- package/dist/extensions/todo/state.js.map +1 -1
- package/dist/extensions/todo/view.d.ts.map +1 -1
- package/dist/extensions/todo/view.js +16 -5
- package/dist/extensions/todo/view.js.map +1 -1
- package/docs/bundled/extensions/background.md +3 -3
- package/docs/bundled/extensions/todo.md +2 -2
- package/docs/compaction.md +2 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Container, Spacer, Text, TruncatedText, } from "@earendil-works/pi-tui";
|
|
1
|
+
import { Container, isFocusable, Spacer, Text, TruncatedText, } from "@earendil-works/pi-tui";
|
|
2
2
|
import { getAgentDir } from "../../config.js";
|
|
3
3
|
import { DynamicBorder } from "../../modes/interactive/components/dynamic-border.js";
|
|
4
4
|
import { keyLabel } from "../../modes/interactive/components/keybinding-hints.js";
|
|
@@ -27,6 +27,85 @@ function navigationHint(theme, keybindings) {
|
|
|
27
27
|
.join("/");
|
|
28
28
|
return keys ? `${theme.fg("dim", keys)}${theme.fg("muted", " navigate")}` : "";
|
|
29
29
|
}
|
|
30
|
+
/** Small Pi-native list page used inside the single /agents custom UI lifecycle. */
|
|
31
|
+
class ChoiceMenuComponent extends Container {
|
|
32
|
+
get focused() {
|
|
33
|
+
return this._focused;
|
|
34
|
+
}
|
|
35
|
+
set focused(value) {
|
|
36
|
+
this._focused = value;
|
|
37
|
+
}
|
|
38
|
+
constructor(options) {
|
|
39
|
+
super();
|
|
40
|
+
this._focused = false;
|
|
41
|
+
this.theme = options.theme;
|
|
42
|
+
this.keybindings = options.keybindings;
|
|
43
|
+
this.choices = options.choices;
|
|
44
|
+
this.onDone = options.onDone;
|
|
45
|
+
this.title = options.title;
|
|
46
|
+
this.cancelDescription = options.cancelDescription;
|
|
47
|
+
this.selectedIndex = Math.min(Math.max(options.initialIndex ?? 0, 0), Math.max(0, options.choices.length - 1));
|
|
48
|
+
this.addChild(new DynamicBorder());
|
|
49
|
+
this.addChild(new Spacer(1));
|
|
50
|
+
this.titleText = new Text("", 1, 0);
|
|
51
|
+
this.addChild(this.titleText);
|
|
52
|
+
this.addChild(new Spacer(1));
|
|
53
|
+
this.listContainer = new Container();
|
|
54
|
+
this.addChild(this.listContainer);
|
|
55
|
+
this.addChild(new Spacer(1));
|
|
56
|
+
this.hintText = new Text("", 1, 0);
|
|
57
|
+
this.addChild(this.hintText);
|
|
58
|
+
this.addChild(new Spacer(1));
|
|
59
|
+
this.addChild(new DynamicBorder());
|
|
60
|
+
this.updateStaticText();
|
|
61
|
+
this.updateList();
|
|
62
|
+
}
|
|
63
|
+
updateStaticText() {
|
|
64
|
+
this.titleText.setText(this.theme.fg("accent", this.theme.bold(this.title)));
|
|
65
|
+
const hints = [
|
|
66
|
+
navigationHint(this.theme, this.keybindings),
|
|
67
|
+
hint(this.theme, this.keybindings, "tui.select.confirm", "select"),
|
|
68
|
+
hint(this.theme, this.keybindings, "tui.select.cancel", this.cancelDescription),
|
|
69
|
+
].filter(Boolean);
|
|
70
|
+
this.hintText.setText(hints.join(this.theme.fg("muted", " • ")));
|
|
71
|
+
}
|
|
72
|
+
updateList() {
|
|
73
|
+
this.listContainer.clear();
|
|
74
|
+
for (const [index, choice] of this.choices.entries()) {
|
|
75
|
+
const selected = index === this.selectedIndex;
|
|
76
|
+
const prefix = selected ? this.theme.fg("accent", "→ ") : " ";
|
|
77
|
+
const label = this.theme.fg(selected ? "accent" : "text", choice.label);
|
|
78
|
+
this.listContainer.addChild(new TruncatedText(`${prefix}${label}`, 1, 0));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
moveSelection(offset) {
|
|
82
|
+
if (this.choices.length === 0)
|
|
83
|
+
return;
|
|
84
|
+
this.selectedIndex = (this.selectedIndex + offset + this.choices.length) % this.choices.length;
|
|
85
|
+
this.updateList();
|
|
86
|
+
}
|
|
87
|
+
invalidate() {
|
|
88
|
+
this.updateStaticText();
|
|
89
|
+
this.updateList();
|
|
90
|
+
super.invalidate();
|
|
91
|
+
}
|
|
92
|
+
handleInput(data) {
|
|
93
|
+
if (this.keybindings.matches(data, "tui.select.up")) {
|
|
94
|
+
this.moveSelection(-1);
|
|
95
|
+
}
|
|
96
|
+
else if (this.keybindings.matches(data, "tui.select.down")) {
|
|
97
|
+
this.moveSelection(1);
|
|
98
|
+
}
|
|
99
|
+
else if (this.keybindings.matches(data, "tui.select.confirm")) {
|
|
100
|
+
const choice = this.choices[this.selectedIndex];
|
|
101
|
+
if (choice)
|
|
102
|
+
this.onDone(choice);
|
|
103
|
+
}
|
|
104
|
+
else if (this.keybindings.matches(data, "tui.select.cancel")) {
|
|
105
|
+
this.onDone(undefined);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
30
109
|
/** Compact Model/Thinking settings menu for one profile; every confirm persists immediately. */
|
|
31
110
|
class ProfileSettingsMenuComponent extends Container {
|
|
32
111
|
get focused() {
|
|
@@ -42,29 +121,48 @@ class ProfileSettingsMenuComponent extends Container {
|
|
|
42
121
|
this.theme = options.theme;
|
|
43
122
|
this.keybindings = options.keybindings;
|
|
44
123
|
this.onDone = options.onDone;
|
|
124
|
+
this.title = AGENT_PROFILE_LABELS[options.profile.name];
|
|
125
|
+
this.status = options.status;
|
|
45
126
|
this.rows = buildSettingsRows({
|
|
46
127
|
override: options.override,
|
|
47
128
|
models: options.models,
|
|
48
129
|
currentSessionModel: options.currentSessionModel,
|
|
49
130
|
currentThinking: options.currentThinking,
|
|
50
131
|
});
|
|
132
|
+
this.selectedIndex = Math.max(0, this.rows.findIndex((row) => row.action === options.selectedAction));
|
|
51
133
|
this.addChild(new DynamicBorder());
|
|
52
134
|
this.addChild(new Spacer(1));
|
|
53
|
-
this.
|
|
135
|
+
this.titleText = new Text("", 1, 0);
|
|
136
|
+
this.addChild(this.titleText);
|
|
54
137
|
this.addChild(new Spacer(1));
|
|
55
138
|
this.listContainer = new Container();
|
|
56
139
|
this.addChild(this.listContainer);
|
|
57
140
|
this.addChild(new Spacer(1));
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
141
|
+
if (this.status) {
|
|
142
|
+
this.statusText = new Text("", 1, 0);
|
|
143
|
+
this.addChild(this.statusText);
|
|
144
|
+
this.addChild(new Spacer(1));
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
this.statusText = undefined;
|
|
148
|
+
}
|
|
149
|
+
this.hintText = new Text("", 1, 0);
|
|
150
|
+
this.addChild(this.hintText);
|
|
64
151
|
this.addChild(new Spacer(1));
|
|
65
152
|
this.addChild(new DynamicBorder());
|
|
153
|
+
this.updateStaticText();
|
|
66
154
|
this.updateList();
|
|
67
155
|
}
|
|
156
|
+
updateStaticText() {
|
|
157
|
+
this.titleText.setText(this.theme.fg("accent", this.theme.bold(this.title)));
|
|
158
|
+
this.statusText?.setText(this.theme.fg("muted", this.status ?? ""));
|
|
159
|
+
const hints = [
|
|
160
|
+
navigationHint(this.theme, this.keybindings),
|
|
161
|
+
hint(this.theme, this.keybindings, "tui.select.confirm", "select"),
|
|
162
|
+
hint(this.theme, this.keybindings, "tui.select.cancel", "back"),
|
|
163
|
+
].filter(Boolean);
|
|
164
|
+
this.hintText.setText(hints.join(this.theme.fg("muted", " • ")));
|
|
165
|
+
}
|
|
68
166
|
updateList() {
|
|
69
167
|
this.listContainer.clear();
|
|
70
168
|
for (const [index, row] of this.rows.entries()) {
|
|
@@ -80,6 +178,11 @@ class ProfileSettingsMenuComponent extends Container {
|
|
|
80
178
|
this.selectedIndex = (this.selectedIndex + offset + this.rows.length) % this.rows.length;
|
|
81
179
|
this.updateList();
|
|
82
180
|
}
|
|
181
|
+
invalidate() {
|
|
182
|
+
this.updateStaticText();
|
|
183
|
+
this.updateList();
|
|
184
|
+
super.invalidate();
|
|
185
|
+
}
|
|
83
186
|
handleInput(data) {
|
|
84
187
|
if (this.keybindings.matches(data, "tui.select.up")) {
|
|
85
188
|
this.moveSelection(-1);
|
|
@@ -95,7 +198,7 @@ class ProfileSettingsMenuComponent extends Container {
|
|
|
95
198
|
}
|
|
96
199
|
}
|
|
97
200
|
}
|
|
98
|
-
/**
|
|
201
|
+
/** Searchable model page for one profile; confirm saves immediately. */
|
|
99
202
|
class ModelPickerComponent extends Container {
|
|
100
203
|
get focused() {
|
|
101
204
|
return this._focused;
|
|
@@ -112,9 +215,12 @@ class ModelPickerComponent extends Container {
|
|
|
112
215
|
this.tui = options.tui;
|
|
113
216
|
this.theme = options.theme;
|
|
114
217
|
this.keybindings = options.keybindings;
|
|
218
|
+
this.title = `Model — ${AGENT_PROFILE_LABELS[options.profile.name]}`;
|
|
219
|
+
this.hasScopedModels = options.scopedModels.length > 0;
|
|
115
220
|
this.addChild(new DynamicBorder());
|
|
116
221
|
this.addChild(new Spacer(1));
|
|
117
|
-
this.
|
|
222
|
+
this.titleText = new Text("", 1, 0);
|
|
223
|
+
this.addChild(this.titleText);
|
|
118
224
|
this.addChild(new Spacer(1));
|
|
119
225
|
this.modelList = new ProfileModelListComponent({
|
|
120
226
|
theme: options.theme,
|
|
@@ -127,15 +233,21 @@ class ModelPickerComponent extends Container {
|
|
|
127
233
|
});
|
|
128
234
|
this.addChild(this.modelList);
|
|
129
235
|
this.addChild(new Spacer(1));
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
options.scopedModels.length > 0 ? hint(this.theme, options.keybindings, "tui.input.tab", "scope") : "",
|
|
133
|
-
hint(this.theme, options.keybindings, "tui.select.confirm", "select"),
|
|
134
|
-
hint(this.theme, options.keybindings, "tui.select.cancel", "back"),
|
|
135
|
-
].filter(Boolean);
|
|
136
|
-
this.addChild(new Text(hints.join(this.theme.fg("muted", " • ")), 1, 0));
|
|
236
|
+
this.hintText = new Text("", 1, 0);
|
|
237
|
+
this.addChild(this.hintText);
|
|
137
238
|
this.addChild(new Spacer(1));
|
|
138
239
|
this.addChild(new DynamicBorder());
|
|
240
|
+
this.updateStaticText();
|
|
241
|
+
}
|
|
242
|
+
updateStaticText() {
|
|
243
|
+
this.titleText.setText(this.theme.fg("accent", this.theme.bold(this.title)));
|
|
244
|
+
const hints = [
|
|
245
|
+
navigationHint(this.theme, this.keybindings),
|
|
246
|
+
this.hasScopedModels ? hint(this.theme, this.keybindings, "tui.input.tab", "scope") : "",
|
|
247
|
+
hint(this.theme, this.keybindings, "tui.select.confirm", "select"),
|
|
248
|
+
hint(this.theme, this.keybindings, "tui.select.cancel", "back"),
|
|
249
|
+
].filter(Boolean);
|
|
250
|
+
this.hintText.setText(hints.join(this.theme.fg("muted", " • ")));
|
|
139
251
|
}
|
|
140
252
|
get refreshSignal() {
|
|
141
253
|
return this.refreshAbortController.signal;
|
|
@@ -162,20 +274,22 @@ class ModelPickerComponent extends Container {
|
|
|
162
274
|
this.modelList.setStatus(message, tone);
|
|
163
275
|
this.tui.requestRender();
|
|
164
276
|
}
|
|
277
|
+
invalidate() {
|
|
278
|
+
this.updateStaticText();
|
|
279
|
+
super.invalidate();
|
|
280
|
+
}
|
|
165
281
|
handleInput(data) {
|
|
166
282
|
this.modelList.handleInput(data);
|
|
167
283
|
}
|
|
168
284
|
}
|
|
169
285
|
/** Persist a single override atomically; the UI only reflects the value on success. */
|
|
170
|
-
async function persistOverride(ctx, profile, patch
|
|
171
|
-
const next = "model" in patch ? patch.model : patch.thinking;
|
|
172
|
-
if (next === current)
|
|
173
|
-
return;
|
|
286
|
+
async function persistOverride(ctx, profile, patch) {
|
|
174
287
|
try {
|
|
175
|
-
await updateProfileOverride(profile.name, patch, getAgentDir());
|
|
288
|
+
return await updateProfileOverride(profile.name, patch, getAgentDir());
|
|
176
289
|
}
|
|
177
290
|
catch (error) {
|
|
178
291
|
ctx.ui.notify(`Could not save ${AGENT_PROFILE_LABELS[profile.name]} settings: ${error instanceof Error ? error.message : String(error)}`, "error");
|
|
292
|
+
return undefined;
|
|
179
293
|
}
|
|
180
294
|
}
|
|
181
295
|
async function refreshPickerModels(ctx, picker) {
|
|
@@ -218,6 +332,194 @@ async function refreshPickerModels(ctx, picker) {
|
|
|
218
332
|
clearTimeout(timeout);
|
|
219
333
|
}
|
|
220
334
|
}
|
|
335
|
+
/** One mounted /agents TUI whose child pages switch without restoring the editor between them. */
|
|
336
|
+
class AgentsMenuComponent extends Container {
|
|
337
|
+
get focused() {
|
|
338
|
+
return this._focused;
|
|
339
|
+
}
|
|
340
|
+
set focused(value) {
|
|
341
|
+
this._focused = value;
|
|
342
|
+
if (this.activeScreen && isFocusable(this.activeScreen))
|
|
343
|
+
this.activeScreen.focused = value;
|
|
344
|
+
}
|
|
345
|
+
constructor(options) {
|
|
346
|
+
super();
|
|
347
|
+
this.route = { kind: "profiles" };
|
|
348
|
+
this.selectedSettingsAction = "model";
|
|
349
|
+
this.saving = false;
|
|
350
|
+
this.closed = false;
|
|
351
|
+
this._focused = false;
|
|
352
|
+
this.tui = options.tui;
|
|
353
|
+
this.theme = options.theme;
|
|
354
|
+
this.keybindings = options.keybindings;
|
|
355
|
+
this.ctx = options.ctx;
|
|
356
|
+
this.currentThinking = options.currentThinking;
|
|
357
|
+
this.config = options.config;
|
|
358
|
+
this.onDone = options.onDone;
|
|
359
|
+
this.showProfiles();
|
|
360
|
+
}
|
|
361
|
+
disposeActiveScreen() {
|
|
362
|
+
const screen = this.activeScreen;
|
|
363
|
+
this.activeScreen = undefined;
|
|
364
|
+
if (!screen)
|
|
365
|
+
return;
|
|
366
|
+
const disposable = screen;
|
|
367
|
+
if (isFocusable(screen))
|
|
368
|
+
screen.focused = false;
|
|
369
|
+
disposable.dispose?.();
|
|
370
|
+
}
|
|
371
|
+
setActiveScreen(screen) {
|
|
372
|
+
this.disposeActiveScreen();
|
|
373
|
+
this.clear();
|
|
374
|
+
this.activeScreen = screen;
|
|
375
|
+
this.addChild(screen);
|
|
376
|
+
if (isFocusable(screen))
|
|
377
|
+
screen.focused = this._focused;
|
|
378
|
+
this.tui.requestRender();
|
|
379
|
+
}
|
|
380
|
+
showProfiles() {
|
|
381
|
+
this.route = { kind: "profiles" };
|
|
382
|
+
const choices = AGENT_PROFILES.map((profile) => ({
|
|
383
|
+
label: AGENT_PROFILE_LABELS[profile.name],
|
|
384
|
+
value: profile,
|
|
385
|
+
}));
|
|
386
|
+
const initialIndex = choices.findIndex((choice) => choice.value.name === this.selectedProfile?.name);
|
|
387
|
+
this.setActiveScreen(new ChoiceMenuComponent({
|
|
388
|
+
theme: this.theme,
|
|
389
|
+
keybindings: this.keybindings,
|
|
390
|
+
title: "Agents",
|
|
391
|
+
choices,
|
|
392
|
+
initialIndex,
|
|
393
|
+
cancelDescription: "close",
|
|
394
|
+
onDone: (choice) => {
|
|
395
|
+
if (!choice) {
|
|
396
|
+
this.onDone();
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
this.selectedProfile = choice.value;
|
|
400
|
+
this.selectedSettingsAction = "model";
|
|
401
|
+
this.showSettings(choice.value);
|
|
402
|
+
},
|
|
403
|
+
}));
|
|
404
|
+
}
|
|
405
|
+
showSettings(profile, selectedAction = this.selectedSettingsAction) {
|
|
406
|
+
this.selectedProfile = profile;
|
|
407
|
+
this.selectedSettingsAction = selectedAction;
|
|
408
|
+
this.route = { kind: "settings", profile, selectedAction };
|
|
409
|
+
this.setActiveScreen(new ProfileSettingsMenuComponent({
|
|
410
|
+
theme: this.theme,
|
|
411
|
+
keybindings: this.keybindings,
|
|
412
|
+
profile,
|
|
413
|
+
override: this.config.profiles[profile.name],
|
|
414
|
+
models: this.ctx.modelRegistry.getAvailable(),
|
|
415
|
+
currentSessionModel: this.ctx.model,
|
|
416
|
+
currentThinking: this.currentThinking,
|
|
417
|
+
selectedAction,
|
|
418
|
+
status: this.saving ? "Saving…" : undefined,
|
|
419
|
+
onDone: (action) => {
|
|
420
|
+
if (!action) {
|
|
421
|
+
this.showProfiles();
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
this.selectedSettingsAction = action;
|
|
425
|
+
if (action === "model")
|
|
426
|
+
this.showModelPicker(profile);
|
|
427
|
+
else
|
|
428
|
+
this.showThinkingPicker(profile);
|
|
429
|
+
},
|
|
430
|
+
}));
|
|
431
|
+
}
|
|
432
|
+
showModelPicker(profile) {
|
|
433
|
+
this.route = { kind: "model", profile };
|
|
434
|
+
const override = this.config.profiles[profile.name];
|
|
435
|
+
const picker = new ModelPickerComponent({
|
|
436
|
+
tui: this.tui,
|
|
437
|
+
theme: this.theme,
|
|
438
|
+
keybindings: this.keybindings,
|
|
439
|
+
profile,
|
|
440
|
+
savedModelId: override?.model,
|
|
441
|
+
models: this.ctx.modelRegistry.getAvailable(),
|
|
442
|
+
scopedModels: this.ctx.scopedModels,
|
|
443
|
+
currentSessionModel: this.ctx.model,
|
|
444
|
+
onDone: (choice) => {
|
|
445
|
+
if (!choice) {
|
|
446
|
+
this.showSettings(profile, "model");
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
this.saveOverride(profile, { model: choice.modelId }, "model");
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
picker.setRefreshStatus("Refreshing model catalogs…");
|
|
453
|
+
this.setActiveScreen(picker);
|
|
454
|
+
void refreshPickerModels(this.ctx, picker);
|
|
455
|
+
}
|
|
456
|
+
showThinkingPicker(profile) {
|
|
457
|
+
this.route = { kind: "thinking", profile };
|
|
458
|
+
const override = this.config.profiles[profile.name];
|
|
459
|
+
const choices = [
|
|
460
|
+
...buildThinkingChoices({
|
|
461
|
+
currentSessionModel: this.ctx.model,
|
|
462
|
+
models: this.ctx.modelRegistry.getAvailable(),
|
|
463
|
+
override,
|
|
464
|
+
currentThinking: this.currentThinking,
|
|
465
|
+
}).entries(),
|
|
466
|
+
].map(([label, level]) => ({ label, value: level }));
|
|
467
|
+
const initialIndex = choices.findIndex((choice) => choice.label.endsWith(" ✓"));
|
|
468
|
+
this.setActiveScreen(new ChoiceMenuComponent({
|
|
469
|
+
theme: this.theme,
|
|
470
|
+
keybindings: this.keybindings,
|
|
471
|
+
title: `Thinking — ${AGENT_PROFILE_LABELS[profile.name]}`,
|
|
472
|
+
choices,
|
|
473
|
+
initialIndex,
|
|
474
|
+
cancelDescription: "back",
|
|
475
|
+
onDone: (choice) => {
|
|
476
|
+
if (!choice) {
|
|
477
|
+
this.showSettings(profile, "thinking");
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
this.saveOverride(profile, { thinking: choice.value }, "thinking");
|
|
481
|
+
},
|
|
482
|
+
}));
|
|
483
|
+
}
|
|
484
|
+
saveOverride(profile, patch, returnAction) {
|
|
485
|
+
if (this.saving)
|
|
486
|
+
return;
|
|
487
|
+
this.saving = true;
|
|
488
|
+
this.showSettings(profile, returnAction);
|
|
489
|
+
void persistOverride(this.ctx, profile, patch)
|
|
490
|
+
.then((config) => this.completeSave(profile, config), () => this.completeSave(profile, undefined))
|
|
491
|
+
.catch(() => {
|
|
492
|
+
// A reload can stale the command context while the queued file write finishes.
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
completeSave(profile, config) {
|
|
496
|
+
if (this.closed)
|
|
497
|
+
return;
|
|
498
|
+
this.saving = false;
|
|
499
|
+
if (config)
|
|
500
|
+
this.config = config;
|
|
501
|
+
if (this.route.kind === "settings" && this.route.profile.name === profile.name) {
|
|
502
|
+
this.showSettings(profile, this.route.selectedAction);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
handleInput(data) {
|
|
506
|
+
if (!this.saving) {
|
|
507
|
+
this.activeScreen?.handleInput?.(data);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (!this.keybindings.matches(data, "tui.select.cancel"))
|
|
511
|
+
return;
|
|
512
|
+
if (this.route.kind === "settings")
|
|
513
|
+
this.showProfiles();
|
|
514
|
+
else if (this.route.kind === "profiles")
|
|
515
|
+
this.onDone();
|
|
516
|
+
}
|
|
517
|
+
dispose() {
|
|
518
|
+
this.closed = true;
|
|
519
|
+
this.disposeActiveScreen();
|
|
520
|
+
this.clear();
|
|
521
|
+
}
|
|
522
|
+
}
|
|
221
523
|
async function selectProfile(ctx) {
|
|
222
524
|
const labels = AGENT_PROFILES.map((profile) => AGENT_PROFILE_LABELS[profile.name]);
|
|
223
525
|
const label = await ctx.ui.select("Agents", labels);
|
|
@@ -225,18 +527,6 @@ async function selectProfile(ctx) {
|
|
|
225
527
|
? undefined
|
|
226
528
|
: AGENT_PROFILES.find((profile) => AGENT_PROFILE_LABELS[profile.name] === label);
|
|
227
529
|
}
|
|
228
|
-
async function showTuiSettingsMenu(ctx, profile, override, currentThinking) {
|
|
229
|
-
return ctx.ui.custom((_tui, theme, keybindings, done) => new ProfileSettingsMenuComponent({
|
|
230
|
-
theme,
|
|
231
|
-
keybindings,
|
|
232
|
-
profile,
|
|
233
|
-
override,
|
|
234
|
-
models: ctx.modelRegistry.getAvailable(),
|
|
235
|
-
currentSessionModel: ctx.model,
|
|
236
|
-
currentThinking,
|
|
237
|
-
onDone: done,
|
|
238
|
-
}));
|
|
239
|
-
}
|
|
240
530
|
async function showDialogSettingsMenu(ctx, profile, override, currentThinking) {
|
|
241
531
|
const options = new Map();
|
|
242
532
|
for (const row of buildSettingsRows({
|
|
@@ -250,25 +540,6 @@ async function showDialogSettingsMenu(ctx, profile, override, currentThinking) {
|
|
|
250
540
|
const label = await ctx.ui.select(AGENT_PROFILE_LABELS[profile.name], [...options.keys()]);
|
|
251
541
|
return label === undefined ? undefined : options.get(label);
|
|
252
542
|
}
|
|
253
|
-
async function showTuiModelPicker(ctx, profile, override) {
|
|
254
|
-
const chosen = await ctx.ui.custom((tui, theme, keybindings, done) => {
|
|
255
|
-
const picker = new ModelPickerComponent({
|
|
256
|
-
tui,
|
|
257
|
-
theme,
|
|
258
|
-
keybindings,
|
|
259
|
-
profile,
|
|
260
|
-
savedModelId: override?.model,
|
|
261
|
-
models: ctx.modelRegistry.getAvailable(),
|
|
262
|
-
scopedModels: ctx.scopedModels,
|
|
263
|
-
currentSessionModel: ctx.model,
|
|
264
|
-
onDone: done,
|
|
265
|
-
});
|
|
266
|
-
picker.setRefreshStatus("Refreshing model catalogs…");
|
|
267
|
-
void refreshPickerModels(ctx, picker);
|
|
268
|
-
return picker;
|
|
269
|
-
});
|
|
270
|
-
return chosen === undefined ? undefined : { modelId: chosen.modelId };
|
|
271
|
-
}
|
|
272
543
|
async function showDialogModelPicker(ctx, profile, override) {
|
|
273
544
|
const models = [...ctx.modelRegistry.getAvailable()].sort(compareModels);
|
|
274
545
|
const choices = buildModelChoices({
|
|
@@ -279,7 +550,7 @@ async function showDialogModelPicker(ctx, profile, override) {
|
|
|
279
550
|
const label = await ctx.ui.select(`Model — ${AGENT_PROFILE_LABELS[profile.name]}`, [...choices.keys()]);
|
|
280
551
|
return label === undefined ? undefined : { modelId: choices.get(label) };
|
|
281
552
|
}
|
|
282
|
-
async function
|
|
553
|
+
async function showDialogThinkingPicker(ctx, profile, override, currentThinking) {
|
|
283
554
|
const choices = buildThinkingChoices({
|
|
284
555
|
currentSessionModel: ctx.model,
|
|
285
556
|
models: ctx.modelRegistry.getAvailable(),
|
|
@@ -289,43 +560,56 @@ async function showThinkingPicker(ctx, profile, override, currentThinking) {
|
|
|
289
560
|
const label = await ctx.ui.select(`Thinking — ${AGENT_PROFILE_LABELS[profile.name]}`, [...choices.keys()]);
|
|
290
561
|
return label === undefined ? undefined : { level: choices.get(label) };
|
|
291
562
|
}
|
|
292
|
-
async function
|
|
563
|
+
async function runDialogProfileSettings(ctx, profile, currentThinking) {
|
|
293
564
|
const agentDir = getAgentDir();
|
|
294
|
-
const isTui = ctx.mode === "tui";
|
|
295
565
|
while (true) {
|
|
296
566
|
const config = await loadSubagentConfig(agentDir);
|
|
297
567
|
const override = config.profiles[profile.name];
|
|
298
|
-
const action =
|
|
299
|
-
? await showTuiSettingsMenu(ctx, profile, override, currentThinking)
|
|
300
|
-
: await showDialogSettingsMenu(ctx, profile, override, currentThinking);
|
|
568
|
+
const action = await showDialogSettingsMenu(ctx, profile, override, currentThinking);
|
|
301
569
|
if (!action)
|
|
302
570
|
return;
|
|
303
571
|
if (action === "model") {
|
|
304
|
-
const chosen =
|
|
305
|
-
? await showTuiModelPicker(ctx, profile, override)
|
|
306
|
-
: await showDialogModelPicker(ctx, profile, override);
|
|
572
|
+
const chosen = await showDialogModelPicker(ctx, profile, override);
|
|
307
573
|
if (!chosen)
|
|
308
574
|
continue;
|
|
309
|
-
await persistOverride(ctx, profile, { model: chosen.modelId }
|
|
575
|
+
await persistOverride(ctx, profile, { model: chosen.modelId });
|
|
310
576
|
}
|
|
311
577
|
else {
|
|
312
|
-
const chosen = await
|
|
578
|
+
const chosen = await showDialogThinkingPicker(ctx, profile, override, currentThinking);
|
|
313
579
|
if (!chosen)
|
|
314
580
|
continue;
|
|
315
|
-
await persistOverride(ctx, profile, { thinking: chosen.level }
|
|
581
|
+
await persistOverride(ctx, profile, { thinking: chosen.level });
|
|
316
582
|
}
|
|
317
583
|
}
|
|
318
584
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
585
|
+
async function showTuiAgentsCommand(ctx, currentThinking) {
|
|
586
|
+
const config = await loadSubagentConfig(getAgentDir());
|
|
587
|
+
await ctx.ui.custom((tui, theme, keybindings, done) => new AgentsMenuComponent({
|
|
588
|
+
tui,
|
|
589
|
+
theme,
|
|
590
|
+
keybindings,
|
|
591
|
+
ctx,
|
|
592
|
+
currentThinking,
|
|
593
|
+
config,
|
|
594
|
+
onDone: () => done(),
|
|
595
|
+
}));
|
|
596
|
+
}
|
|
597
|
+
async function showDialogAgentsCommand(ctx, currentThinking) {
|
|
324
598
|
while (true) {
|
|
325
599
|
const profile = await selectProfile(ctx);
|
|
326
600
|
if (!profile)
|
|
327
601
|
return;
|
|
328
|
-
await
|
|
602
|
+
await runDialogProfileSettings(ctx, profile, currentThinking);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
export async function showAgentsCommand(ctx, currentThinking) {
|
|
606
|
+
if (!ctx.hasUI) {
|
|
607
|
+
ctx.ui.notify("/agents requires an interactive UI.", "warning");
|
|
608
|
+
return;
|
|
329
609
|
}
|
|
610
|
+
if (ctx.mode === "tui")
|
|
611
|
+
await showTuiAgentsCommand(ctx, currentThinking);
|
|
612
|
+
else
|
|
613
|
+
await showDialogAgentsCommand(ctx, currentThinking);
|
|
330
614
|
}
|
|
331
615
|
//# sourceMappingURL=agents-command.js.map
|