opencode-models-manager 0.0.0-stage → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Felipe Gutiérrez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,73 @@
1
- # Temporary Holding Version
1
+ <p align="center">
2
+ <picture>
3
+ <source srcset="assets/logo-dark.svg" media="(prefers-color-scheme: dark)">
4
+ <source srcset="assets/logo-light.svg" media="(prefers-color-scheme: light)">
5
+ <img src="assets/logo-light.svg" alt="agents logo">
6
+ </picture>
7
+ </p>
8
+ <p align="center">Manage your AI models from a single JSON file.</p>
9
+ <p align="center">
10
+ <a href="https://www.npmjs.com/package/opencode-models-manager"><img alt="npm" src="https://img.shields.io/npm/v/opencode-models-manager?style=flat-square" /></a>
11
+ <a href="https://github.com/RainingDaemons/opencode-models-manager/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" /></a>
12
+ </p>
2
13
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
14
+ ---
15
+
16
+ ## Why?
17
+
18
+ This repo was created to provide a simple solution for managing AI models for every chat mode from a single point. The AI industry changes rapidly, so having one place to update models makes it easy to keep every agent current without editing each configuration separately.
19
+
20
+ ## Installation
21
+
22
+ This branch is the OpenCode v1 line and requires OpenCode 1.18.0 or later. Pin 0.1.0 explicitly so a future v2 release on the latest dist-tag is never installed into a v1 host:
23
+
24
+ ```
25
+ opencode plugin opencode-models-manager@0.1.1
26
+ ```
27
+
28
+ Once the opencode-v1 dist-tag is published, `opencode-models-manager@opencode-v1` resolves to this line and can replace the pinned version above.
29
+
30
+ Restart OpenCode after installation.
31
+
32
+ ## Manual installation
33
+
34
+ Add to `~/.config/opencode/opencode.json` (global) or `opencode.json` (project):
35
+
36
+ ```json
37
+ {
38
+ "plugin": ["opencode-models-manager@0.1.1"]
39
+ }
40
+ ```
41
+
42
+ ## Local installation
43
+
44
+ Copy `models.ts` into your project plugin directory:
45
+
46
+ ```
47
+ .opencode/plugins/models.ts
48
+ ```
49
+
50
+ OpenCode loads `.opencode/plugins/` automatically at startup, so no config entry is needed.
51
+
52
+ ## Usage
53
+
54
+ Create `.opencode/models.json` in the project root:
55
+
56
+ ```json
57
+ {
58
+ "agent": {
59
+ "chat": "opencode-go/deepseek-v4.1-flash",
60
+ "chat2": "opencode-go/mimo-v2.6-flash"
61
+ },
62
+ "commands": {
63
+ "document": "opencode-go/deepseek-v4.1-flash",
64
+ "document2": "opencode-go/mimo-v2.6-flash"
65
+ }
66
+ }
67
+ ```
68
+
69
+ The `agent` section targets agents in `.opencode/agent` and the `commands` section targets commands in `.opencode/commands`. The plugin merges the model into each existing configuration, so prompts, permissions, frontmatter, and other settings are preserved. A flat map such as `{ "chat": "provider/model" }` is still supported and applies to agents.
70
+
71
+ Invalid entries are logged and skipped. Restart OpenCode after changing `models.json` so the config hook runs again.
72
+
73
+ Actually Opencode v1 is supported.
@@ -0,0 +1,240 @@
1
+ <svg width="414" height="48" viewBox="0 0 414 48" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="0" y="6" width="6" height="6" fill="#F1ECEC"/>
3
+ <rect x="6" y="6" width="6" height="6" fill="#F1ECEC"/>
4
+ <rect x="12" y="6" width="6" height="6" fill="#F1ECEC"/>
5
+ <rect x="18" y="6" width="6" height="6" fill="#F1ECEC"/>
6
+ <rect x="24" y="6" width="6" height="6" fill="#F1ECEC"/>
7
+ <rect x="0" y="12" width="6" height="6" fill="#F1ECEC"/>
8
+ <rect x="12" y="12" width="6" height="6" fill="#F1ECEC"/>
9
+ <rect x="24" y="12" width="6" height="6" fill="#F1ECEC"/>
10
+ <rect x="0" y="18" width="6" height="6" fill="#F1ECEC"/>
11
+ <rect x="6" y="18" width="6" height="6" fill="#4B4646"/>
12
+ <rect x="12" y="18" width="6" height="6" fill="#F1ECEC"/>
13
+ <rect x="18" y="18" width="6" height="6" fill="#4B4646"/>
14
+ <rect x="24" y="18" width="6" height="6" fill="#F1ECEC"/>
15
+ <rect x="0" y="24" width="6" height="6" fill="#F1ECEC"/>
16
+ <rect x="6" y="24" width="6" height="6" fill="#4B4646"/>
17
+ <rect x="12" y="24" width="6" height="6" fill="#F1ECEC"/>
18
+ <rect x="18" y="24" width="6" height="6" fill="#4B4646"/>
19
+ <rect x="24" y="24" width="6" height="6" fill="#F1ECEC"/>
20
+ <rect x="0" y="30" width="6" height="6" fill="#F1ECEC"/>
21
+ <rect x="6" y="30" width="6" height="6" fill="#4B4646"/>
22
+ <rect x="12" y="30" width="6" height="6" fill="#F1ECEC"/>
23
+ <rect x="18" y="30" width="6" height="6" fill="#4B4646"/>
24
+ <rect x="24" y="30" width="6" height="6" fill="#F1ECEC"/>
25
+ <rect x="36" y="6" width="6" height="6" fill="#F1ECEC"/>
26
+ <rect x="42" y="6" width="6" height="6" fill="#F1ECEC"/>
27
+ <rect x="48" y="6" width="6" height="6" fill="#F1ECEC"/>
28
+ <rect x="54" y="6" width="6" height="6" fill="#F1ECEC"/>
29
+ <rect x="36" y="12" width="6" height="6" fill="#F1ECEC"/>
30
+ <rect x="54" y="12" width="6" height="6" fill="#F1ECEC"/>
31
+ <rect x="36" y="18" width="6" height="6" fill="#F1ECEC"/>
32
+ <rect x="42" y="18" width="6" height="6" fill="#4B4646"/>
33
+ <rect x="48" y="18" width="6" height="6" fill="#4B4646"/>
34
+ <rect x="54" y="18" width="6" height="6" fill="#F1ECEC"/>
35
+ <rect x="36" y="24" width="6" height="6" fill="#F1ECEC"/>
36
+ <rect x="42" y="24" width="6" height="6" fill="#4B4646"/>
37
+ <rect x="48" y="24" width="6" height="6" fill="#4B4646"/>
38
+ <rect x="54" y="24" width="6" height="6" fill="#F1ECEC"/>
39
+ <rect x="36" y="30" width="6" height="6" fill="#F1ECEC"/>
40
+ <rect x="42" y="30" width="6" height="6" fill="#F1ECEC"/>
41
+ <rect x="48" y="30" width="6" height="6" fill="#F1ECEC"/>
42
+ <rect x="54" y="30" width="6" height="6" fill="#F1ECEC"/>
43
+ <rect x="78" y="6" width="6" height="6" fill="#F1ECEC"/>
44
+ <rect x="84" y="6" width="6" height="6" fill="#F1ECEC"/>
45
+ <rect x="66" y="12" width="6" height="6" fill="#F1ECEC"/>
46
+ <rect x="72" y="12" width="6" height="6" fill="#F1ECEC"/>
47
+ <rect x="78" y="12" width="6" height="6" fill="#F1ECEC"/>
48
+ <rect x="84" y="12" width="6" height="6" fill="#F1ECEC"/>
49
+ <rect x="66" y="18" width="6" height="6" fill="#F1ECEC"/>
50
+ <rect x="72" y="18" width="6" height="6" fill="#4B4646"/>
51
+ <rect x="78" y="18" width="6" height="6" fill="#4B4646"/>
52
+ <rect x="84" y="18" width="6" height="6" fill="#F1ECEC"/>
53
+ <rect x="66" y="24" width="6" height="6" fill="#F1ECEC"/>
54
+ <rect x="72" y="24" width="6" height="6" fill="#4B4646"/>
55
+ <rect x="78" y="24" width="6" height="6" fill="#4B4646"/>
56
+ <rect x="84" y="24" width="6" height="6" fill="#F1ECEC"/>
57
+ <rect x="66" y="30" width="6" height="6" fill="#F1ECEC"/>
58
+ <rect x="72" y="30" width="6" height="6" fill="#F1ECEC"/>
59
+ <rect x="78" y="30" width="6" height="6" fill="#F1ECEC"/>
60
+ <rect x="84" y="30" width="6" height="6" fill="#F1ECEC"/>
61
+ <rect x="96" y="6" width="6" height="6" fill="#F1ECEC"/>
62
+ <rect x="102" y="6" width="6" height="6" fill="#F1ECEC"/>
63
+ <rect x="108" y="6" width="6" height="6" fill="#F1ECEC"/>
64
+ <rect x="114" y="6" width="6" height="6" fill="#F1ECEC"/>
65
+ <rect x="96" y="12" width="6" height="6" fill="#F1ECEC"/>
66
+ <rect x="114" y="12" width="6" height="6" fill="#F1ECEC"/>
67
+ <rect x="96" y="18" width="6" height="6" fill="#F1ECEC"/>
68
+ <rect x="102" y="18" width="6" height="6" fill="#F1ECEC"/>
69
+ <rect x="108" y="18" width="6" height="6" fill="#F1ECEC"/>
70
+ <rect x="114" y="18" width="6" height="6" fill="#F1ECEC"/>
71
+ <rect x="96" y="24" width="6" height="6" fill="#F1ECEC"/>
72
+ <rect x="102" y="24" width="6" height="6" fill="#4B4646"/>
73
+ <rect x="108" y="24" width="6" height="6" fill="#4B4646"/>
74
+ <rect x="114" y="24" width="6" height="6" fill="#4B4646"/>
75
+ <rect x="96" y="30" width="6" height="6" fill="#F1ECEC"/>
76
+ <rect x="102" y="30" width="6" height="6" fill="#F1ECEC"/>
77
+ <rect x="108" y="30" width="6" height="6" fill="#F1ECEC"/>
78
+ <rect x="114" y="30" width="6" height="6" fill="#F1ECEC"/>
79
+ <rect x="126" y="6" width="6" height="6" fill="#F1ECEC"/>
80
+ <rect x="132" y="6" width="6" height="6" fill="#F1ECEC"/>
81
+ <rect x="138" y="6" width="6" height="6" fill="#F1ECEC"/>
82
+ <rect x="132" y="12" width="6" height="6" fill="#F1ECEC"/>
83
+ <rect x="132" y="18" width="6" height="6" fill="#F1ECEC"/>
84
+ <rect x="132" y="24" width="6" height="6" fill="#F1ECEC"/>
85
+ <rect x="138" y="24" width="6" height="6" fill="#4B4646"/>
86
+ <rect x="144" y="24" width="6" height="6" fill="#4B4646"/>
87
+ <rect x="126" y="30" width="6" height="6" fill="#F1ECEC"/>
88
+ <rect x="132" y="30" width="6" height="6" fill="#F1ECEC"/>
89
+ <rect x="138" y="30" width="6" height="6" fill="#F1ECEC"/>
90
+ <rect x="144" y="30" width="6" height="6" fill="#F1ECEC"/>
91
+ <rect x="156" y="6" width="6" height="6" fill="#F1ECEC"/>
92
+ <rect x="162" y="6" width="6" height="6" fill="#F1ECEC"/>
93
+ <rect x="168" y="6" width="6" height="6" fill="#F1ECEC"/>
94
+ <rect x="174" y="6" width="6" height="6" fill="#F1ECEC"/>
95
+ <rect x="156" y="12" width="6" height="6" fill="#F1ECEC"/>
96
+ <rect x="156" y="18" width="6" height="6" fill="#F1ECEC"/>
97
+ <rect x="162" y="18" width="6" height="6" fill="#F1ECEC"/>
98
+ <rect x="168" y="18" width="6" height="6" fill="#F1ECEC"/>
99
+ <rect x="174" y="18" width="6" height="6" fill="#F1ECEC"/>
100
+ <rect x="156" y="24" width="6" height="6" fill="#4B4646"/>
101
+ <rect x="162" y="24" width="6" height="6" fill="#4B4646"/>
102
+ <rect x="168" y="24" width="6" height="6" fill="#4B4646"/>
103
+ <rect x="174" y="24" width="6" height="6" fill="#F1ECEC"/>
104
+ <rect x="156" y="30" width="6" height="6" fill="#F1ECEC"/>
105
+ <rect x="162" y="30" width="6" height="6" fill="#F1ECEC"/>
106
+ <rect x="168" y="30" width="6" height="6" fill="#F1ECEC"/>
107
+ <rect x="174" y="30" width="6" height="6" fill="#F1ECEC"/>
108
+ <rect x="204" y="6" width="6" height="6" fill="#F1ECEC"/>
109
+ <rect x="210" y="6" width="6" height="6" fill="#F1ECEC"/>
110
+ <rect x="216" y="6" width="6" height="6" fill="#F1ECEC"/>
111
+ <rect x="222" y="6" width="6" height="6" fill="#F1ECEC"/>
112
+ <rect x="228" y="6" width="6" height="6" fill="#F1ECEC"/>
113
+ <rect x="204" y="12" width="6" height="6" fill="#F1ECEC"/>
114
+ <rect x="216" y="12" width="6" height="6" fill="#F1ECEC"/>
115
+ <rect x="228" y="12" width="6" height="6" fill="#F1ECEC"/>
116
+ <rect x="204" y="18" width="6" height="6" fill="#F1ECEC"/>
117
+ <rect x="210" y="18" width="6" height="6" fill="#4B4646"/>
118
+ <rect x="216" y="18" width="6" height="6" fill="#F1ECEC"/>
119
+ <rect x="222" y="18" width="6" height="6" fill="#4B4646"/>
120
+ <rect x="228" y="18" width="6" height="6" fill="#F1ECEC"/>
121
+ <rect x="204" y="24" width="6" height="6" fill="#F1ECEC"/>
122
+ <rect x="210" y="24" width="6" height="6" fill="#4B4646"/>
123
+ <rect x="216" y="24" width="6" height="6" fill="#F1ECEC"/>
124
+ <rect x="222" y="24" width="6" height="6" fill="#4B4646"/>
125
+ <rect x="228" y="24" width="6" height="6" fill="#F1ECEC"/>
126
+ <rect x="204" y="30" width="6" height="6" fill="#F1ECEC"/>
127
+ <rect x="210" y="30" width="6" height="6" fill="#4B4646"/>
128
+ <rect x="216" y="30" width="6" height="6" fill="#F1ECEC"/>
129
+ <rect x="222" y="30" width="6" height="6" fill="#4B4646"/>
130
+ <rect x="228" y="30" width="6" height="6" fill="#F1ECEC"/>
131
+ <rect x="240" y="6" width="6" height="6" fill="#F1ECEC"/>
132
+ <rect x="246" y="6" width="6" height="6" fill="#F1ECEC"/>
133
+ <rect x="252" y="6" width="6" height="6" fill="#F1ECEC"/>
134
+ <rect x="258" y="6" width="6" height="6" fill="#F1ECEC"/>
135
+ <rect x="240" y="12" width="6" height="6" fill="#F1ECEC"/>
136
+ <rect x="258" y="12" width="6" height="6" fill="#F1ECEC"/>
137
+ <rect x="240" y="18" width="6" height="6" fill="#F1ECEC"/>
138
+ <rect x="246" y="18" width="6" height="6" fill="#F1ECEC"/>
139
+ <rect x="252" y="18" width="6" height="6" fill="#F1ECEC"/>
140
+ <rect x="258" y="18" width="6" height="6" fill="#F1ECEC"/>
141
+ <rect x="240" y="24" width="6" height="6" fill="#F1ECEC"/>
142
+ <rect x="246" y="24" width="6" height="6" fill="#4B4646"/>
143
+ <rect x="252" y="24" width="6" height="6" fill="#4B4646"/>
144
+ <rect x="258" y="24" width="6" height="6" fill="#F1ECEC"/>
145
+ <rect x="240" y="30" width="6" height="6" fill="#F1ECEC"/>
146
+ <rect x="246" y="30" width="6" height="6" fill="#4B4646"/>
147
+ <rect x="252" y="30" width="6" height="6" fill="#4B4646"/>
148
+ <rect x="258" y="30" width="6" height="6" fill="#F1ECEC"/>
149
+ <rect x="270" y="6" width="6" height="6" fill="#F1ECEC"/>
150
+ <rect x="276" y="6" width="6" height="6" fill="#F1ECEC"/>
151
+ <rect x="282" y="6" width="6" height="6" fill="#F1ECEC"/>
152
+ <rect x="288" y="6" width="6" height="6" fill="#F1ECEC"/>
153
+ <rect x="270" y="12" width="6" height="6" fill="#F1ECEC"/>
154
+ <rect x="288" y="12" width="6" height="6" fill="#F1ECEC"/>
155
+ <rect x="270" y="18" width="6" height="6" fill="#F1ECEC"/>
156
+ <rect x="276" y="18" width="6" height="6" fill="#4B4646"/>
157
+ <rect x="282" y="18" width="6" height="6" fill="#4B4646"/>
158
+ <rect x="288" y="18" width="6" height="6" fill="#F1ECEC"/>
159
+ <rect x="270" y="24" width="6" height="6" fill="#F1ECEC"/>
160
+ <rect x="276" y="24" width="6" height="6" fill="#4B4646"/>
161
+ <rect x="282" y="24" width="6" height="6" fill="#4B4646"/>
162
+ <rect x="288" y="24" width="6" height="6" fill="#F1ECEC"/>
163
+ <rect x="270" y="30" width="6" height="6" fill="#F1ECEC"/>
164
+ <rect x="276" y="30" width="6" height="6" fill="#4B4646"/>
165
+ <rect x="282" y="30" width="6" height="6" fill="#4B4646"/>
166
+ <rect x="288" y="30" width="6" height="6" fill="#F1ECEC"/>
167
+ <rect x="300" y="6" width="6" height="6" fill="#F1ECEC"/>
168
+ <rect x="306" y="6" width="6" height="6" fill="#F1ECEC"/>
169
+ <rect x="312" y="6" width="6" height="6" fill="#F1ECEC"/>
170
+ <rect x="318" y="6" width="6" height="6" fill="#F1ECEC"/>
171
+ <rect x="300" y="12" width="6" height="6" fill="#F1ECEC"/>
172
+ <rect x="318" y="12" width="6" height="6" fill="#F1ECEC"/>
173
+ <rect x="300" y="18" width="6" height="6" fill="#F1ECEC"/>
174
+ <rect x="306" y="18" width="6" height="6" fill="#F1ECEC"/>
175
+ <rect x="312" y="18" width="6" height="6" fill="#F1ECEC"/>
176
+ <rect x="318" y="18" width="6" height="6" fill="#F1ECEC"/>
177
+ <rect x="300" y="24" width="6" height="6" fill="#F1ECEC"/>
178
+ <rect x="306" y="24" width="6" height="6" fill="#4B4646"/>
179
+ <rect x="312" y="24" width="6" height="6" fill="#4B4646"/>
180
+ <rect x="318" y="24" width="6" height="6" fill="#F1ECEC"/>
181
+ <rect x="300" y="30" width="6" height="6" fill="#F1ECEC"/>
182
+ <rect x="306" y="30" width="6" height="6" fill="#4B4646"/>
183
+ <rect x="312" y="30" width="6" height="6" fill="#4B4646"/>
184
+ <rect x="318" y="30" width="6" height="6" fill="#F1ECEC"/>
185
+ <rect x="330" y="6" width="6" height="6" fill="#F1ECEC"/>
186
+ <rect x="336" y="6" width="6" height="6" fill="#F1ECEC"/>
187
+ <rect x="342" y="6" width="6" height="6" fill="#F1ECEC"/>
188
+ <rect x="348" y="6" width="6" height="6" fill="#F1ECEC"/>
189
+ <rect x="330" y="12" width="6" height="6" fill="#F1ECEC"/>
190
+ <rect x="348" y="12" width="6" height="6" fill="#F1ECEC"/>
191
+ <rect x="330" y="18" width="6" height="6" fill="#F1ECEC"/>
192
+ <rect x="336" y="18" width="6" height="6" fill="#4B4646"/>
193
+ <rect x="342" y="18" width="6" height="6" fill="#4B4646"/>
194
+ <rect x="348" y="18" width="6" height="6" fill="#F1ECEC"/>
195
+ <rect x="330" y="24" width="6" height="6" fill="#F1ECEC"/>
196
+ <rect x="336" y="24" width="6" height="6" fill="#4B4646"/>
197
+ <rect x="342" y="24" width="6" height="6" fill="#4B4646"/>
198
+ <rect x="348" y="24" width="6" height="6" fill="#F1ECEC"/>
199
+ <rect x="330" y="30" width="6" height="6" fill="#F1ECEC"/>
200
+ <rect x="336" y="30" width="6" height="6" fill="#F1ECEC"/>
201
+ <rect x="342" y="30" width="6" height="6" fill="#F1ECEC"/>
202
+ <rect x="348" y="30" width="6" height="6" fill="#F1ECEC"/>
203
+ <rect x="348" y="36" width="6" height="6" fill="#F1ECEC"/>
204
+ <rect x="330" y="42" width="6" height="6" fill="#F1ECEC"/>
205
+ <rect x="336" y="42" width="6" height="6" fill="#F1ECEC"/>
206
+ <rect x="342" y="42" width="6" height="6" fill="#F1ECEC"/>
207
+ <rect x="348" y="42" width="6" height="6" fill="#F1ECEC"/>
208
+ <rect x="360" y="6" width="6" height="6" fill="#F1ECEC"/>
209
+ <rect x="366" y="6" width="6" height="6" fill="#F1ECEC"/>
210
+ <rect x="372" y="6" width="6" height="6" fill="#F1ECEC"/>
211
+ <rect x="378" y="6" width="6" height="6" fill="#F1ECEC"/>
212
+ <rect x="360" y="12" width="6" height="6" fill="#F1ECEC"/>
213
+ <rect x="378" y="12" width="6" height="6" fill="#F1ECEC"/>
214
+ <rect x="360" y="18" width="6" height="6" fill="#F1ECEC"/>
215
+ <rect x="366" y="18" width="6" height="6" fill="#F1ECEC"/>
216
+ <rect x="372" y="18" width="6" height="6" fill="#F1ECEC"/>
217
+ <rect x="378" y="18" width="6" height="6" fill="#F1ECEC"/>
218
+ <rect x="360" y="24" width="6" height="6" fill="#F1ECEC"/>
219
+ <rect x="366" y="24" width="6" height="6" fill="#4B4646"/>
220
+ <rect x="372" y="24" width="6" height="6" fill="#4B4646"/>
221
+ <rect x="378" y="24" width="6" height="6" fill="#4B4646"/>
222
+ <rect x="360" y="30" width="6" height="6" fill="#F1ECEC"/>
223
+ <rect x="366" y="30" width="6" height="6" fill="#F1ECEC"/>
224
+ <rect x="372" y="30" width="6" height="6" fill="#F1ECEC"/>
225
+ <rect x="378" y="30" width="6" height="6" fill="#F1ECEC"/>
226
+ <rect x="390" y="6" width="6" height="6" fill="#F1ECEC"/>
227
+ <rect x="396" y="6" width="6" height="6" fill="#F1ECEC"/>
228
+ <rect x="402" y="6" width="6" height="6" fill="#F1ECEC"/>
229
+ <rect x="408" y="6" width="6" height="6" fill="#F1ECEC"/>
230
+ <rect x="390" y="12" width="6" height="6" fill="#F1ECEC"/>
231
+ <rect x="408" y="12" width="6" height="6" fill="#F1ECEC"/>
232
+ <rect x="390" y="18" width="6" height="6" fill="#F1ECEC"/>
233
+ <rect x="396" y="18" width="6" height="6" fill="#4B4646"/>
234
+ <rect x="402" y="18" width="6" height="6" fill="#4B4646"/>
235
+ <rect x="408" y="18" width="6" height="6" fill="#F1ECEC"/>
236
+ <rect x="390" y="24" width="6" height="6" fill="#F1ECEC"/>
237
+ <rect x="396" y="24" width="6" height="6" fill="#4B4646"/>
238
+ <rect x="390" y="30" width="6" height="6" fill="#F1ECEC"/>
239
+ <rect x="396" y="30" width="6" height="6" fill="#4B4646"/>
240
+ </svg>
@@ -0,0 +1,240 @@
1
+ <svg width="414" height="48" viewBox="0 0 414 48" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="0" y="6" width="6" height="6" fill="#211E1E"/>
3
+ <rect x="6" y="6" width="6" height="6" fill="#211E1E"/>
4
+ <rect x="12" y="6" width="6" height="6" fill="#211E1E"/>
5
+ <rect x="18" y="6" width="6" height="6" fill="#211E1E"/>
6
+ <rect x="24" y="6" width="6" height="6" fill="#211E1E"/>
7
+ <rect x="0" y="12" width="6" height="6" fill="#211E1E"/>
8
+ <rect x="12" y="12" width="6" height="6" fill="#211E1E"/>
9
+ <rect x="24" y="12" width="6" height="6" fill="#211E1E"/>
10
+ <rect x="0" y="18" width="6" height="6" fill="#211E1E"/>
11
+ <rect x="6" y="18" width="6" height="6" fill="#CFCECD"/>
12
+ <rect x="12" y="18" width="6" height="6" fill="#211E1E"/>
13
+ <rect x="18" y="18" width="6" height="6" fill="#CFCECD"/>
14
+ <rect x="24" y="18" width="6" height="6" fill="#211E1E"/>
15
+ <rect x="0" y="24" width="6" height="6" fill="#211E1E"/>
16
+ <rect x="6" y="24" width="6" height="6" fill="#CFCECD"/>
17
+ <rect x="12" y="24" width="6" height="6" fill="#211E1E"/>
18
+ <rect x="18" y="24" width="6" height="6" fill="#CFCECD"/>
19
+ <rect x="24" y="24" width="6" height="6" fill="#211E1E"/>
20
+ <rect x="0" y="30" width="6" height="6" fill="#211E1E"/>
21
+ <rect x="6" y="30" width="6" height="6" fill="#CFCECD"/>
22
+ <rect x="12" y="30" width="6" height="6" fill="#211E1E"/>
23
+ <rect x="18" y="30" width="6" height="6" fill="#CFCECD"/>
24
+ <rect x="24" y="30" width="6" height="6" fill="#211E1E"/>
25
+ <rect x="36" y="6" width="6" height="6" fill="#211E1E"/>
26
+ <rect x="42" y="6" width="6" height="6" fill="#211E1E"/>
27
+ <rect x="48" y="6" width="6" height="6" fill="#211E1E"/>
28
+ <rect x="54" y="6" width="6" height="6" fill="#211E1E"/>
29
+ <rect x="36" y="12" width="6" height="6" fill="#211E1E"/>
30
+ <rect x="54" y="12" width="6" height="6" fill="#211E1E"/>
31
+ <rect x="36" y="18" width="6" height="6" fill="#211E1E"/>
32
+ <rect x="42" y="18" width="6" height="6" fill="#CFCECD"/>
33
+ <rect x="48" y="18" width="6" height="6" fill="#CFCECD"/>
34
+ <rect x="54" y="18" width="6" height="6" fill="#211E1E"/>
35
+ <rect x="36" y="24" width="6" height="6" fill="#211E1E"/>
36
+ <rect x="42" y="24" width="6" height="6" fill="#CFCECD"/>
37
+ <rect x="48" y="24" width="6" height="6" fill="#CFCECD"/>
38
+ <rect x="54" y="24" width="6" height="6" fill="#211E1E"/>
39
+ <rect x="36" y="30" width="6" height="6" fill="#211E1E"/>
40
+ <rect x="42" y="30" width="6" height="6" fill="#211E1E"/>
41
+ <rect x="48" y="30" width="6" height="6" fill="#211E1E"/>
42
+ <rect x="54" y="30" width="6" height="6" fill="#211E1E"/>
43
+ <rect x="78" y="6" width="6" height="6" fill="#211E1E"/>
44
+ <rect x="84" y="6" width="6" height="6" fill="#211E1E"/>
45
+ <rect x="66" y="12" width="6" height="6" fill="#211E1E"/>
46
+ <rect x="72" y="12" width="6" height="6" fill="#211E1E"/>
47
+ <rect x="78" y="12" width="6" height="6" fill="#211E1E"/>
48
+ <rect x="84" y="12" width="6" height="6" fill="#211E1E"/>
49
+ <rect x="66" y="18" width="6" height="6" fill="#211E1E"/>
50
+ <rect x="72" y="18" width="6" height="6" fill="#CFCECD"/>
51
+ <rect x="78" y="18" width="6" height="6" fill="#CFCECD"/>
52
+ <rect x="84" y="18" width="6" height="6" fill="#211E1E"/>
53
+ <rect x="66" y="24" width="6" height="6" fill="#211E1E"/>
54
+ <rect x="72" y="24" width="6" height="6" fill="#CFCECD"/>
55
+ <rect x="78" y="24" width="6" height="6" fill="#CFCECD"/>
56
+ <rect x="84" y="24" width="6" height="6" fill="#211E1E"/>
57
+ <rect x="66" y="30" width="6" height="6" fill="#211E1E"/>
58
+ <rect x="72" y="30" width="6" height="6" fill="#211E1E"/>
59
+ <rect x="78" y="30" width="6" height="6" fill="#211E1E"/>
60
+ <rect x="84" y="30" width="6" height="6" fill="#211E1E"/>
61
+ <rect x="96" y="6" width="6" height="6" fill="#211E1E"/>
62
+ <rect x="102" y="6" width="6" height="6" fill="#211E1E"/>
63
+ <rect x="108" y="6" width="6" height="6" fill="#211E1E"/>
64
+ <rect x="114" y="6" width="6" height="6" fill="#211E1E"/>
65
+ <rect x="96" y="12" width="6" height="6" fill="#211E1E"/>
66
+ <rect x="114" y="12" width="6" height="6" fill="#211E1E"/>
67
+ <rect x="96" y="18" width="6" height="6" fill="#211E1E"/>
68
+ <rect x="102" y="18" width="6" height="6" fill="#211E1E"/>
69
+ <rect x="108" y="18" width="6" height="6" fill="#211E1E"/>
70
+ <rect x="114" y="18" width="6" height="6" fill="#211E1E"/>
71
+ <rect x="96" y="24" width="6" height="6" fill="#211E1E"/>
72
+ <rect x="102" y="24" width="6" height="6" fill="#CFCECD"/>
73
+ <rect x="108" y="24" width="6" height="6" fill="#CFCECD"/>
74
+ <rect x="114" y="24" width="6" height="6" fill="#CFCECD"/>
75
+ <rect x="96" y="30" width="6" height="6" fill="#211E1E"/>
76
+ <rect x="102" y="30" width="6" height="6" fill="#211E1E"/>
77
+ <rect x="108" y="30" width="6" height="6" fill="#211E1E"/>
78
+ <rect x="114" y="30" width="6" height="6" fill="#211E1E"/>
79
+ <rect x="126" y="6" width="6" height="6" fill="#211E1E"/>
80
+ <rect x="132" y="6" width="6" height="6" fill="#211E1E"/>
81
+ <rect x="138" y="6" width="6" height="6" fill="#211E1E"/>
82
+ <rect x="132" y="12" width="6" height="6" fill="#211E1E"/>
83
+ <rect x="132" y="18" width="6" height="6" fill="#211E1E"/>
84
+ <rect x="132" y="24" width="6" height="6" fill="#211E1E"/>
85
+ <rect x="138" y="24" width="6" height="6" fill="#CFCECD"/>
86
+ <rect x="144" y="24" width="6" height="6" fill="#CFCECD"/>
87
+ <rect x="126" y="30" width="6" height="6" fill="#211E1E"/>
88
+ <rect x="132" y="30" width="6" height="6" fill="#211E1E"/>
89
+ <rect x="138" y="30" width="6" height="6" fill="#211E1E"/>
90
+ <rect x="144" y="30" width="6" height="6" fill="#211E1E"/>
91
+ <rect x="156" y="6" width="6" height="6" fill="#211E1E"/>
92
+ <rect x="162" y="6" width="6" height="6" fill="#211E1E"/>
93
+ <rect x="168" y="6" width="6" height="6" fill="#211E1E"/>
94
+ <rect x="174" y="6" width="6" height="6" fill="#211E1E"/>
95
+ <rect x="156" y="12" width="6" height="6" fill="#211E1E"/>
96
+ <rect x="156" y="18" width="6" height="6" fill="#211E1E"/>
97
+ <rect x="162" y="18" width="6" height="6" fill="#211E1E"/>
98
+ <rect x="168" y="18" width="6" height="6" fill="#211E1E"/>
99
+ <rect x="174" y="18" width="6" height="6" fill="#211E1E"/>
100
+ <rect x="156" y="24" width="6" height="6" fill="#CFCECD"/>
101
+ <rect x="162" y="24" width="6" height="6" fill="#CFCECD"/>
102
+ <rect x="168" y="24" width="6" height="6" fill="#CFCECD"/>
103
+ <rect x="174" y="24" width="6" height="6" fill="#211E1E"/>
104
+ <rect x="156" y="30" width="6" height="6" fill="#211E1E"/>
105
+ <rect x="162" y="30" width="6" height="6" fill="#211E1E"/>
106
+ <rect x="168" y="30" width="6" height="6" fill="#211E1E"/>
107
+ <rect x="174" y="30" width="6" height="6" fill="#211E1E"/>
108
+ <rect x="204" y="6" width="6" height="6" fill="#211E1E"/>
109
+ <rect x="210" y="6" width="6" height="6" fill="#211E1E"/>
110
+ <rect x="216" y="6" width="6" height="6" fill="#211E1E"/>
111
+ <rect x="222" y="6" width="6" height="6" fill="#211E1E"/>
112
+ <rect x="228" y="6" width="6" height="6" fill="#211E1E"/>
113
+ <rect x="204" y="12" width="6" height="6" fill="#211E1E"/>
114
+ <rect x="216" y="12" width="6" height="6" fill="#211E1E"/>
115
+ <rect x="228" y="12" width="6" height="6" fill="#211E1E"/>
116
+ <rect x="204" y="18" width="6" height="6" fill="#211E1E"/>
117
+ <rect x="210" y="18" width="6" height="6" fill="#CFCECD"/>
118
+ <rect x="216" y="18" width="6" height="6" fill="#211E1E"/>
119
+ <rect x="222" y="18" width="6" height="6" fill="#CFCECD"/>
120
+ <rect x="228" y="18" width="6" height="6" fill="#211E1E"/>
121
+ <rect x="204" y="24" width="6" height="6" fill="#211E1E"/>
122
+ <rect x="210" y="24" width="6" height="6" fill="#CFCECD"/>
123
+ <rect x="216" y="24" width="6" height="6" fill="#211E1E"/>
124
+ <rect x="222" y="24" width="6" height="6" fill="#CFCECD"/>
125
+ <rect x="228" y="24" width="6" height="6" fill="#211E1E"/>
126
+ <rect x="204" y="30" width="6" height="6" fill="#211E1E"/>
127
+ <rect x="210" y="30" width="6" height="6" fill="#CFCECD"/>
128
+ <rect x="216" y="30" width="6" height="6" fill="#211E1E"/>
129
+ <rect x="222" y="30" width="6" height="6" fill="#CFCECD"/>
130
+ <rect x="228" y="30" width="6" height="6" fill="#211E1E"/>
131
+ <rect x="240" y="6" width="6" height="6" fill="#211E1E"/>
132
+ <rect x="246" y="6" width="6" height="6" fill="#211E1E"/>
133
+ <rect x="252" y="6" width="6" height="6" fill="#211E1E"/>
134
+ <rect x="258" y="6" width="6" height="6" fill="#211E1E"/>
135
+ <rect x="240" y="12" width="6" height="6" fill="#211E1E"/>
136
+ <rect x="258" y="12" width="6" height="6" fill="#211E1E"/>
137
+ <rect x="240" y="18" width="6" height="6" fill="#211E1E"/>
138
+ <rect x="246" y="18" width="6" height="6" fill="#211E1E"/>
139
+ <rect x="252" y="18" width="6" height="6" fill="#211E1E"/>
140
+ <rect x="258" y="18" width="6" height="6" fill="#211E1E"/>
141
+ <rect x="240" y="24" width="6" height="6" fill="#211E1E"/>
142
+ <rect x="246" y="24" width="6" height="6" fill="#CFCECD"/>
143
+ <rect x="252" y="24" width="6" height="6" fill="#CFCECD"/>
144
+ <rect x="258" y="24" width="6" height="6" fill="#211E1E"/>
145
+ <rect x="240" y="30" width="6" height="6" fill="#211E1E"/>
146
+ <rect x="246" y="30" width="6" height="6" fill="#CFCECD"/>
147
+ <rect x="252" y="30" width="6" height="6" fill="#CFCECD"/>
148
+ <rect x="258" y="30" width="6" height="6" fill="#211E1E"/>
149
+ <rect x="270" y="6" width="6" height="6" fill="#211E1E"/>
150
+ <rect x="276" y="6" width="6" height="6" fill="#211E1E"/>
151
+ <rect x="282" y="6" width="6" height="6" fill="#211E1E"/>
152
+ <rect x="288" y="6" width="6" height="6" fill="#211E1E"/>
153
+ <rect x="270" y="12" width="6" height="6" fill="#211E1E"/>
154
+ <rect x="288" y="12" width="6" height="6" fill="#211E1E"/>
155
+ <rect x="270" y="18" width="6" height="6" fill="#211E1E"/>
156
+ <rect x="276" y="18" width="6" height="6" fill="#CFCECD"/>
157
+ <rect x="282" y="18" width="6" height="6" fill="#CFCECD"/>
158
+ <rect x="288" y="18" width="6" height="6" fill="#211E1E"/>
159
+ <rect x="270" y="24" width="6" height="6" fill="#211E1E"/>
160
+ <rect x="276" y="24" width="6" height="6" fill="#CFCECD"/>
161
+ <rect x="282" y="24" width="6" height="6" fill="#CFCECD"/>
162
+ <rect x="288" y="24" width="6" height="6" fill="#211E1E"/>
163
+ <rect x="270" y="30" width="6" height="6" fill="#211E1E"/>
164
+ <rect x="276" y="30" width="6" height="6" fill="#CFCECD"/>
165
+ <rect x="282" y="30" width="6" height="6" fill="#CFCECD"/>
166
+ <rect x="288" y="30" width="6" height="6" fill="#211E1E"/>
167
+ <rect x="300" y="6" width="6" height="6" fill="#211E1E"/>
168
+ <rect x="306" y="6" width="6" height="6" fill="#211E1E"/>
169
+ <rect x="312" y="6" width="6" height="6" fill="#211E1E"/>
170
+ <rect x="318" y="6" width="6" height="6" fill="#211E1E"/>
171
+ <rect x="300" y="12" width="6" height="6" fill="#211E1E"/>
172
+ <rect x="318" y="12" width="6" height="6" fill="#211E1E"/>
173
+ <rect x="300" y="18" width="6" height="6" fill="#211E1E"/>
174
+ <rect x="306" y="18" width="6" height="6" fill="#211E1E"/>
175
+ <rect x="312" y="18" width="6" height="6" fill="#211E1E"/>
176
+ <rect x="318" y="18" width="6" height="6" fill="#211E1E"/>
177
+ <rect x="300" y="24" width="6" height="6" fill="#211E1E"/>
178
+ <rect x="306" y="24" width="6" height="6" fill="#CFCECD"/>
179
+ <rect x="312" y="24" width="6" height="6" fill="#CFCECD"/>
180
+ <rect x="318" y="24" width="6" height="6" fill="#211E1E"/>
181
+ <rect x="300" y="30" width="6" height="6" fill="#211E1E"/>
182
+ <rect x="306" y="30" width="6" height="6" fill="#CFCECD"/>
183
+ <rect x="312" y="30" width="6" height="6" fill="#CFCECD"/>
184
+ <rect x="318" y="30" width="6" height="6" fill="#211E1E"/>
185
+ <rect x="330" y="6" width="6" height="6" fill="#211E1E"/>
186
+ <rect x="336" y="6" width="6" height="6" fill="#211E1E"/>
187
+ <rect x="342" y="6" width="6" height="6" fill="#211E1E"/>
188
+ <rect x="348" y="6" width="6" height="6" fill="#211E1E"/>
189
+ <rect x="330" y="12" width="6" height="6" fill="#211E1E"/>
190
+ <rect x="348" y="12" width="6" height="6" fill="#211E1E"/>
191
+ <rect x="330" y="18" width="6" height="6" fill="#211E1E"/>
192
+ <rect x="336" y="18" width="6" height="6" fill="#CFCECD"/>
193
+ <rect x="342" y="18" width="6" height="6" fill="#CFCECD"/>
194
+ <rect x="348" y="18" width="6" height="6" fill="#211E1E"/>
195
+ <rect x="330" y="24" width="6" height="6" fill="#211E1E"/>
196
+ <rect x="336" y="24" width="6" height="6" fill="#CFCECD"/>
197
+ <rect x="342" y="24" width="6" height="6" fill="#CFCECD"/>
198
+ <rect x="348" y="24" width="6" height="6" fill="#211E1E"/>
199
+ <rect x="330" y="30" width="6" height="6" fill="#211E1E"/>
200
+ <rect x="336" y="30" width="6" height="6" fill="#211E1E"/>
201
+ <rect x="342" y="30" width="6" height="6" fill="#211E1E"/>
202
+ <rect x="348" y="30" width="6" height="6" fill="#211E1E"/>
203
+ <rect x="348" y="36" width="6" height="6" fill="#211E1E"/>
204
+ <rect x="330" y="42" width="6" height="6" fill="#211E1E"/>
205
+ <rect x="336" y="42" width="6" height="6" fill="#211E1E"/>
206
+ <rect x="342" y="42" width="6" height="6" fill="#211E1E"/>
207
+ <rect x="348" y="42" width="6" height="6" fill="#211E1E"/>
208
+ <rect x="360" y="6" width="6" height="6" fill="#211E1E"/>
209
+ <rect x="366" y="6" width="6" height="6" fill="#211E1E"/>
210
+ <rect x="372" y="6" width="6" height="6" fill="#211E1E"/>
211
+ <rect x="378" y="6" width="6" height="6" fill="#211E1E"/>
212
+ <rect x="360" y="12" width="6" height="6" fill="#211E1E"/>
213
+ <rect x="378" y="12" width="6" height="6" fill="#211E1E"/>
214
+ <rect x="360" y="18" width="6" height="6" fill="#211E1E"/>
215
+ <rect x="366" y="18" width="6" height="6" fill="#211E1E"/>
216
+ <rect x="372" y="18" width="6" height="6" fill="#211E1E"/>
217
+ <rect x="378" y="18" width="6" height="6" fill="#211E1E"/>
218
+ <rect x="360" y="24" width="6" height="6" fill="#211E1E"/>
219
+ <rect x="366" y="24" width="6" height="6" fill="#CFCECD"/>
220
+ <rect x="372" y="24" width="6" height="6" fill="#CFCECD"/>
221
+ <rect x="378" y="24" width="6" height="6" fill="#CFCECD"/>
222
+ <rect x="360" y="30" width="6" height="6" fill="#211E1E"/>
223
+ <rect x="366" y="30" width="6" height="6" fill="#211E1E"/>
224
+ <rect x="372" y="30" width="6" height="6" fill="#211E1E"/>
225
+ <rect x="378" y="30" width="6" height="6" fill="#211E1E"/>
226
+ <rect x="390" y="6" width="6" height="6" fill="#211E1E"/>
227
+ <rect x="396" y="6" width="6" height="6" fill="#211E1E"/>
228
+ <rect x="402" y="6" width="6" height="6" fill="#211E1E"/>
229
+ <rect x="408" y="6" width="6" height="6" fill="#211E1E"/>
230
+ <rect x="390" y="12" width="6" height="6" fill="#211E1E"/>
231
+ <rect x="408" y="12" width="6" height="6" fill="#211E1E"/>
232
+ <rect x="390" y="18" width="6" height="6" fill="#211E1E"/>
233
+ <rect x="396" y="18" width="6" height="6" fill="#CFCECD"/>
234
+ <rect x="402" y="18" width="6" height="6" fill="#CFCECD"/>
235
+ <rect x="408" y="18" width="6" height="6" fill="#211E1E"/>
236
+ <rect x="390" y="24" width="6" height="6" fill="#211E1E"/>
237
+ <rect x="396" y="24" width="6" height="6" fill="#CFCECD"/>
238
+ <rect x="390" y="30" width="6" height="6" fill="#211E1E"/>
239
+ <rect x="396" y="30" width="6" height="6" fill="#CFCECD"/>
240
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,44 @@
1
1
  {
2
2
  "name": "opencode-models-manager",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "description": "OpenCode plugin — manage agent models from a single JSON file",
6
+ "author": "RainingDaemons",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/RainingDaemons/opencode-models-manager.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/RainingDaemons/opencode-models-manager/issues"
14
+ },
15
+ "homepage": "https://github.com/RainingDaemons/opencode-models-manager",
16
+ "keywords": [
17
+ "opencode",
18
+ "opencode-plugin",
19
+ "models",
20
+ "agents",
21
+ "config",
22
+ "model-manager"
23
+ ],
24
+ "engines": {
25
+ "opencode": ">=1.18.0"
26
+ },
27
+ "main": "./src/models.ts",
28
+ "exports": {
29
+ ".": "./src/models.ts"
30
+ },
31
+ "files": [
32
+ "src",
33
+ "assets",
34
+ "!test",
35
+ "!test/**"
36
+ ],
37
+ "dependencies": {
38
+ "@opencode-ai/plugin": "^1.18.1"
39
+ },
40
+ "scripts": {
41
+ "test": "node --test test/models.test.ts",
42
+ "logo": "node script/logo.mjs"
43
+ }
6
44
  }
