@d3ara1n/pi-command-palette 0.3.0 → 0.4.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/package.json +1 -1
- package/src/index.ts +54 -5
package/README.md
CHANGED
|
@@ -46,6 +46,8 @@ When a command replaces your current editor text, the original content is saved
|
|
|
46
46
|
|
|
47
47
|
The "Model: Switch Model" action opens a secondary overlay listing all models with configured API keys. Select one to switch instantly — no need to go through `/model` or `Ctrl+P`.
|
|
48
48
|
|
|
49
|
+
**Scoped models float to the top**, marked with a ★ (favorite) prefix. "Scoped" here means the same set pi uses for its built-in selector's scoped tab and `Ctrl+P` cycling — the `enabledModels` patterns in your `settings.json` (project `.pi/settings.json` overrides global `~/.pi/agent/settings.json`). Everything else follows alphabetically. If no scope is configured, the list is a plain alphabetical roster — nothing breaks.
|
|
50
|
+
|
|
49
51
|
## Configuration
|
|
50
52
|
|
|
51
53
|
The default shortcut is `Ctrl+Shift+P`. If it conflicts with your terminal, override it via either of the following (evaluated in order, first match wins).
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -13,7 +13,12 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
DynamicBorder,
|
|
18
|
+
getAgentDir,
|
|
19
|
+
resolveModelScopeWithDiagnostics,
|
|
20
|
+
SettingsManager,
|
|
21
|
+
} from "@earendil-works/pi-coding-agent";
|
|
17
22
|
import {
|
|
18
23
|
Container,
|
|
19
24
|
type SelectItem,
|
|
@@ -150,6 +155,36 @@ function buildPaletteItems(pi: ExtensionAPI, ctx: ExtensionContext): PaletteItem
|
|
|
150
155
|
|
|
151
156
|
// ── Model selector ─────────────────────────────────────────────────
|
|
152
157
|
|
|
158
|
+
const STAR = "★ ";
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Resolve the set of "scoped" model full-ids (`provider/id`) — the same models
|
|
162
|
+
* pi surfaces in its built-in selector's "scoped" tab and Ctrl+P cycling.
|
|
163
|
+
*
|
|
164
|
+
* Fully official-API driven, no manual settings parsing:
|
|
165
|
+
* - `SettingsManager.getEnabledModels()` reads the `enabledModels` scope
|
|
166
|
+
* patterns (global + project merge handled by pi).
|
|
167
|
+
* - `resolveModelScopeWithDiagnostics()` expands those patterns (globs, aliases,
|
|
168
|
+
* thinking-level suffixes) into concrete models — identical to pi's scope tab.
|
|
169
|
+
*
|
|
170
|
+
* Any failure degrades to an empty set: the selector still works, just without
|
|
171
|
+
* the scoped grouping.
|
|
172
|
+
*/
|
|
173
|
+
async function resolveScopedModelIds(
|
|
174
|
+
modelRegistry: ExtensionContext["modelRegistry"],
|
|
175
|
+
cwd: string,
|
|
176
|
+
): Promise<Set<string>> {
|
|
177
|
+
try {
|
|
178
|
+
const settings = SettingsManager.create(cwd, getAgentDir());
|
|
179
|
+
const patterns = settings.getEnabledModels();
|
|
180
|
+
if (!patterns || patterns.length === 0) return new Set();
|
|
181
|
+
const { scopedModels } = await resolveModelScopeWithDiagnostics(patterns, modelRegistry);
|
|
182
|
+
return new Set(scopedModels.map((s) => `${s.model.provider}/${s.model.id}`));
|
|
183
|
+
} catch {
|
|
184
|
+
return new Set();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
153
188
|
async function showModelSelector(pi: ExtensionAPI, ctx: ExtensionContext): Promise<void> {
|
|
154
189
|
let models: Awaited<ReturnType<typeof ctx.modelRegistry.getAvailable>>;
|
|
155
190
|
try {
|
|
@@ -164,10 +199,24 @@ async function showModelSelector(pi: ExtensionAPI, ctx: ExtensionContext): Promi
|
|
|
164
199
|
return;
|
|
165
200
|
}
|
|
166
201
|
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
202
|
+
const scopedIds = await resolveScopedModelIds(ctx.modelRegistry, ctx.cwd);
|
|
203
|
+
|
|
204
|
+
// Scoped models float to the top with a ★ prefix (favorites); the rest follow
|
|
205
|
+
// alphabetically. Within the scoped group we also sort alphabetically so the
|
|
206
|
+
// ordering is stable and predictable regardless of registry order.
|
|
207
|
+
const decorated = models.map((m) => {
|
|
208
|
+
const value = `${m.provider}/${m.id}`;
|
|
209
|
+
return { model: m, value, scoped: scopedIds.has(value) };
|
|
210
|
+
});
|
|
211
|
+
decorated.sort((a, b) => {
|
|
212
|
+
if (a.scoped !== b.scoped) return a.scoped ? -1 : 1;
|
|
213
|
+
return a.model.name.localeCompare(b.model.name);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const items: SelectItem[] = decorated.map((d) => ({
|
|
217
|
+
value: d.value,
|
|
218
|
+
label: d.scoped ? `${STAR}${d.model.name}` : d.model.name,
|
|
219
|
+
description: d.model.provider,
|
|
171
220
|
}));
|
|
172
221
|
|
|
173
222
|
const result = await ctx.ui.custom<string | null>(
|