pi-hide-providers 0.1.16 → 0.1.17

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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/package.json +11 -11
  3. package/src/index.ts +28 -2
package/README.md CHANGED
@@ -31,6 +31,7 @@ Pi has `enabledModels` in `settings.json` as an allowlist, but maintaining it ma
31
31
  - `/hide-models reset` removes the runtime/registry patch — all models return immediately
32
32
  - Changes via `/hide-models add` and `/hide-models remove` take effect immediately (no reload needed)
33
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
+ - `model` fields accept glob patterns — `"gpt-3.5*"` hides the whole family, `"*preview*"` hides every preview variant — so one rule can cover dated aliases and future models that follow the same naming convention
34
35
  - `/hide-models` subcommands for adding, removing, and inspecting rules
35
36
 
36
37
  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.16",
3
+ "version": "0.1.17",
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",
@@ -30,9 +30,16 @@
30
30
  "src/",
31
31
  "README.md"
32
32
  ],
33
+ "scripts": {
34
+ "test": "vitest run",
35
+ "test:watch": "vitest",
36
+ "test:coverage": "vitest run --coverage",
37
+ "typecheck": "tsc --noEmit",
38
+ "lint:dead": "knip --no-gitignore"
39
+ },
33
40
  "devDependencies": {
34
- "@earendil-works/pi-coding-agent": "0.84.4",
35
- "@earendil-works/pi-tui": "0.84.4",
41
+ "@earendil-works/pi-coding-agent": "0.85.0",
42
+ "@earendil-works/pi-tui": "0.85.0",
36
43
  "@types/node": "25.9.1",
37
44
  "@vitest/coverage-v8": "4.1.7",
38
45
  "knip": "6.14.1",
@@ -43,12 +50,5 @@
43
50
  "extensions": [
44
51
  "./hide-providers.ts"
45
52
  ]
46
- },
47
- "scripts": {
48
- "test": "vitest run",
49
- "test:watch": "vitest",
50
- "test:coverage": "vitest run --coverage",
51
- "typecheck": "tsc --noEmit",
52
- "lint:dead": "knip --no-gitignore"
53
53
  }
54
- }
54
+ }
package/src/index.ts CHANGED
@@ -17,6 +17,8 @@ export interface HideRule {
17
17
  /**
18
18
  * Model id pattern to hide within the provider.
19
19
  * Use "*" to hide all models from the provider.
20
+ * Use glob wildcards — "*" matches any run of characters, "?" matches exactly
21
+ * one — to hide a model family, e.g. "gpt-3.5*" or "*preview*".
20
22
  * Omit or leave undefined to hide the entire provider.
21
23
  */
22
24
  model?: string;
@@ -27,12 +29,36 @@ export interface HideProvidersConfig {
27
29
  hide: HideRule[];
28
30
  }
29
31
 
32
+ /**
33
+ * Translate a model-id glob into an anchored, case-sensitive RegExp.
34
+ *
35
+ * "*" matches any run of characters (including none), "?" matches exactly one,
36
+ * and every other character matches literally. Glob matching is scoped to the
37
+ * model id — the provider must still match the rule exactly.
38
+ */
39
+ function modelPatternToRegExp(pattern: string): RegExp {
40
+ let source = "";
41
+ for (const char of pattern) {
42
+ if (char === "*") source += ".*";
43
+ else if (char === "?") source += ".";
44
+ else source += char.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
45
+ }
46
+ return new RegExp(`^${source}$`);
47
+ }
48
+
49
+ function matchesModelPattern(pattern: string, modelId: string): boolean {
50
+ if (pattern === PROVIDER_WILDCARD) return true;
51
+ if (!pattern.includes("*") && !pattern.includes("?")) return pattern === modelId;
52
+ return modelPatternToRegExp(pattern).test(modelId);
53
+ }
54
+
30
55
  /**
31
56
  * Check whether a model is matched by any hide rule.
32
57
  *
33
58
  * A rule matches when:
34
59
  * - rule.provider === model.provider (exact, case-sensitive)
35
- * - AND (rule.model is undefined OR rule.model === "*" OR rule.model === model.id)
60
+ * - AND rule.model is undefined (hide entire provider), or matches the model id
61
+ * — either as the "*" wildcard, an exact id, or a glob pattern ("*"/"?").
36
62
  */
37
63
  export function isHidden(
38
64
  rules: ReadonlyArray<HideRule>,
@@ -42,7 +68,7 @@ export function isHidden(
42
68
  return rules.some(
43
69
  (rule) =>
44
70
  rule.provider === provider &&
45
- (rule.model === undefined || rule.model === PROVIDER_WILDCARD || rule.model === modelId),
71
+ (rule.model === undefined || matchesModelPattern(rule.model, modelId)),
46
72
  );
47
73
  }
48
74