package/src/models.ts ADDED
@@ -0,0 +1,131 @@
1
+ import { readFileSync } from "node:fs"
2
+ import path from "node:path"
3
+ import type { Plugin } from "@opencode-ai/plugin"
4
+
5
+ const CONFIG_FILE = path.join(".opencode", "models.json")
6
+
7
+ type Section = "agent" | "command"
8
+ type Models = Record<Section, Record<string, string>>
9
+
10
+ const SECTIONS: Record<string, Section> = {
11
+ agent: "agent",
12
+ agents: "agent",
13
+ command: "command",
14
+ commands: "command",
15
+ }
16
+
17
+ function isRecord(value: unknown): value is Record<string, unknown> {
18
+ return typeof value === "object" && value !== null && !Array.isArray(value)
19
+ }
20
+
21
+ function isModelRef(value: string): boolean {
22
+ const slash = value.indexOf("/")
23
+ return slash > 0 && slash < value.length - 1
24
+ }
25
+
26
+ function isEntryName(name: string): boolean {
27
+ return name.trim() !== ""
28
+ }
29
+
30
+ function loadSection(
31
+ file: string,
32
+ section: Section,
33
+ value: Record<string, unknown>
34
+ ): Record<string, string> {
35
+ const models: Record<string, string> = {}
36
+ for (const [name, model] of Object.entries(value)) {
37
+ if (!isEntryName(name)) {
38
+ console.error(`[model-manager] ${file} ${section}s contains an empty name`)
39
+ continue
40
+ }
41
+ if (typeof model !== "string" || !isModelRef(model)) {
42
+ console.error(
43
+ `[model-manager] ${file} "${section}.${name}" must be "provider/model", got ${JSON.stringify(model)}`
44
+ )
45
+ continue
46
+ }
47
+ models[name] = model
48
+ }
49
+ return models
50
+ }
51
+
52
+ function loadModels(file: string): Models | null {
53
+ let raw: string
54
+ try {
55
+ raw = readFileSync(file, "utf8")
56
+ } catch {
57
+ return null
58
+ }
59
+
60
+ let parsed: unknown
61
+ try {
62
+ parsed = JSON.parse(raw)
63
+ } catch (error) {
64
+ console.error(`[model-manager] could not parse ${file}: ${(error as Error).message}`)
65
+ return null
66
+ }
67
+
68
+ if (!isRecord(parsed)) {
69
+ console.error(`[model-manager] ${file} must contain a JSON object`)
70
+ return null
71
+ }
72
+
73
+ const models: Models = { agent: {}, command: {} }
74
+ for (const [key, value] of Object.entries(parsed)) {
75
+ if (typeof value === "string") {
76
+ if (!isEntryName(key)) {
77
+ console.error(`[model-manager] ${file} contains an empty agent name`)
78
+ continue
79
+ }
80
+ if (!isModelRef(value)) {
81
+ console.error(
82
+ `[model-manager] ${file} "${key}" must be "provider/model", got ${JSON.stringify(value)}`
83
+ )
84
+ continue
85
+ }
86
+ models.agent[key] = value
87
+ continue
88
+ }
89
+
90
+ const section = Object.hasOwn(SECTIONS, key) ? SECTIONS[key] : undefined
91
+ if (!section) {
92
+ console.error(`[model-manager] ${file} has unknown key "${key}"`)
93
+ continue
94
+ }
95
+ if (!isRecord(value)) {
96
+ console.error(`[model-manager] ${file} "${key}" must be a JSON object`)
97
+ continue
98
+ }
99
+ Object.assign(models[section], loadSection(file, section, value))
100
+ }
101
+
102
+ return models
103
+ }
104
+
105
+ export default (async ({ directory, worktree }) => ({
106
+ config: async (cfg) => {
107
+ const root = worktree || directory
108
+ const models = loadModels(path.join(root, CONFIG_FILE)) ??
109
+ (root === directory ? null : loadModels(path.join(directory, CONFIG_FILE)))
110
+ if (!models) return
111
+
112
+ if (Object.keys(models.agent).length > 0) {
113
+ cfg.agent ??= {}
114
+ for (const [name, model] of Object.entries(models.agent)) {
115
+ cfg.agent[name] = { ...cfg.agent[name], model }
116
+ }
117
+ }
118
+
119
+ if (Object.keys(models.command).length > 0) {
120
+ cfg.command ??= {}
121
+ for (const [name, model] of Object.entries(models.command)) {
122
+ const command = cfg.command[name]
123
+ if (!command) {
124
+ console.error(`[model-manager] command "${name}" was not found`)
125
+ continue
126
+ }
127
+ cfg.command[name] = { ...command, model }
128
+ }
129
+ }
130
+ },
131
+ })) satisfies Plugin