@mrclrchtr/supi-web 2.7.0 → 2.8.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.
@@ -43,7 +43,7 @@ Config file locations:
43
43
  - `registerSettingsCommand(pi)` — register `/supi-settings` (used by `@mrclrchtr/supi-settings`)
44
44
  - `openSettingsOverlay(pi, ctx)` — open the shared settings UI directly
45
45
  - `createInputSubmenu()` — helper for simple text-entry submenus
46
- - `createModelPickerSubmenu()` — helper for scoped model selection submenus
46
+ - `createModelPickerSubmenu()` — helper for scoped model selection submenus, with optional host-owned choices and `disabled` control
47
47
 
48
48
  The built-in settings UI supports:
49
49
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -324,6 +324,7 @@ export class ScopedSettingsList {
324
324
  this.tui.requestRender();
325
325
  },
326
326
  this.ctx,
327
+ row.field.field,
327
328
  ),
328
329
  onDone: () => {
329
330
  this.submenu = null;
@@ -91,9 +91,23 @@ export interface StringListField extends BaseField {
91
91
  kind: "stringList";
92
92
  }
93
93
 
94
+ /** One non-model choice shown before the scoped models in a model picker. */
95
+ export interface ModelPickerStaticOption {
96
+ /** Persisted value for the choice. */
97
+ value: string;
98
+ /** Human-readable picker label. */
99
+ label: string;
100
+ /** Optional explanation shown alongside the label. */
101
+ description?: string;
102
+ }
103
+
94
104
  /** Model picker backed by the scoped model set. */
95
105
  export interface ModelPickerField extends BaseField {
96
106
  kind: "modelPicker";
107
+ /** Additional host-owned choices shown before scoped models. */
108
+ staticOptions?: ModelPickerStaticOption[];
109
+ /** Whether to include the built-in `disabled` choice. Defaults to true. */
110
+ includeDisabled?: boolean;
97
111
  }
98
112
 
99
113
  /**
@@ -14,6 +14,7 @@ import {
14
14
  Text,
15
15
  } from "@earendil-works/pi-tui";
16
16
  import { getSelectableModels } from "../model-selection.ts";
17
+ import type { ModelPickerField } from "./settings-schema.ts";
17
18
 
18
19
  /**
19
20
  * Creates a pi-tui Input-backed submenu component with enter-to-confirm
@@ -57,25 +58,26 @@ export function createInputSubmenu(
57
58
  }
58
59
 
59
60
  /**
60
- * Creates a model picker submenu for settings with "disabled" as the first option.
61
+ * Creates a model picker submenu backed by the scoped model set.
62
+ *
63
+ * The built-in `disabled` choice remains enabled by default. Callers can add
64
+ * host-owned static choices or omit `disabled` through the field options.
61
65
  */
62
66
  export function createModelPickerSubmenu(
63
67
  currentValue: string,
64
68
  done: (selectedValue?: string) => void,
65
69
  ctx?: ExtensionContext,
70
+ options: Pick<ModelPickerField, "includeDisabled" | "staticOptions"> = {},
66
71
  ): {
67
72
  render: (width: number) => string[];
68
73
  invalidate: () => void;
69
74
  handleInput: (data: string) => boolean;
70
75
  } {
71
- const items = buildModelItems(ctx);
72
- const initialIndex =
73
- currentValue === "disabled"
74
- ? 0
75
- : Math.max(
76
- 0,
77
- items.findIndex((item) => item.value === currentValue),
78
- );
76
+ const items = buildModelItems(ctx, options);
77
+ const initialIndex = Math.max(
78
+ 0,
79
+ items.findIndex((item) => item.value === currentValue),
80
+ );
79
81
 
80
82
  const container = new Container();
81
83
  container.addChild(new Text(" Select model", 1, 0));
@@ -105,20 +107,35 @@ export function createModelPickerSubmenu(
105
107
  };
106
108
  }
107
109
 
108
- /** Build selectable model items with "disabled" as the first option. */
109
- function buildModelItems(ctx?: ExtensionContext): SelectItem[] {
110
- const items: SelectItem[] = [
111
- { value: "disabled", label: "disabled", description: "No model selected" },
112
- ];
110
+ /** Build static choices followed by the selectable scoped models. */
111
+ function buildModelItems(
112
+ ctx: ExtensionContext | undefined,
113
+ options: Pick<ModelPickerField, "includeDisabled" | "staticOptions">,
114
+ ): SelectItem[] {
115
+ const items: SelectItem[] = [];
116
+ const seen = new Set<string>();
117
+ for (const option of options.staticOptions ?? []) {
118
+ if (seen.has(option.value)) continue;
119
+ items.push({ ...option });
120
+ seen.add(option.value);
121
+ }
122
+
123
+ if (options.includeDisabled !== false && !seen.has("disabled")) {
124
+ items.push({ value: "disabled", label: "disabled", description: "No model selected" });
125
+ seen.add("disabled");
126
+ }
127
+
113
128
  if (!ctx) return items;
114
129
  const models = getSelectableModels(ctx);
115
130
  for (const model of models) {
131
+ if (seen.has(model.canonicalId)) continue;
116
132
  const suffix = model.isCurrent ? " [current]" : "";
117
133
  items.push({
118
134
  value: model.canonicalId,
119
135
  label: `${model.canonicalId}${suffix}`,
120
136
  description: model.label !== model.canonicalId ? model.label : undefined,
121
137
  });
138
+ seen.add(model.canonicalId);
122
139
  }
123
140
  return items;
124
141
  }
@@ -20,6 +20,7 @@ export type {
20
20
  DeclarativeSettingsOptions,
21
21
  EnumField,
22
22
  ModelPickerField,
23
+ ModelPickerStaticOption,
23
24
  NumberField,
24
25
  ScopedFieldValue,
25
26
  SettingsField,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-web",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "SuPi Web extension — fetch web pages as clean Markdown (web_fetch_md) and library docs via Context7 (web_docs_search, web_docs_fetch)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -36,7 +36,7 @@
36
36
  "@mozilla/readability": "^0.6.0",
37
37
  "turndown": "^7.2.0",
38
38
  "turndown-plugin-gfm": "^1.0.2",
39
- "@mrclrchtr/supi-core": "2.7.0"
39
+ "@mrclrchtr/supi-core": "2.8.0"
40
40
  },
41
41
  "bundledDependencies": [
42
42
  "@mrclrchtr/supi-core"