@aiwayds/dsh-tui-pi 0.26.0 → 0.27.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/README.md +2 -0
- package/README.zh-CN.md +2 -0
- package/lib/index.js +39 -1
- package/lib/index.js.map +1 -1
- package/lib/model-profiles.d.ts +117 -0
- package/lib/model-profiles.js +291 -0
- package/lib/model-profiles.js.map +1 -0
- package/lib/profile.d.ts +45 -0
- package/lib/profile.js +591 -0
- package/lib/profile.js.map +1 -0
- package/lib/selectors.d.ts +8 -1
- package/lib/selectors.js +29 -7
- package/lib/selectors.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User model profiles — named snapshots of the whole model configuration
|
|
3
|
+
* (default model + think level, plus per-subagent model/thinking) that can
|
|
4
|
+
* be saved, reviewed and applied in one step, so switching between contexts
|
|
5
|
+
* (work ↔ personal) is a single command instead of a /model + per-agent
|
|
6
|
+
* /agents tour.
|
|
7
|
+
*
|
|
8
|
+
* Storage: `$DSH_HOME/model-profiles.json` — a small JSON document the TUI
|
|
9
|
+
* owns outright (same model as tui-command-usage.json, src/usage.ts). Reads
|
|
10
|
+
* never throw: a missing, corrupt or wrong-version file degrades to the
|
|
11
|
+
* seeded default document (work / personal / other, empty until configured).
|
|
12
|
+
* Writes are atomic (tmp sibling + rename) and whole-document
|
|
13
|
+
* last-write-wins — the accepted loss model for a human-paced UI feature
|
|
14
|
+
* (same as settings.yaml).
|
|
15
|
+
*
|
|
16
|
+
* Snapshot semantics — the part to keep straight:
|
|
17
|
+
* - `profile.agents[name]` PRESENT → applying writes that agent's
|
|
18
|
+
* frontmatter model/thinking to exactly the recorded values (absent keys
|
|
19
|
+
* CLEAR the line — explicit inherit).
|
|
20
|
+
* - `profile.agents[name]` ABSENT → applying leaves the agent untouched
|
|
21
|
+
* (an agent file created after the last save — the profile never knew it).
|
|
22
|
+
* - "Save current" records EVERY discovered agent, inherit ones as empty
|
|
23
|
+
* entries, so a round-trip switch restores inherit where inherit was.
|
|
24
|
+
*/
|
|
25
|
+
import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
26
|
+
import { dirname, join } from 'node:path';
|
|
27
|
+
import { dshHome } from "./append-system.js";
|
|
28
|
+
/** On-disk schema version; bump only for breaking changes. */
|
|
29
|
+
export const MODEL_PROFILES_VERSION = 1;
|
|
30
|
+
/** Profiles seeded into a fresh document (and re-seeded when the stored one is empty). */
|
|
31
|
+
export const DEFAULT_PROFILE_NAMES = ['work', 'personal', 'other'];
|
|
32
|
+
/** `$DSH_HOME/model-profiles.json` (or an explicit home override). */
|
|
33
|
+
export function modelProfilesPath(home = dshHome()) {
|
|
34
|
+
return join(home, 'model-profiles.json');
|
|
35
|
+
}
|
|
36
|
+
/** Narrow an unknown JSON value into a route; anything else is dropped. */
|
|
37
|
+
function narrowRoute(value) {
|
|
38
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
39
|
+
return undefined;
|
|
40
|
+
const { provider, model, reasoningEffort } = value;
|
|
41
|
+
if (typeof provider !== 'string' || provider === '')
|
|
42
|
+
return undefined;
|
|
43
|
+
if (typeof model !== 'string' || model === '')
|
|
44
|
+
return undefined;
|
|
45
|
+
const route = { provider, model };
|
|
46
|
+
if (typeof reasoningEffort === 'string' && reasoningEffort !== '')
|
|
47
|
+
route.reasoningEffort = reasoningEffort;
|
|
48
|
+
return route;
|
|
49
|
+
}
|
|
50
|
+
/** Narrow one agents-map value; `undefined` drops the entry, `{}` keeps it. */
|
|
51
|
+
function narrowEntry(value) {
|
|
52
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
53
|
+
return undefined;
|
|
54
|
+
const { model, thinking } = value;
|
|
55
|
+
const entry = {};
|
|
56
|
+
if (typeof model === 'string' && model !== '')
|
|
57
|
+
entry.model = model;
|
|
58
|
+
if (typeof thinking === 'string' && thinking !== '')
|
|
59
|
+
entry.thinking = thinking;
|
|
60
|
+
return entry;
|
|
61
|
+
}
|
|
62
|
+
/** Narrow one profile; a missing/invalid name drops the whole profile. */
|
|
63
|
+
function narrowProfile(value) {
|
|
64
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
65
|
+
return undefined;
|
|
66
|
+
const { name, defaultModel, agents } = value;
|
|
67
|
+
if (typeof name !== 'string' || name.trim() === '')
|
|
68
|
+
return undefined;
|
|
69
|
+
const profile = { name: name.trim(), agents: {} };
|
|
70
|
+
const route = narrowRoute(defaultModel);
|
|
71
|
+
if (route !== undefined)
|
|
72
|
+
profile.defaultModel = route;
|
|
73
|
+
if (agents !== null && typeof agents === 'object' && !Array.isArray(agents)) {
|
|
74
|
+
for (const [agentName, entry] of Object.entries(agents)) {
|
|
75
|
+
const key = agentName.trim();
|
|
76
|
+
if (key === '')
|
|
77
|
+
continue;
|
|
78
|
+
const narrowed = narrowEntry(entry);
|
|
79
|
+
if (narrowed !== undefined)
|
|
80
|
+
profile.agents[key] = narrowed;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return profile;
|
|
84
|
+
}
|
|
85
|
+
/** A fresh document with the three seeded, unconfigured default profiles. */
|
|
86
|
+
export function seedModelProfilesDoc() {
|
|
87
|
+
return { profiles: DEFAULT_PROFILE_NAMES.map(name => ({ name, agents: {} })) };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Validate an unknown parsed document. A wrong version, a non-object or an
|
|
91
|
+
* empty/invalid profiles array degrades to the seeded defaults — the store
|
|
92
|
+
* is self-healing, never fatal. Duplicate names (case-insensitive) keep the
|
|
93
|
+
* first occurrence; a `current` pointing at a dropped profile is unset.
|
|
94
|
+
*/
|
|
95
|
+
export function normalizeModelProfiles(raw) {
|
|
96
|
+
const doc = seedModelProfilesDoc();
|
|
97
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw))
|
|
98
|
+
return doc;
|
|
99
|
+
const { version, current, profiles } = raw;
|
|
100
|
+
if (version !== MODEL_PROFILES_VERSION)
|
|
101
|
+
return doc;
|
|
102
|
+
const narrowed = [];
|
|
103
|
+
const seen = new Set();
|
|
104
|
+
if (Array.isArray(profiles)) {
|
|
105
|
+
for (const value of profiles) {
|
|
106
|
+
const profile = narrowProfile(value);
|
|
107
|
+
if (profile === undefined)
|
|
108
|
+
continue;
|
|
109
|
+
const key = profile.name.toLowerCase();
|
|
110
|
+
if (seen.has(key))
|
|
111
|
+
continue;
|
|
112
|
+
seen.add(key);
|
|
113
|
+
narrowed.push(profile);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (narrowed.length === 0)
|
|
117
|
+
return doc;
|
|
118
|
+
doc.profiles = narrowed;
|
|
119
|
+
if (typeof current === 'string' && narrowed.some(profile => profile.name === current)) {
|
|
120
|
+
doc.current = current;
|
|
121
|
+
}
|
|
122
|
+
return doc;
|
|
123
|
+
}
|
|
124
|
+
/** Read + validate the store; any failure degrades to the seeded document. */
|
|
125
|
+
export function loadModelProfiles(path) {
|
|
126
|
+
let text;
|
|
127
|
+
try {
|
|
128
|
+
text = readFileSync(path, 'utf8');
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return seedModelProfilesDoc();
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
return normalizeModelProfiles(JSON.parse(text));
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return seedModelProfilesDoc();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Atomically persist the document (tmp sibling + rename). Creates the
|
|
142
|
+
* directory when missing. Resolves an error message on failure, or
|
|
143
|
+
* `undefined` on success — callers flash it, never throw.
|
|
144
|
+
*/
|
|
145
|
+
export function saveModelProfiles(path, doc) {
|
|
146
|
+
const body = JSON.stringify({
|
|
147
|
+
version: MODEL_PROFILES_VERSION,
|
|
148
|
+
current: doc.current,
|
|
149
|
+
profiles: doc.profiles,
|
|
150
|
+
});
|
|
151
|
+
const dir = dirname(path);
|
|
152
|
+
const base = path.split('/').pop() ?? 'model-profiles.json';
|
|
153
|
+
const tmp = join(dir, `.${base}.tmp-${process.pid}`);
|
|
154
|
+
try {
|
|
155
|
+
mkdirSync(dir, { recursive: true });
|
|
156
|
+
writeFileSync(tmp, body);
|
|
157
|
+
renameSync(tmp, path);
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
try {
|
|
162
|
+
rmSync(tmp, { force: true });
|
|
163
|
+
}
|
|
164
|
+
catch { /* best-effort cleanup of the failed tmp sibling */ }
|
|
165
|
+
return error instanceof Error ? error.message : String(error);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/** Find a profile by (case-insensitive) name. */
|
|
169
|
+
export function findProfile(doc, name) {
|
|
170
|
+
const needle = name.trim().toLowerCase();
|
|
171
|
+
return doc.profiles.find(profile => profile.name.toLowerCase() === needle);
|
|
172
|
+
}
|
|
173
|
+
/** Trim one candidate profile name; empty (or whitespace-only) is invalid. */
|
|
174
|
+
export function normalizeProfileName(name) {
|
|
175
|
+
const trimmed = name.trim();
|
|
176
|
+
return trimmed === '' ? undefined : trimmed;
|
|
177
|
+
}
|
|
178
|
+
/** Create a new empty profile; the name must be valid and not taken. */
|
|
179
|
+
export function createProfile(doc, rawName) {
|
|
180
|
+
const name = normalizeProfileName(rawName);
|
|
181
|
+
if (name === undefined)
|
|
182
|
+
return { error: 'profile name must not be empty' };
|
|
183
|
+
if (findProfile(doc, name) !== undefined)
|
|
184
|
+
return { error: `a profile named "${name}" already exists` };
|
|
185
|
+
const profile = { name, agents: {} };
|
|
186
|
+
doc.profiles.push(profile);
|
|
187
|
+
return { profile };
|
|
188
|
+
}
|
|
189
|
+
/** Rename a profile in place, keeping `current` consistent. Error or undefined. */
|
|
190
|
+
export function renameProfile(doc, from, to) {
|
|
191
|
+
const profile = findProfile(doc, from);
|
|
192
|
+
if (profile === undefined)
|
|
193
|
+
return `no profile named "${from}"`;
|
|
194
|
+
const name = normalizeProfileName(to);
|
|
195
|
+
if (name === undefined)
|
|
196
|
+
return 'profile name must not be empty';
|
|
197
|
+
if (name.toLowerCase() !== profile.name.toLowerCase() && findProfile(doc, name) !== undefined) {
|
|
198
|
+
return `a profile named "${name}" already exists`;
|
|
199
|
+
}
|
|
200
|
+
if (doc.current === profile.name)
|
|
201
|
+
doc.current = name;
|
|
202
|
+
profile.name = name;
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
/** Delete a profile; the last remaining one is refused (the store never goes empty). */
|
|
206
|
+
export function deleteProfile(doc, name) {
|
|
207
|
+
const index = doc.profiles.findIndex(profile => profile.name.toLowerCase() === name.trim().toLowerCase());
|
|
208
|
+
if (index < 0)
|
|
209
|
+
return `no profile named "${name}"`;
|
|
210
|
+
if (doc.profiles.length <= 1)
|
|
211
|
+
return 'the last profile cannot be deleted';
|
|
212
|
+
const [removed] = doc.profiles.splice(index, 1);
|
|
213
|
+
if (doc.current === removed.name)
|
|
214
|
+
doc.current = undefined;
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Record every discovered agent's model/thinking into a fresh agents map —
|
|
219
|
+
* the "save current" capture. Inherit agents become EMPTY entries so the
|
|
220
|
+
* snapshot is complete: applying it later restores inherit where inherit
|
|
221
|
+
* was (see the module header's snapshot semantics).
|
|
222
|
+
*/
|
|
223
|
+
export function captureAgentsSnapshot(agents) {
|
|
224
|
+
const snapshot = {};
|
|
225
|
+
for (const agent of agents) {
|
|
226
|
+
snapshot[agent.meta.name] = {
|
|
227
|
+
...(agent.meta.model !== undefined ? { model: agent.meta.model } : {}),
|
|
228
|
+
...(agent.meta.thinking !== undefined ? { thinking: agent.meta.thinking } : {}),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
return snapshot;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* The frontmatter writes that apply `profile` onto the discovered `agents`:
|
|
235
|
+
* every agent LISTED in the profile gets exactly the recorded overrides
|
|
236
|
+
* (absent keys clear the line); agents absent from the profile are skipped
|
|
237
|
+
* — the profile never knew them, applying must not guess. The caller
|
|
238
|
+
* executes each plan through `updateAgentFrontmatter`.
|
|
239
|
+
*/
|
|
240
|
+
export function planAgentApply(profile, agents) {
|
|
241
|
+
const planned = [];
|
|
242
|
+
for (const agent of agents) {
|
|
243
|
+
const entry = profile.agents[agent.meta.name];
|
|
244
|
+
if (entry === undefined)
|
|
245
|
+
continue;
|
|
246
|
+
planned.push({
|
|
247
|
+
agent,
|
|
248
|
+
updates: {
|
|
249
|
+
model: entry.model ?? null,
|
|
250
|
+
thinking: entry.thinking ?? null,
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
return planned;
|
|
255
|
+
}
|
|
256
|
+
/** `provider/model · think high` label for a route; `fallback` when unset. */
|
|
257
|
+
export function formatProfileRoute(route, fallback = '(not set)') {
|
|
258
|
+
if (route === undefined)
|
|
259
|
+
return fallback;
|
|
260
|
+
const base = `${route.provider}/${route.model}`;
|
|
261
|
+
return route.reasoningEffort === undefined ? base : `${base} · think ${route.reasoningEffort}`;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* The full review dump of one profile (the `v` viewer): header, default
|
|
265
|
+
* model, then every discovered agent's recorded state — plus stale entries
|
|
266
|
+
* whose agent file no longer exists, marked so the user can prune them.
|
|
267
|
+
*/
|
|
268
|
+
export function profileReviewLines(profile, agents, isCurrent = false) {
|
|
269
|
+
const lines = [
|
|
270
|
+
`Profile: ${profile.name}${isCurrent ? ' · current' : ''}`,
|
|
271
|
+
`Default model: ${formatProfileRoute(profile.defaultModel)}`,
|
|
272
|
+
];
|
|
273
|
+
const discovered = new Set(agents.map(agent => agent.meta.name));
|
|
274
|
+
const rows = agents.map(agent => ({ name: agent.meta.name, entry: profile.agents[agent.meta.name], stale: false }));
|
|
275
|
+
for (const [name, entry] of Object.entries(profile.agents)) {
|
|
276
|
+
if (!discovered.has(name))
|
|
277
|
+
rows.push({ name, entry, stale: true });
|
|
278
|
+
}
|
|
279
|
+
if (rows.length === 0) {
|
|
280
|
+
lines.push('Agents: none recorded — pick models under /profile-cfg, or press s to save the current configuration');
|
|
281
|
+
return lines;
|
|
282
|
+
}
|
|
283
|
+
lines.push(`Agents (${String(rows.length)}):`);
|
|
284
|
+
for (const { name, entry, stale } of rows) {
|
|
285
|
+
const model = entry?.model ?? (entry === undefined ? '(not saved — apply leaves untouched)' : '(inherit)');
|
|
286
|
+
const think = entry?.thinking !== undefined ? `think ${entry.thinking}` : 'inherit';
|
|
287
|
+
lines.push(` ${name}${stale ? ' (file missing)' : ''} · ${model} · ${think}`);
|
|
288
|
+
}
|
|
289
|
+
return lines;
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=model-profiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-profiles.js","sourceRoot":"","sources":["../src/model-profiles.ts"],"names":[],"mappings":"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"}
|
package/lib/profile.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/profile-switch` + `/profile-cfg` — user model profiles: named snapshots
|
|
3
|
+
* of the whole model configuration (default model + think level, every
|
|
4
|
+
* subagent's model/thinking) that switch in one step between contexts like
|
|
5
|
+
* work and personal.
|
|
6
|
+
*
|
|
7
|
+
* Layers, all on the select-panel framework (src/panels.ts):
|
|
8
|
+
*
|
|
9
|
+
* 1. `/profile-switch` switcher (TablePanel) — one row per profile (name |
|
|
10
|
+
* default model | think | agents), Enter applies it to the live
|
|
11
|
+
* selection AND the agent markdown files, Esc backs out.
|
|
12
|
+
* 2. `/profile-cfg` manager (TablePanel) — the roster: n new, d delete
|
|
13
|
+
* (double-press confirm), Enter opens the profile's fields.
|
|
14
|
+
* 3. profile fields (FieldPanel) — model / think / agents rows plus the
|
|
15
|
+
* s save-current, r rename, v review shortcuts.
|
|
16
|
+
* 4. agents sub-table (TablePanel) — every discovered agent's recorded
|
|
17
|
+
* model/thinking; Enter picks through the SAME favorites/hidden model
|
|
18
|
+
* table /model uses (pickModel with the shared PanelHost), i sets
|
|
19
|
+
* explicit inherit, t edits think alone.
|
|
20
|
+
*
|
|
21
|
+
* Every edit persists to `$DSH_HOME/model-profiles.json` immediately
|
|
22
|
+
* (src/model-profiles.ts). Applying a profile writes the agent frontmatter
|
|
23
|
+
* files (updateAgentFrontmatter) and the default model through the same
|
|
24
|
+
* chain as /model: live bridge selection + persistDefaultModel.
|
|
25
|
+
*/
|
|
26
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
27
|
+
import type { ModelSelection } from '@deepseek-ai/dsh-agent';
|
|
28
|
+
import type { TUI } from '@earendil-works/pi-tui';
|
|
29
|
+
import { type TuiTheme } from './theme/index.ts';
|
|
30
|
+
/** Live-session handles the profile flows need (bridged in from index.ts). */
|
|
31
|
+
export interface ProfileDeps {
|
|
32
|
+
getSelection(): ModelSelection | undefined;
|
|
33
|
+
setSelection(selection: ModelSelection): void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Open the `/profile-switch` switcher. Resolves the apply summary when a profile
|
|
37
|
+
* was switched, or `undefined` when cancelled / nothing applied.
|
|
38
|
+
*/
|
|
39
|
+
export declare function openProfileSwitcher(ctx: Context, tui: TUI, theme: TuiTheme, deps: ProfileDeps, restoreFocus: () => void): Promise<string | undefined>;
|
|
40
|
+
/**
|
|
41
|
+
* Open the `/profile-cfg` manager. Resolves a summary when anything changed,
|
|
42
|
+
* or `undefined` when the manager closed untouched. `preselect` jumps
|
|
43
|
+
* straight into one profile's fields window.
|
|
44
|
+
*/
|
|
45
|
+
export declare function openProfileManager(ctx: Context, tui: TUI, theme: TuiTheme, deps: ProfileDeps, restoreFocus: () => void, preselect?: string): Promise<string | undefined>;
|