pi-hide-providers 0.1.3 → 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,8 @@ 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` command — no-args opens the TUI selector; subcommands for adding, removing, and inspecting rules
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
+ - `/hide-models` subcommands for adding, removing, and inspecting rules
34
35
 
35
36
  No `settings.json` is modified. No 250+ entry explosion. No allowlist semantics.
36
37
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-hide-providers",
3
- "version": "0.1.3",
4
- "description": "Hide providers and models from pi's model selector \u2014 filter the /model list and Ctrl+P cycling via a configurable blocklist",
3
+ "version": "0.1.5",
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",
7
7
  "license": "MIT",
@@ -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,7 +107,12 @@ export class HideProviderSelectorComponent implements Component {
103
107
  hidden: isHidden(currentRules, m.provider, m.id),
104
108
  });
105
109
  }
106
- 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();
107
116
 
108
117
  this.searchInput = new Input();
109
118
  this.listContainer = new Container();
@@ -268,26 +277,59 @@ export class HideProviderSelectorComponent implements Component {
268
277
 
269
278
  private refresh(): void {
270
279
  const query = this.searchInput.getValue();
280
+
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.
284
+ for (const item of this.allItems) {
285
+ item.hidden = isHidden(this.hiddenRules, item.provider, item.modelId);
286
+ }
287
+
288
+ const items = this.buildItems();
271
289
  this.filteredItems = query
272
290
  ? fuzzyFilter(
273
- this.allItems,
291
+ items,
274
292
  query,
275
293
  (i) => `${i.provider} ${i.modelId} ${i.provider}/${i.modelId} ${i.modelName}`,
276
294
  )
277
- : [...this.allItems];
278
-
279
- // Update hidden status on all items (rules may have changed)
280
- for (const item of this.filteredItems) {
281
- item.hidden = isHidden(this.hiddenRules, item.provider, item.modelId);
282
- }
295
+ : items;
283
296
 
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.
284
299
  this.selectedIndex = Math.min(
285
300
  this.selectedIndex,
286
301
  Math.max(0, this.filteredItems.length - 1),
287
302
  );
303
+
288
304
  this.updateList();
289
305
  }
290
306
 
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.
310
+ */
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);
320
+ }
321
+ }
322
+
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);
327
+ }
328
+ }
329
+
330
+ return result;
331
+ }
332
+
291
333
  private updateList(): void {
292
334
  this.listContainer.clear();
293
335
 
@@ -398,12 +440,20 @@ export class HideProviderSelectorComponent implements Component {
398
440
  !(r.provider === item.provider && r.model === item.modelId),
399
441
  );
400
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
+ }
401
448
  } else {
402
449
  // Add a rule for this specific model
403
450
  this.hiddenRules = deduplicateRules([
404
451
  ...this.hiddenRules,
405
452
  { provider: item.provider, model: item.modelId },
406
453
  ]);
454
+
455
+ // Remove from the visible order.
456
+ this.visibleIds = this.visibleIds.filter((id) => id !== item.fullId);
407
457
  }
408
458
  this.hasChanges = true;
409
459
  this.refresh();
@@ -421,12 +471,25 @@ export class HideProviderSelectorComponent implements Component {
421
471
  this.hiddenRules = this.hiddenRules.filter(
422
472
  (r) => r.provider !== provider,
423
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
+ ];
424
482
  } else {
425
483
  // Hide all — add a single provider-level rule
426
484
  this.hiddenRules = deduplicateRules([
427
485
  ...this.hiddenRules,
428
486
  { provider },
429
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
+ );
430
493
  }
431
494
  this.hasChanges = true;
432
495
  this.refresh();
@@ -461,6 +524,10 @@ export class HideProviderSelectorComponent implements Component {
461
524
  }
462
525
  }
463
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));
464
531
  }
465
532
 
466
533
  /** Remove hide rules for the given items. */
@@ -513,6 +580,13 @@ export class HideProviderSelectorComponent implements Component {
513
580
  }
514
581
  }
515
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
+ }
516
590
  }
517
591
 
518
592
  /** Close and pass results to `done`. */