pi-hide-providers 0.1.4 → 0.1.5

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 CHANGED
@@ -30,7 +30,7 @@ Pi has `enabledModels` in `settings.json` as an allowlist, but maintaining it ma
30
30
  - The `/model` selector, `Ctrl+P` cycling, `--list-models`, and session restoration all see only visible models
31
31
  - `/hide-models reset` unpatches the registry — all models return immediately
32
32
  - Changes via `/hide-models add` and `/hide-models remove` take effect immediately (no reload needed)
33
- - Interactive `/hide-models` TUI lists visible providers/models first, re-sorting as you hide or show items — same ordering behavior as pi core's `/scoped-models`
33
+ - Interactive `/hide-models` TUI lists visible models first in user-toggle order, then hidden models in their original registry order, and keeps the cursor at the same index after each toggle — matching pi core's `/scoped-models` UX
34
34
  - `/hide-models` subcommands for adding, removing, and inspecting rules
35
35
 
36
36
  No `settings.json` is modified. No 250+ entry explosion. No allowlist semantics.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-hide-providers",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Hide providers and models from pi's model selector — filter the /model list and Ctrl+P cycling via a configurable blocklist",
5
5
  "type": "module",
6
6
  "author": "Tom X Nguyen",
@@ -61,6 +61,10 @@ export class HideProviderSelectorComponent implements Component {
61
61
  // model data
62
62
  private allItems: DisplayItem[] = [];
63
63
 
64
+ // visible model fullIds in the order they were unhidden (mirrors pi core's
65
+ // enabledIds cycle order in the scoped models selector)
66
+ private visibleIds: string[] = [];
67
+
64
68
  // current hide rules
65
69
  private hiddenRules: HideRule[] = [];
66
70
 
@@ -93,7 +97,7 @@ export class HideProviderSelectorComponent implements Component {
93
97
  this.done = done;
94
98
  this.hiddenRules = deduplicateRules(currentRules);
95
99
 
96
- // Build display items
100
+ // Build display items in the original registry order.
97
101
  for (const m of allModels) {
98
102
  this.allItems.push({
99
103
  fullId: `${m.provider}/${m.id}`,
@@ -103,9 +107,12 @@ export class HideProviderSelectorComponent implements Component {
103
107
  hidden: isHidden(currentRules, m.provider, m.id),
104
108
  });
105
109
  }
106
- // Enabled (visible) providers/models first, then alphabetical within each group
107
- this.sortItems(this.allItems);
108
- this.filteredItems = [...this.allItems];
110
+ // Track visible models in original order initially; toggle order changes
111
+ // during the session, matching pi core's /scoped-models behavior.
112
+ this.visibleIds = this.allItems
113
+ .filter((i) => !i.hidden)
114
+ .map((i) => i.fullId);
115
+ this.filteredItems = this.buildItems();
109
116
 
110
117
  this.searchInput = new Input();
111
118
  this.listContainer = new Container();
@@ -271,27 +278,24 @@ export class HideProviderSelectorComponent implements Component {
271
278
  private refresh(): void {
272
279
  const query = this.searchInput.getValue();
273
280
 
274
- // Recompute hidden status on the canonical full list first, then sort it.
275
- // This ensures both allItems and filteredItems stay ordered as enabled
276
- // (visible) models first, disabled (hidden) models second.
281
+ // Recompute hidden status, then rebuild the list in pi core's order:
282
+ // visible models in user-toggle order, followed by hidden models in
283
+ // original registry order.
277
284
  for (const item of this.allItems) {
278
285
  item.hidden = isHidden(this.hiddenRules, item.provider, item.modelId);
279
286
  }
280
- this.sortItems(this.allItems);
281
287
 
288
+ const items = this.buildItems();
282
289
  this.filteredItems = query
283
290
  ? fuzzyFilter(
284
- this.allItems,
291
+ items,
285
292
  query,
286
293
  (i) => `${i.provider} ${i.modelId} ${i.provider}/${i.modelId} ${i.modelName}`,
287
294
  )
288
- : [...this.allItems];
289
-
290
- // Ensure filtered results also honor enabled-first ordering.
291
- this.sortItems(this.filteredItems);
295
+ : items;
292
296
 
293
- // Keep the cursor at the same relative position after re-sorting. The
294
- // selected model may change, which matches pi's /scoped-models behavior.
297
+ // Keep the cursor at the same numeric index after re-sorting. The selected
298
+ // model may change, matching pi core's /scoped-models behavior.
295
299
  this.selectedIndex = Math.min(
296
300
  this.selectedIndex,
297
301
  Math.max(0, this.filteredItems.length - 1),
@@ -300,27 +304,30 @@ export class HideProviderSelectorComponent implements Component {
300
304
  this.updateList();
301
305
  }
302
306
 
303
- /** Sort items so enabled (visible) models come before disabled (hidden)
304
- * models, then alphabetically by provider and model id. Each model is ranked
305
- * individually — a single visible model in a provider does not pull the whole
306
- * provider to the top.
307
+ /** Build the display order used by pi core's scoped models selector:
308
+ * visible models first in the order they were unhidden, then hidden models
309
+ * in their original registry order.
307
310
  */
308
- private sortItems(items: DisplayItem[]): void {
309
- items.sort((a, b) => {
310
- // Visible models first, then hidden models.
311
- if (a.hidden !== b.hidden) {
312
- return a.hidden ? 1 : -1;
311
+ private buildItems(): DisplayItem[] {
312
+ const visibleSet = new Set(this.visibleIds);
313
+ const result: DisplayItem[] = [];
314
+
315
+ // Visible models in user-toggle order.
316
+ for (const fullId of this.visibleIds) {
317
+ const item = this.allItems.find((i) => i.fullId === fullId);
318
+ if (item && !item.hidden) {
319
+ result.push(item);
313
320
  }
321
+ }
314
322
 
315
- // Then alphabetical by provider.
316
- const providerCompare = a.provider.localeCompare(b.provider);
317
- if (providerCompare !== 0) {
318
- return providerCompare;
323
+ // Hidden models in original registry order.
324
+ for (const item of this.allItems) {
325
+ if (item.hidden && !visibleSet.has(item.fullId)) {
326
+ result.push(item);
319
327
  }
328
+ }
320
329
 
321
- // Then alphabetical by model id.
322
- return a.modelId.localeCompare(b.modelId);
323
- });
330
+ return result;
324
331
  }
325
332
 
326
333
  private updateList(): void {
@@ -433,12 +440,20 @@ export class HideProviderSelectorComponent implements Component {
433
440
  !(r.provider === item.provider && r.model === item.modelId),
434
441
  );
435
442
  }
443
+
444
+ // Newly visible model goes to the end of the visible order (pi core).
445
+ if (!this.visibleIds.includes(item.fullId)) {
446
+ this.visibleIds.push(item.fullId);
447
+ }
436
448
  } else {
437
449
  // Add a rule for this specific model
438
450
  this.hiddenRules = deduplicateRules([
439
451
  ...this.hiddenRules,
440
452
  { provider: item.provider, model: item.modelId },
441
453
  ]);
454
+
455
+ // Remove from the visible order.
456
+ this.visibleIds = this.visibleIds.filter((id) => id !== item.fullId);
442
457
  }
443
458
  this.hasChanges = true;
444
459
  this.refresh();
@@ -456,12 +471,25 @@ export class HideProviderSelectorComponent implements Component {
456
471
  this.hiddenRules = this.hiddenRules.filter(
457
472
  (r) => r.provider !== provider,
458
473
  );
474
+
475
+ // Append newly visible provider models to the end of the visible order
476
+ // in original registry order (pi core).
477
+ const providerIds = providerItems.map((i) => i.fullId);
478
+ this.visibleIds = [
479
+ ...this.visibleIds,
480
+ ...providerIds.filter((id) => !this.visibleIds.includes(id)),
481
+ ];
459
482
  } else {
460
483
  // Hide all — add a single provider-level rule
461
484
  this.hiddenRules = deduplicateRules([
462
485
  ...this.hiddenRules,
463
486
  { provider },
464
487
  ]);
488
+
489
+ // Remove provider models from the visible order.
490
+ this.visibleIds = this.visibleIds.filter(
491
+ (id) => !providerItems.some((i) => i.fullId === id),
492
+ );
465
493
  }
466
494
  this.hasChanges = true;
467
495
  this.refresh();
@@ -496,6 +524,10 @@ export class HideProviderSelectorComponent implements Component {
496
524
  }
497
525
  }
498
526
  }
527
+
528
+ // Remove hidden models from the visible order.
529
+ const hiddenFullIds = new Set(items.map((i) => i.fullId));
530
+ this.visibleIds = this.visibleIds.filter((id) => !hiddenFullIds.has(id));
499
531
  }
500
532
 
501
533
  /** Remove hide rules for the given items. */
@@ -548,6 +580,13 @@ export class HideProviderSelectorComponent implements Component {
548
580
  }
549
581
  }
550
582
  }
583
+
584
+ // Append newly visible models to the end of the visible order (pi core).
585
+ for (const item of items) {
586
+ if (!this.visibleIds.includes(item.fullId)) {
587
+ this.visibleIds.push(item.fullId);
588
+ }
589
+ }
551
590
  }
552
591
 
553
592
  /** Close and pass results to `done`. */