@sagmans/dsh-tui 0.6.0 → 0.7.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/.agents/skills/dsh-tui-dogfood/SKILL.md +83 -0
- package/.agents/skills/dsh-tui-dogfood/references/home-state.md +78 -0
- package/.agents/skills/dsh-tui-dogfood/scripts/clone-links.mjs +133 -0
- package/.agents/skills/dsh-tui-dogfood/scripts/run-plugin-from-worktree.sh +417 -0
- package/.agents/skills/dsh-tui-update-models/SKILL.md +121 -0
- package/.agents/skills/dsh-tui-update-models/references/model-wiring.md +162 -0
- package/.agents/skills/dsh-tui-update-models/scripts/dump-model-catalog.mjs +178 -0
- package/README.md +99 -5
- package/lib/agent/present.d.ts.map +1 -1
- package/lib/agent/present.js +2 -1
- package/lib/agent/present.js.map +1 -1
- package/lib/cards/composition.d.ts +68 -0
- package/lib/cards/composition.d.ts.map +1 -0
- package/lib/cards/composition.js +117 -0
- package/lib/cards/composition.js.map +1 -0
- package/lib/cards/presenter.d.ts +23 -0
- package/lib/cards/presenter.d.ts.map +1 -0
- package/lib/cards/presenter.js +394 -0
- package/lib/cards/presenter.js.map +1 -0
- package/lib/cards/preview.d.ts +42 -0
- package/lib/cards/preview.d.ts.map +1 -0
- package/lib/cards/preview.js +51 -0
- package/lib/cards/preview.js.map +1 -0
- package/lib/cards.d.ts +12 -120
- package/lib/cards.d.ts.map +1 -1
- package/lib/cards.js +4 -556
- package/lib/cards.js.map +1 -1
- package/lib/compat/section.d.ts +29 -0
- package/lib/compat/section.d.ts.map +1 -0
- package/lib/compat/section.js +82 -0
- package/lib/compat/section.js.map +1 -0
- package/lib/config.d.ts +27 -2
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +61 -1
- package/lib/config.js.map +1 -1
- package/lib/contracts.d.ts +28 -0
- package/lib/contracts.d.ts.map +1 -1
- package/lib/fold-cursor.d.ts +8 -0
- package/lib/fold-cursor.d.ts.map +1 -1
- package/lib/fold-cursor.js +18 -0
- package/lib/fold-cursor.js.map +1 -1
- package/lib/gates/question-card.d.ts +77 -0
- package/lib/gates/question-card.d.ts.map +1 -0
- package/lib/gates/question-card.js +113 -0
- package/lib/gates/question-card.js.map +1 -0
- package/lib/gates/questions.d.ts +127 -0
- package/lib/gates/questions.d.ts.map +1 -0
- package/lib/gates/questions.js +418 -0
- package/lib/gates/questions.js.map +1 -0
- package/lib/gates.d.ts +1 -113
- package/lib/gates.d.ts.map +1 -1
- package/lib/gates.js +1 -484
- package/lib/gates.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +343 -2602
- package/lib/index.js.map +1 -1
- package/lib/input/action-catalog.d.ts +74 -0
- package/lib/input/action-catalog.d.ts.map +1 -0
- package/lib/input/action-catalog.js +137 -0
- package/lib/input/action-catalog.js.map +1 -0
- package/lib/input/actions.d.ts +5 -81
- package/lib/input/actions.d.ts.map +1 -1
- package/lib/input/actions.js +4 -625
- package/lib/input/actions.js.map +1 -1
- package/lib/input/completion.d.ts +1 -1
- package/lib/input/completion.d.ts.map +1 -1
- package/lib/input/completion.js +2 -1
- package/lib/input/completion.js.map +1 -1
- package/lib/input/file-index.d.ts +40 -0
- package/lib/input/file-index.d.ts.map +1 -0
- package/lib/input/file-index.js +141 -0
- package/lib/input/file-index.js.map +1 -0
- package/lib/input/file-search.d.ts +1 -38
- package/lib/input/file-search.d.ts.map +1 -1
- package/lib/input/file-search.js +1 -487
- package/lib/input/file-search.js.map +1 -1
- package/lib/input/key-press.d.ts +57 -0
- package/lib/input/key-press.d.ts.map +1 -0
- package/lib/input/key-press.js +218 -0
- package/lib/input/key-press.js.map +1 -0
- package/lib/input/keymap-conflicts.d.ts +59 -0
- package/lib/input/keymap-conflicts.d.ts.map +1 -0
- package/lib/input/keymap-conflicts.js +292 -0
- package/lib/input/keymap-conflicts.js.map +1 -0
- package/lib/input/keymap-settings.js +1 -1
- package/lib/input/keymap-settings.js.map +1 -1
- package/lib/input/keymap.d.ts.map +1 -1
- package/lib/input/keymap.js +3 -1
- package/lib/input/keymap.js.map +1 -1
- package/lib/input/workspace-files.d.ts +10 -0
- package/lib/input/workspace-files.d.ts.map +1 -0
- package/lib/input/workspace-files.js +359 -0
- package/lib/input/workspace-files.js.map +1 -0
- package/lib/install-skills.d.ts +20 -0
- package/lib/install-skills.d.ts.map +1 -0
- package/lib/install-skills.js +198 -0
- package/lib/install-skills.js.map +1 -0
- package/lib/keys-command.d.ts +2 -1
- package/lib/keys-command.d.ts.map +1 -1
- package/lib/keys-command.js +2 -1
- package/lib/keys-command.js.map +1 -1
- package/lib/model-list.d.ts +37 -0
- package/lib/model-list.d.ts.map +1 -0
- package/lib/model-list.js +60 -0
- package/lib/model-list.js.map +1 -0
- package/lib/startup.d.ts +8 -0
- package/lib/startup.d.ts.map +1 -1
- package/lib/startup.js +120 -24
- package/lib/startup.js.map +1 -1
- package/lib/subagents.d.ts +7 -3
- package/lib/subagents.d.ts.map +1 -1
- package/lib/subagents.js +28 -4
- package/lib/subagents.js.map +1 -1
- package/lib/surface/appearance-preferences.d.ts +26 -0
- package/lib/surface/appearance-preferences.d.ts.map +1 -0
- package/lib/surface/appearance-preferences.js +139 -0
- package/lib/surface/appearance-preferences.js.map +1 -0
- package/lib/surface/appearance.d.ts +87 -0
- package/lib/surface/appearance.d.ts.map +1 -0
- package/lib/surface/appearance.js +353 -0
- package/lib/surface/appearance.js.map +1 -0
- package/lib/surface/background-work.d.ts +49 -0
- package/lib/surface/background-work.d.ts.map +1 -0
- package/lib/surface/background-work.js +146 -0
- package/lib/surface/background-work.js.map +1 -0
- package/lib/surface/commands.d.ts +80 -0
- package/lib/surface/commands.d.ts.map +1 -0
- package/lib/surface/commands.js +364 -0
- package/lib/surface/commands.js.map +1 -0
- package/lib/surface/modal-input.d.ts +58 -0
- package/lib/surface/modal-input.d.ts.map +1 -0
- package/lib/surface/modal-input.js +237 -0
- package/lib/surface/modal-input.js.map +1 -0
- package/lib/surface/model-choice.d.ts +54 -0
- package/lib/surface/model-choice.d.ts.map +1 -0
- package/lib/surface/model-choice.js +325 -0
- package/lib/surface/model-choice.js.map +1 -0
- package/lib/surface/preset-choice.d.ts +78 -0
- package/lib/surface/preset-choice.d.ts.map +1 -0
- package/lib/surface/preset-choice.js +163 -0
- package/lib/surface/preset-choice.js.map +1 -0
- package/lib/surface/prompt-input.d.ts +97 -0
- package/lib/surface/prompt-input.d.ts.map +1 -0
- package/lib/surface/prompt-input.js +215 -0
- package/lib/surface/prompt-input.js.map +1 -0
- package/lib/surface/prompt-memory.d.ts +76 -0
- package/lib/surface/prompt-memory.d.ts.map +1 -0
- package/lib/surface/prompt-memory.js +167 -0
- package/lib/surface/prompt-memory.js.map +1 -0
- package/lib/surface/session-lifecycle.d.ts +120 -0
- package/lib/surface/session-lifecycle.d.ts.map +1 -0
- package/lib/surface/session-lifecycle.js +321 -0
- package/lib/surface/session-lifecycle.js.map +1 -0
- package/lib/surface/session-picker.d.ts +39 -0
- package/lib/surface/session-picker.d.ts.map +1 -0
- package/lib/surface/session-picker.js +107 -0
- package/lib/surface/session-picker.js.map +1 -0
- package/lib/surface/session-view.d.ts +86 -0
- package/lib/surface/session-view.d.ts.map +1 -0
- package/lib/surface/session-view.js +215 -0
- package/lib/surface/session-view.js.map +1 -0
- package/lib/surface/staged-turns.d.ts +81 -0
- package/lib/surface/staged-turns.d.ts.map +1 -0
- package/lib/surface/staged-turns.js +206 -0
- package/lib/surface/staged-turns.js.map +1 -0
- package/lib/surface/terminal-lifecycle.d.ts +76 -0
- package/lib/surface/terminal-lifecycle.d.ts.map +1 -0
- package/lib/surface/terminal-lifecycle.js +222 -0
- package/lib/surface/terminal-lifecycle.js.map +1 -0
- package/lib/terminal-text/scan.d.ts +44 -0
- package/lib/terminal-text/scan.d.ts.map +1 -0
- package/lib/terminal-text/scan.js +195 -0
- package/lib/terminal-text/scan.js.map +1 -0
- package/lib/terminal-text/sgr.d.ts +32 -0
- package/lib/terminal-text/sgr.d.ts.map +1 -0
- package/lib/terminal-text/sgr.js +203 -0
- package/lib/terminal-text/sgr.js.map +1 -0
- package/lib/terminal-text.d.ts +1 -1
- package/lib/terminal-text.d.ts.map +1 -1
- package/lib/terminal-text.js +2 -379
- package/lib/terminal-text.js.map +1 -1
- package/lib/theme-command.js +2 -1
- package/lib/theme-command.js.map +1 -1
- package/lib/theme-defaults.d.ts +64 -0
- package/lib/theme-defaults.d.ts.map +1 -0
- package/lib/theme-defaults.js +248 -0
- package/lib/theme-defaults.js.map +1 -0
- package/lib/theme-resolver.d.ts +36 -0
- package/lib/theme-resolver.d.ts.map +1 -0
- package/lib/theme-resolver.js +112 -0
- package/lib/theme-resolver.js.map +1 -0
- package/lib/theme-schema.d.ts.map +1 -1
- package/lib/theme-schema.js +3 -2
- package/lib/theme-schema.js.map +1 -1
- package/lib/theme-settings.d.ts +5 -7
- package/lib/theme-settings.d.ts.map +1 -1
- package/lib/theme-settings.js +27 -19
- package/lib/theme-settings.js.map +1 -1
- package/lib/theme-tokens.d.ts +0 -89
- package/lib/theme-tokens.d.ts.map +1 -1
- package/lib/theme-tokens.js +0 -356
- package/lib/theme-tokens.js.map +1 -1
- package/lib/theme.d.ts +1 -1
- package/lib/theme.d.ts.map +1 -1
- package/lib/theme.js +2 -1
- package/lib/theme.js.map +1 -1
- package/lib/tool-display.d.ts.map +1 -1
- package/lib/tool-display.js +2 -1
- package/lib/tool-display.js.map +1 -1
- package/lib/transcript/message-content.d.ts +21 -0
- package/lib/transcript/message-content.d.ts.map +1 -0
- package/lib/transcript/message-content.js +61 -0
- package/lib/transcript/message-content.js.map +1 -0
- package/lib/transcript/tool-calls.d.ts +106 -0
- package/lib/transcript/tool-calls.d.ts.map +1 -0
- package/lib/transcript/tool-calls.js +254 -0
- package/lib/transcript/tool-calls.js.map +1 -0
- package/lib/transcript.d.ts +14 -55
- package/lib/transcript.d.ts.map +1 -1
- package/lib/transcript.js +31 -253
- package/lib/transcript.js.map +1 -1
- package/lib/ui/dock.d.ts +14 -2
- package/lib/ui/dock.d.ts.map +1 -1
- package/lib/ui/dock.js +52 -10
- package/lib/ui/dock.js.map +1 -1
- package/lib/ui/editor.d.ts.map +1 -1
- package/lib/ui/editor.js +2 -1
- package/lib/ui/editor.js.map +1 -1
- package/lib/ui/keymap-picker.d.ts +2 -1
- package/lib/ui/keymap-picker.d.ts.map +1 -1
- package/lib/ui/keymap-picker.js +1 -0
- package/lib/ui/keymap-picker.js.map +1 -1
- package/lib/ui/view/gate-card.d.ts +21 -0
- package/lib/ui/view/gate-card.d.ts.map +1 -0
- package/lib/ui/view/gate-card.js +104 -0
- package/lib/ui/view/gate-card.js.map +1 -0
- package/lib/ui/view/tool-card.d.ts +138 -0
- package/lib/ui/view/tool-card.d.ts.map +1 -0
- package/lib/ui/view/tool-card.js +413 -0
- package/lib/ui/view/tool-card.js.map +1 -0
- package/lib/ui/view/transcript-message.d.ts +62 -0
- package/lib/ui/view/transcript-message.d.ts.map +1 -0
- package/lib/ui/view/transcript-message.js +158 -0
- package/lib/ui/view/transcript-message.js.map +1 -0
- package/lib/ui/view.d.ts +80 -220
- package/lib/ui/view.d.ts.map +1 -1
- package/lib/ui/view.js +81 -675
- package/lib/ui/view.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { ModelSwitch, createModelCatalog, parseModelArgument, readModelRouteKey, } from "../agent/model.js";
|
|
2
|
+
import { stripControlCharacters } from "../text.js";
|
|
3
|
+
import { EffortPicker, ModelPicker, PROVIDER_DEFAULT_EFFORT_ID, effortChoices } from "../ui/picker.js";
|
|
4
|
+
// Adapter errors may contain credentials or request bodies, even in their messages.
|
|
5
|
+
const MODEL_DISCOVERY_FAILURE = 'could not list models; check provider configuration and credentials, then retry /model';
|
|
6
|
+
const PROVIDER_DISCOVERY_FAILURE = 'could not list providers; check provider configuration, then retry /model';
|
|
7
|
+
/**
|
|
8
|
+
* Which model and reasoning effort this session runs with, and the two pickers
|
|
9
|
+
* that change them.
|
|
10
|
+
*
|
|
11
|
+
* The switch and the catalog are one owner because a choice only means
|
|
12
|
+
* something against the directory it was read from: the rows of the model list
|
|
13
|
+
* stream in as each provider's adapter answers, and the levels belong to the
|
|
14
|
+
* exact route. The route in force is resolved against the status facts as much
|
|
15
|
+
* as against the switch, because a session that has chosen nothing runs the
|
|
16
|
+
* settings-backed default the footer states.
|
|
17
|
+
*/
|
|
18
|
+
export function createModelChoice(ctx, ports) {
|
|
19
|
+
const modelSwitch = new ModelSwitch();
|
|
20
|
+
const catalog = createModelCatalog(ctx);
|
|
21
|
+
const runModelCommand = (argument) => {
|
|
22
|
+
if (catalog === undefined) {
|
|
23
|
+
ports.notice('this profile has no llm service, so models cannot be listed or switched');
|
|
24
|
+
ports.render();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
let providers;
|
|
28
|
+
try {
|
|
29
|
+
providers = catalog.providers();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
ports.notice(PROVIDER_DISCOVERY_FAILURE);
|
|
33
|
+
ports.render();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const command = parseModelArgument(argument, providers, modelSwitch.current());
|
|
37
|
+
switch (command.kind) {
|
|
38
|
+
case 'current':
|
|
39
|
+
// Choosing by eye is the point of a terminal selector; the picker
|
|
40
|
+
// heads itself with the route the next step will actually use.
|
|
41
|
+
void openModelPicker(providers);
|
|
42
|
+
return;
|
|
43
|
+
case 'list-models':
|
|
44
|
+
void catalog.models(command.provider).then(entries => {
|
|
45
|
+
ports.notice(entries.length === 0
|
|
46
|
+
? `${command.provider} advertises no models; an id may still work`
|
|
47
|
+
: `${command.provider}: ${entries.map(entry => entry.id).join(' ')}`);
|
|
48
|
+
ports.render();
|
|
49
|
+
}).catch(() => {
|
|
50
|
+
ports.notice(`${stripControlCharacters(command.provider)}: ${MODEL_DISCOVERY_FAILURE}`);
|
|
51
|
+
ports.render();
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
case 'switch': {
|
|
55
|
+
const choice = command.choice;
|
|
56
|
+
if (choice.reasoningEffort === undefined) {
|
|
57
|
+
// Naming no level still leaves one in force, and the model the reader
|
|
58
|
+
// is moving to decides whether it can take it: a level the request
|
|
59
|
+
// path would refuse makes an otherwise usable model look broken.
|
|
60
|
+
void (async () => {
|
|
61
|
+
const carried = await carriedEffort(choice.provider, choice.model);
|
|
62
|
+
modelSwitch.choose({
|
|
63
|
+
provider: choice.provider,
|
|
64
|
+
model: choice.model,
|
|
65
|
+
...(carried.effort === undefined ? {} : { reasoningEffort: carried.effort }),
|
|
66
|
+
});
|
|
67
|
+
ports.notice(`model set to ${choice.provider}/${choice.model} for the next step${droppedClause(carried.dropped)}`);
|
|
68
|
+
ports.render();
|
|
69
|
+
})();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// The route decides which efforts exist, so an explicit one is checked
|
|
73
|
+
// against the adapter before it is put in force: a typo must not become
|
|
74
|
+
// a request the provider rejects.
|
|
75
|
+
void (async () => {
|
|
76
|
+
try {
|
|
77
|
+
const info = await catalog.efforts(choice.provider, choice.model);
|
|
78
|
+
const efforts = info?.efforts ?? [];
|
|
79
|
+
if (!efforts.some(effort => effort.id === choice.reasoningEffort)) {
|
|
80
|
+
ports.notice(efforts.length === 0
|
|
81
|
+
? `/model: ${choice.provider}/${choice.model} advertises no reasoning efforts`
|
|
82
|
+
: `/model: ${choice.provider}/${choice.model} does not offer reasoning effort "${choice.reasoningEffort}" — offers: ${efforts.map(effort => effort.id).join(' ')}`);
|
|
83
|
+
ports.render();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
modelSwitch.choose(choice);
|
|
87
|
+
ports.notice(`model set to ${choice.provider}/${choice.model} (${choice.reasoningEffort}) for the next step`);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
ports.notice(`/model: could not read reasoning efforts: ${error instanceof Error ? error.message : String(error)}`);
|
|
91
|
+
}
|
|
92
|
+
ports.render();
|
|
93
|
+
})();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
case 'invalid':
|
|
97
|
+
ports.notice(`/model: ${command.reason}`);
|
|
98
|
+
ports.render();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
/** Whether a route's effort list is being read, so a second key cannot race it. */
|
|
103
|
+
let openingEfforts = false;
|
|
104
|
+
/** Put the reader's effort choice in force for the next step. */
|
|
105
|
+
const applyEffort = (provider, modelId, effortId) => {
|
|
106
|
+
modelSwitch.choose(effortId === PROVIDER_DEFAULT_EFFORT_ID
|
|
107
|
+
? { provider, model: modelId }
|
|
108
|
+
: { provider, model: modelId, reasoningEffort: effortId });
|
|
109
|
+
ports.notice(`reasoning effort for ${provider}/${modelId} set to ${effortId === PROVIDER_DEFAULT_EFFORT_ID ? 'provider default' : effortId} for the next step`);
|
|
110
|
+
ports.render();
|
|
111
|
+
};
|
|
112
|
+
/** Whether a model picker's catalog is being read, so a second key cannot race it. */
|
|
113
|
+
let openingModels = false;
|
|
114
|
+
/**
|
|
115
|
+
* The route the next step would actually use.
|
|
116
|
+
*
|
|
117
|
+
* Without a choice of its own the surface reports the composition default,
|
|
118
|
+
* not that it has no opinion: the picker's heading and its marked row have to
|
|
119
|
+
* agree with the status line about the route in force.
|
|
120
|
+
*/
|
|
121
|
+
const effectiveRoute = () => {
|
|
122
|
+
const chosen = modelSwitch.current();
|
|
123
|
+
if (chosen !== undefined)
|
|
124
|
+
return chosen;
|
|
125
|
+
const facts = ports.statusFacts();
|
|
126
|
+
if (facts.provider === undefined || facts.model === undefined)
|
|
127
|
+
return undefined;
|
|
128
|
+
return {
|
|
129
|
+
provider: facts.provider,
|
|
130
|
+
model: facts.model,
|
|
131
|
+
...facts.effort === undefined ? {} : { reasoningEffort: facts.effort },
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* The effort a switch may carry onto the route it lands on.
|
|
136
|
+
*
|
|
137
|
+
* The levels belong to the exact route, so the level in force is checked
|
|
138
|
+
* against the model the reader moves to: the request path refuses an
|
|
139
|
+
* unsupported level before the provider sees it, and that refusal reads as
|
|
140
|
+
* the chosen model being broken. The model's own default is the fallback the
|
|
141
|
+
* picker's provider-default row also produces, and the level given up is
|
|
142
|
+
* named because silence would leave the reader reading a level that is no
|
|
143
|
+
* longer in force.
|
|
144
|
+
*/
|
|
145
|
+
const carriedEffort = async (provider, modelId) => {
|
|
146
|
+
const inForce = effectiveRoute()?.reasoningEffort;
|
|
147
|
+
if (inForce === undefined || catalog === undefined)
|
|
148
|
+
return {};
|
|
149
|
+
try {
|
|
150
|
+
const efforts = (await catalog.efforts(provider, modelId))?.efforts ?? [];
|
|
151
|
+
return efforts.some(effort => effort.id === inForce) ? { effort: inForce } : { dropped: inForce };
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// The directory is advisory here: a switch the reader asked for must not
|
|
155
|
+
// fail on it, and a route's default is the one state every model accepts.
|
|
156
|
+
return {};
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
/** The clause a switch adds when the effort in force could not travel with it. */
|
|
160
|
+
const droppedClause = (dropped) => dropped === undefined
|
|
161
|
+
? ''
|
|
162
|
+
: ` — dropped reasoning effort "${dropped}" because this model does not offer it`;
|
|
163
|
+
/** Put the reader's route choice in force for the next step. */
|
|
164
|
+
const applyRoute = async (route) => {
|
|
165
|
+
const carried = await carriedEffort(route.provider, route.model);
|
|
166
|
+
modelSwitch.choose({
|
|
167
|
+
provider: route.provider,
|
|
168
|
+
model: route.model,
|
|
169
|
+
...(carried.effort === undefined ? {} : { reasoningEffort: carried.effort }),
|
|
170
|
+
});
|
|
171
|
+
ports.notice(`model set to ${route.provider}/${route.model} for the next step${droppedClause(carried.dropped)}`);
|
|
172
|
+
ports.render();
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Offer the levels a route advertises, after the route is already in force.
|
|
176
|
+
*
|
|
177
|
+
* Cancelling the list is a real choice — the reader keeps the model with the
|
|
178
|
+
* provider's own default — which is why the route is applied first. The list
|
|
179
|
+
* is read before the picker opens because the rows are the route's own
|
|
180
|
+
* metadata; a menu painted before that arrived could offer a level the
|
|
181
|
+
* request would then be refused for.
|
|
182
|
+
*/
|
|
183
|
+
const offerRouteEfforts = async (route) => {
|
|
184
|
+
if (catalog === undefined)
|
|
185
|
+
return;
|
|
186
|
+
try {
|
|
187
|
+
const info = await catalog.efforts(route.provider, route.model);
|
|
188
|
+
const efforts = info?.efforts ?? [];
|
|
189
|
+
if (efforts.length === 0)
|
|
190
|
+
return;
|
|
191
|
+
const current = effectiveRoute();
|
|
192
|
+
const effective = current !== undefined && current.provider === route.provider && current.model === route.model
|
|
193
|
+
? current.reasoningEffort
|
|
194
|
+
: undefined;
|
|
195
|
+
const picked = await ports.openPicker(new EffortPicker(() => effortChoices(efforts, effective), `reasoning effort · ${route.provider}/${route.model}`, ports.keymap));
|
|
196
|
+
if (picked !== undefined)
|
|
197
|
+
applyEffort(route.provider, route.model, picked);
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
ports.notice(`could not read reasoning efforts: ${error instanceof Error ? error.message : String(error)}`);
|
|
201
|
+
}
|
|
202
|
+
ports.render();
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* Offer every model the configured routes advertise.
|
|
206
|
+
*
|
|
207
|
+
* Rows come from the routes the llm service registered — the providers this
|
|
208
|
+
* deployment configured — and each provider's models join the open list as
|
|
209
|
+
* its catalog resolves, so the picker is filterable before the slowest
|
|
210
|
+
* adapter answers. A route whose catalog cannot be read stays reachable by
|
|
211
|
+
* name through the text form; a notice explains why its rows are missing.
|
|
212
|
+
*/
|
|
213
|
+
const openModelPicker = async (providers) => {
|
|
214
|
+
if (catalog === undefined) {
|
|
215
|
+
ports.notice('this profile has no llm service, so models cannot be listed or switched');
|
|
216
|
+
ports.render();
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (providers.length === 0) {
|
|
220
|
+
ports.notice('no provider is configured; add one before choosing a model');
|
|
221
|
+
ports.render();
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (openingModels)
|
|
225
|
+
return;
|
|
226
|
+
openingModels = true;
|
|
227
|
+
try {
|
|
228
|
+
const routes = [];
|
|
229
|
+
for (const provider of providers) {
|
|
230
|
+
void catalog.models(provider.id).then(entries => {
|
|
231
|
+
if (entries.length === 0)
|
|
232
|
+
return;
|
|
233
|
+
routes.push(...entries.map(entry => ({ provider: provider.id, model: entry.id, name: entry.name })));
|
|
234
|
+
ports.render();
|
|
235
|
+
}).catch(() => {
|
|
236
|
+
ports.notice(`${stripControlCharacters(provider.id)}: ${MODEL_DISCOVERY_FAILURE}`);
|
|
237
|
+
ports.render();
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
const picked = await ports.openPicker(new ModelPicker(() => routes, effectiveRoute, ports.keymap));
|
|
241
|
+
if (picked === undefined)
|
|
242
|
+
return;
|
|
243
|
+
const route = readModelRouteKey(picked);
|
|
244
|
+
if (route === undefined)
|
|
245
|
+
return;
|
|
246
|
+
await applyRoute(route);
|
|
247
|
+
await offerRouteEfforts(route);
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
openingModels = false;
|
|
251
|
+
ports.render();
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* Offer the efforts the route in force advertises.
|
|
256
|
+
*
|
|
257
|
+
* The list is read before the picker opens because the rows are the route's
|
|
258
|
+
* own metadata; a menu painted before that arrived could offer a level the
|
|
259
|
+
* request would then be refused for.
|
|
260
|
+
*/
|
|
261
|
+
const openEffortPicker = async () => {
|
|
262
|
+
if (catalog === undefined) {
|
|
263
|
+
ports.notice('this profile has no llm service, so reasoning efforts cannot be read');
|
|
264
|
+
ports.render();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const facts = ports.statusFacts();
|
|
268
|
+
if (facts.provider === undefined || facts.model === undefined) {
|
|
269
|
+
ports.notice('no model route is in use; /model <provider>/<model> picks one first');
|
|
270
|
+
ports.render();
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (openingEfforts)
|
|
274
|
+
return;
|
|
275
|
+
openingEfforts = true;
|
|
276
|
+
try {
|
|
277
|
+
const info = await catalog.efforts(facts.provider, facts.model);
|
|
278
|
+
const efforts = info?.efforts ?? [];
|
|
279
|
+
if (efforts.length === 0) {
|
|
280
|
+
ports.notice(`${facts.provider}/${facts.model} advertises no reasoning efforts`);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const picked = await ports.openPicker(new EffortPicker(() => effortChoices(efforts, facts.effort), `reasoning effort · ${facts.provider}/${facts.model}`, ports.keymap));
|
|
284
|
+
if (picked !== undefined)
|
|
285
|
+
applyEffort(facts.provider, facts.model, picked);
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
ports.notice(`could not read reasoning efforts: ${error instanceof Error ? error.message : String(error)}`);
|
|
289
|
+
}
|
|
290
|
+
finally {
|
|
291
|
+
openingEfforts = false;
|
|
292
|
+
ports.render();
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
/**
|
|
296
|
+
* Put the deployment default in force before the first turn.
|
|
297
|
+
*
|
|
298
|
+
* The agent is created before the settings file has been read, so the route
|
|
299
|
+
* its loop captured is the composition placeholder; the reader's default —
|
|
300
|
+
* effort included — only exists by the time they can type. Adopting it here
|
|
301
|
+
* is what makes the status line's route the one the request actually uses.
|
|
302
|
+
*/
|
|
303
|
+
const adoptDefault = () => {
|
|
304
|
+
if (modelSwitch.current() !== undefined)
|
|
305
|
+
return;
|
|
306
|
+
const facts = ports.statusFacts();
|
|
307
|
+
if (facts.provider === undefined || facts.model === undefined)
|
|
308
|
+
return;
|
|
309
|
+
modelSwitch.adopt({
|
|
310
|
+
provider: facts.provider,
|
|
311
|
+
model: facts.model,
|
|
312
|
+
...(facts.effort === undefined ? {} : { reasoningEffort: facts.effort }),
|
|
313
|
+
});
|
|
314
|
+
};
|
|
315
|
+
return {
|
|
316
|
+
current: () => modelSwitch.current(),
|
|
317
|
+
setup: agentCtx => modelSwitch.install(agentCtx),
|
|
318
|
+
adoptDefault,
|
|
319
|
+
runModelCommand,
|
|
320
|
+
openEffortPicker: () => {
|
|
321
|
+
void openEffortPicker();
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
//# sourceMappingURL=model-choice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-choice.js","sourceRoot":"","sources":["../../src/surface/model-choice.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
2
|
+
import type { ForkInheritance, TuiAgent } from '../agent/host.ts';
|
|
3
|
+
import { type PresetRoster } from '../agent/presets.ts';
|
|
4
|
+
import type { Keymap } from '../input/actions.ts';
|
|
5
|
+
import type { Picker } from './modal-input.ts';
|
|
6
|
+
/**
|
|
7
|
+
* What the mode owner needs from the surface that composes it.
|
|
8
|
+
*
|
|
9
|
+
* The roster arrives as a handle because the open path mounts through it as
|
|
10
|
+
* well, and the stored mode is a property of a log this surface only reads. The
|
|
11
|
+
* screen, the keyboard, the notice, and the session the reader is watching
|
|
12
|
+
* belong to the surface that owns them; the keys move with a settings edit, so
|
|
13
|
+
* they are read per press.
|
|
14
|
+
*/
|
|
15
|
+
export interface PresetChoicePorts {
|
|
16
|
+
readonly agentPresets: PresetRoster | undefined;
|
|
17
|
+
/** The mode named on the command line, which is the only one that may conflict. */
|
|
18
|
+
readonly requestedPreset: string | undefined;
|
|
19
|
+
/** The mode a stored session's own log recorded, absent when it recorded none. */
|
|
20
|
+
readonly storedPreset: (id: SessionId) => Promise<string | undefined>;
|
|
21
|
+
/** The mode a live session runs right now, which only its own projection knows. */
|
|
22
|
+
readonly livePreset: (id: SessionId) => string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* The agent this terminal drives, read at call time.
|
|
25
|
+
*
|
|
26
|
+
* Opening a session replaces it, so a command typed after that switch has to
|
|
27
|
+
* reach the agent now on screen rather than the one it replaced.
|
|
28
|
+
*/
|
|
29
|
+
readonly drivingAgent: () => TuiAgent | undefined;
|
|
30
|
+
readonly keymap: () => Keymap;
|
|
31
|
+
/** Take the keyboard for a list and answer with the pick id it settled on. */
|
|
32
|
+
readonly openPicker: (picker: Picker) => Promise<string | undefined>;
|
|
33
|
+
readonly notice: (message: string) => void;
|
|
34
|
+
readonly render: () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Show the session this terminal drives again.
|
|
37
|
+
*
|
|
38
|
+
* Navigation belongs to the surface that owns the view, so the mode owner only
|
|
39
|
+
* decides when a switch needs the reader looking at the session it landed on.
|
|
40
|
+
*/
|
|
41
|
+
readonly returnToDrivenSession: () => Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
/** The launch a run was started for, as the mode it named has to be read. */
|
|
44
|
+
export interface PresetLaunch {
|
|
45
|
+
/** The session this run opens. */
|
|
46
|
+
readonly sessionId: SessionId;
|
|
47
|
+
readonly resume: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Whether a bare `--resume` still has to ask which session to open.
|
|
50
|
+
*
|
|
51
|
+
* The mode a stored session recorded can only be compared with the run's own
|
|
52
|
+
* flag once that pick lands, so the conflict waits for the chosen session.
|
|
53
|
+
*/
|
|
54
|
+
readonly resumePicker: boolean;
|
|
55
|
+
}
|
|
56
|
+
/** The reads and operations the composing surface routes to the mode owner. */
|
|
57
|
+
export interface PresetChoice {
|
|
58
|
+
/** The mode one agent joins. */
|
|
59
|
+
readonly presetFor: (id: SessionId, resume: boolean, fork: ForkInheritance | undefined) => Promise<string | undefined>;
|
|
60
|
+
/** Resolve the named mode and refuse a launch that cannot run it. */
|
|
61
|
+
readonly validateLaunch: (launch: PresetLaunch) => Promise<void>;
|
|
62
|
+
/** Show or choose the mode this session runs. */
|
|
63
|
+
readonly runPresetCommand: (argument: string) => void;
|
|
64
|
+
/** The mode a session starting now would take. */
|
|
65
|
+
readonly currentSeat: () => string | undefined;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Which mode a session runs — its seat in the roster — and the two ways it
|
|
69
|
+
* changes.
|
|
70
|
+
*
|
|
71
|
+
* The seat is one value for the whole run: a launch flag seeds it and a
|
|
72
|
+
* successful switch updates it, so `/new` and `/fork` land in the mode the
|
|
73
|
+
* reader last chose. A resumed session keeps the mode its own log recorded,
|
|
74
|
+
* because swapping it would leave logged tool calls the new composition cannot
|
|
75
|
+
* make — the same reason the harness refuses a switch once a turn has run.
|
|
76
|
+
*/
|
|
77
|
+
export declare function createPresetChoice(ports: PresetChoicePorts): PresetChoice;
|
|
78
|
+
//# sourceMappingURL=preset-choice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preset-choice.d.ts","sourceRoot":"","sources":["../../src/surface/preset-choice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AACjE,OAAO,EAAuB,KAAK,YAAY,EAAsB,MAAM,qBAAqB,CAAA;AAChG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAEjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAE9C;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,YAAY,EAAE,YAAY,GAAG,SAAS,CAAA;IAC/C,mFAAmF;IACnF,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5C,kFAAkF;IAClF,QAAQ,CAAC,YAAY,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACrE,mFAAmF;IACnF,QAAQ,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,MAAM,GAAG,SAAS,CAAA;IAC1D;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,QAAQ,GAAG,SAAS,CAAA;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,CAAA;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACpE,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAA;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,qBAAqB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACpD;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;CAC/B;AAED,+EAA+E;AAC/E,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,GAAG,SAAS,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACtH,qEAAqE;IACrE,QAAQ,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAChE,iDAAiD;IACjD,QAAQ,CAAC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACrD,kDAAkD;IAClD,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;CAC/C;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAyJzE"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { parsePresetArgument } from "../agent/presets.js";
|
|
2
|
+
import { PresetPicker } from "../ui/picker.js";
|
|
3
|
+
/**
|
|
4
|
+
* Which mode a session runs — its seat in the roster — and the two ways it
|
|
5
|
+
* changes.
|
|
6
|
+
*
|
|
7
|
+
* The seat is one value for the whole run: a launch flag seeds it and a
|
|
8
|
+
* successful switch updates it, so `/new` and `/fork` land in the mode the
|
|
9
|
+
* reader last chose. A resumed session keeps the mode its own log recorded,
|
|
10
|
+
* because swapping it would leave logged tool calls the new composition cannot
|
|
11
|
+
* make — the same reason the harness refuses a switch once a turn has run.
|
|
12
|
+
*/
|
|
13
|
+
export function createPresetChoice(ports) {
|
|
14
|
+
const requestedPreset = ports.requestedPreset;
|
|
15
|
+
/**
|
|
16
|
+
* The mode a session the reader starts from here on joins.
|
|
17
|
+
*
|
|
18
|
+
* A launch flag seeds it and a successful switch updates it, so `/new` and
|
|
19
|
+
* `/fork` land in the mode the reader last chose; nothing is written to
|
|
20
|
+
* settings, because the mode of a session is not a property of the machine.
|
|
21
|
+
* Unset means nobody chose, which is where the roster's default applies.
|
|
22
|
+
*/
|
|
23
|
+
let seat = requestedPreset;
|
|
24
|
+
/**
|
|
25
|
+
* The mode a session takes its seat in: the reader's latest choice, or the
|
|
26
|
+
* roster's default read at this moment.
|
|
27
|
+
*
|
|
28
|
+
* The default cannot be captured when this row applies: it comes from the
|
|
29
|
+
* settings document, which may be read after that, so a captured copy would
|
|
30
|
+
* pin every later session to the mode the bundle happened to ship.
|
|
31
|
+
*/
|
|
32
|
+
const seatMode = () => seat ?? ports.agentPresets?.defaultId;
|
|
33
|
+
/** The roster as the picker paints it, refreshed when the picker opens. */
|
|
34
|
+
let presetRows = [];
|
|
35
|
+
/** Choose the mode a session that has not started yet will run. */
|
|
36
|
+
const askForPreset = async (currentId) => {
|
|
37
|
+
const roster = ports.agentPresets;
|
|
38
|
+
if (roster === undefined)
|
|
39
|
+
return undefined;
|
|
40
|
+
presetRows = await roster.list();
|
|
41
|
+
return await ports.openPicker(new PresetPicker(() => presetRows, () => currentId, ports.keymap));
|
|
42
|
+
};
|
|
43
|
+
/** The stored mode's roster row, or undefined when the roster no longer offers it. */
|
|
44
|
+
const resolveStored = async (id, stored) => {
|
|
45
|
+
try {
|
|
46
|
+
return (await ports.agentPresets?.resolve(stored))?.id;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* The mode one agent joins.
|
|
54
|
+
*
|
|
55
|
+
* A resumed session keeps the composition its own log recorded, because
|
|
56
|
+
* swapping it would leave logged tool calls the new composition cannot make —
|
|
57
|
+
* the same reason the harness refuses a switch once a turn has run. A session
|
|
58
|
+
* that recorded none, which is every session written before modes existed,
|
|
59
|
+
* takes the seat; a branch inherits the mode its parent is running.
|
|
60
|
+
*/
|
|
61
|
+
const presetFor = async (id, resume, fork) => {
|
|
62
|
+
const roster = ports.agentPresets;
|
|
63
|
+
if (roster === undefined)
|
|
64
|
+
return undefined;
|
|
65
|
+
if (fork !== undefined)
|
|
66
|
+
return ports.livePreset(fork.from) ?? seatMode();
|
|
67
|
+
if (!resume)
|
|
68
|
+
return seatMode();
|
|
69
|
+
const stored = await ports.storedPreset(id);
|
|
70
|
+
if (stored === undefined)
|
|
71
|
+
return seatMode();
|
|
72
|
+
const resolvedStored = await resolveStored(id, stored);
|
|
73
|
+
if (resolvedStored === undefined) {
|
|
74
|
+
// The composition this session recorded is gone. Naming one explicitly is
|
|
75
|
+
// the reader's only way forward, so that is the one case an override is
|
|
76
|
+
// taken for a stored session.
|
|
77
|
+
if (requestedPreset !== undefined)
|
|
78
|
+
return (await roster.resolve(requestedPreset)).id;
|
|
79
|
+
throw new Error(`session ${id} runs mode "${stored}", which this roster no longer offers; name another with --preset`);
|
|
80
|
+
}
|
|
81
|
+
if (requestedPreset !== undefined && requestedPreset !== resolvedStored) {
|
|
82
|
+
throw new Error(`session ${id} runs mode "${resolvedStored}", so --preset ${requestedPreset} does not apply; /preset ${requestedPreset} switches it before its first turn`);
|
|
83
|
+
}
|
|
84
|
+
return resolvedStored;
|
|
85
|
+
};
|
|
86
|
+
/** Join this session to another mode and remember it for the next session. */
|
|
87
|
+
const applyPreset = async (id) => {
|
|
88
|
+
const roster = ports.agentPresets;
|
|
89
|
+
const agent = ports.drivingAgent();
|
|
90
|
+
if (roster === undefined || agent === undefined)
|
|
91
|
+
return;
|
|
92
|
+
try {
|
|
93
|
+
const chosen = await roster.select(agent.agent, id);
|
|
94
|
+
seat = chosen;
|
|
95
|
+
// The durable selection is folded as a marker on the session it belongs
|
|
96
|
+
// to, so a reader watching a child has to come back to see it.
|
|
97
|
+
await ports.returnToDrivenSession();
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
ports.notice(`could not switch the mode: ${error instanceof Error ? error.message : String(error)}`);
|
|
101
|
+
}
|
|
102
|
+
ports.render();
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Show or choose the mode this session runs.
|
|
106
|
+
*
|
|
107
|
+
* The mode decides which tools, prompt sections, and skills exist at all, so
|
|
108
|
+
* it is fixed once a turn has run: the harness refuses the swap and this
|
|
109
|
+
* surface explains why rather than pretending otherwise. Before the first
|
|
110
|
+
* turn the switch is recorded in the log, which is what keeps the transcript
|
|
111
|
+
* honest about the composition later turns ran under.
|
|
112
|
+
*/
|
|
113
|
+
const runPresetCommand = (argument) => {
|
|
114
|
+
const roster = ports.agentPresets;
|
|
115
|
+
if (roster === undefined) {
|
|
116
|
+
ports.notice('this profile has no agent roster, so there is no mode to choose');
|
|
117
|
+
ports.render();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const agent = ports.drivingAgent();
|
|
121
|
+
if (agent === undefined) {
|
|
122
|
+
ports.notice('the agent is still starting; try again in a moment');
|
|
123
|
+
ports.render();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const session = agent.agent.session;
|
|
127
|
+
const current = roster.current(session);
|
|
128
|
+
const command = parsePresetArgument(argument);
|
|
129
|
+
if (command.kind === 'pick') {
|
|
130
|
+
if (roster.started(session)) {
|
|
131
|
+
ports.notice(`this session runs ${current === undefined ? 'a mode' : `"${current}"`} and has already started, so its mode is fixed — /new starts a fresh session`);
|
|
132
|
+
ports.render();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
void askForPreset(current).then(picked => picked === undefined ? undefined : applyPreset(picked));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
void applyPreset(command.id);
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Resolve the mode named on the command line and refuse a launch that cannot
|
|
142
|
+
* run it.
|
|
143
|
+
*
|
|
144
|
+
* Raised while the launcher still owns the terminal, because the alternate
|
|
145
|
+
* screen closes over whatever was painted on it: a mode this roster does not
|
|
146
|
+
* offer has to be answered here rather than as a blank screen.
|
|
147
|
+
*/
|
|
148
|
+
const validateLaunch = async (launch) => {
|
|
149
|
+
const roster = ports.agentPresets;
|
|
150
|
+
if (requestedPreset !== undefined && roster !== undefined) {
|
|
151
|
+
seat = (await roster.resolve(requestedPreset)).id;
|
|
152
|
+
}
|
|
153
|
+
if (!launch.resumePicker)
|
|
154
|
+
await presetFor(launch.sessionId, launch.resume, undefined);
|
|
155
|
+
};
|
|
156
|
+
return {
|
|
157
|
+
presetFor,
|
|
158
|
+
validateLaunch,
|
|
159
|
+
runPresetCommand,
|
|
160
|
+
currentSeat: seatMode,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=preset-choice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preset-choice.js","sourceRoot":"","sources":["../../src/surface/preset-choice.ts"],"names":[],"mappings":"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"}
|