@brainervirus/opencode-commandcode 0.6.0 → 0.7.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.0] - 2026-08-28
11
+
12
+ ### Changed
13
+
14
+ - npm publishes only when plugin or catalog files change since the last tag — CI, tests, and scripts-only merges skip a release.
15
+
16
+ ### Added
17
+
18
+ - Catalog models include vision vs text-only from the Command Code CLI `inputModalities` field on every SKU. models.dev only adds extra inputs (video/audio/pdf) on matches.
19
+
20
+ ## [0.6.1] - 2026-08-28
21
+
22
+ ### Added
23
+
24
+ - semantic-release now cuts Keep a Changelog `[Unreleased]` into `## [version]` on publish and includes `CHANGELOG.md` in the post-release sync PR.
25
+
26
+ ### Fixed
27
+
28
+ - Catalog GitHub release notes table no longer renders a blank header row above Plugin.
29
+ - Credits sentence no longer mentions Command Code wiring or restates MIT copyright.
30
+
31
+ ## [0.6.0] - 2026-08-28
32
+
33
+ ### Changed
34
+
35
+ - Renamed the published package and GitHub repository to `@brainervirus/opencode-commandcode`.
36
+
37
+ ## [0.5.1] - 2026-08-28
38
+
39
+ ### Fixed
40
+
41
+ - Price Command Code free SKUs at `$0` before models.dev, and fill remaining paid gaps from models.dev.
42
+
43
+ ## [0.5.0] - 2026-08-28
44
+
10
45
  ### Added
11
46
 
12
47
  - GitHub flow: PR-gated `main`, CI matrix (`check (test|typecheck|pack)`), semantic-release on merge, catalog updates as PRs.
package/README.md CHANGED
@@ -12,13 +12,14 @@ Previously published as `@brainervirus/commandcode-go-opencode-provider`. Use th
12
12
 
13
13
  ## Credits
14
14
 
15
- This package is based on **[FanFan4204/opencode-commandcode-provider](https://github.com/FanFan4204/opencode-commandcode-provider)**. That work started from **[brent-weatherall/opencode-commandcode-provider](https://github.com/brent-weatherall/opencode-commandcode-provider)** by **[Brent Weatherall](https://github.com/brent-weatherall)**. Thank you both — FanFan for the OpenCode provider this repo continues, and Brent for the original plugin, catalog extraction, and Command Code wiring. The license remains MIT; copyright stays with Brent Weatherall.
15
+ This package is based on **[FanFan4204/opencode-commandcode-provider](https://github.com/FanFan4204/opencode-commandcode-provider)**. That work started from **[brent-weatherall/opencode-commandcode-provider](https://github.com/brent-weatherall/opencode-commandcode-provider)** by **[Brent Weatherall](https://github.com/brent-weatherall)**. Thank you both — FanFan for the OpenCode provider this repo continues, and Brent for the original plugin, catalog extraction.
16
16
 
17
17
  ### What this package adds
18
18
 
19
19
  - Bundled `models.json` is the default runtime catalog (no local CLI scrape).
20
20
  - CLI cost extraction can fail (as on `command-code@1.38.x`) without dropping models.
21
21
  - Official docs fill missing costs; remaining paid gaps use [models.dev](https://models.dev) as a reference. Command Code free SKUs stay `$0`.
22
+ - Vision vs text-only comes from the Command Code CLI catalog (`inputModalities` on every SKU). [models.dev](https://models.dev) only adds extra inputs (video/audio/pdf) when it matches.
22
23
  - Reasoning effort **variants** on models that declare `reasoningEfforts`.
23
24
  - Quiet OpenCode startup (diagnostics go to `startup.json`, not stdout).
24
25
 
package/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-08-28T19:50:57.386Z",
4
- "pluginVersion": "0.5.0",
3
+ "generatedAt": "2026-08-28T21:14:42.165Z",
4
+ "pluginVersion": "0.6.1",
5
5
  "commandCodeVersion": "1.38.1",
6
6
  "commandCodeTarball": "https://registry.npmjs.org/command-code/-/command-code-1.38.1.tgz",
7
7
  "modelCount": 65,
package/models.json CHANGED
@@ -21,6 +21,16 @@
21
21
  "limit": {
22
22
  "context": 1000000,
23
23
  "output": 65536
24
+ },
25
+ "attachment": true,
26
+ "modalities": {
27
+ "input": [
28
+ "text",
29
+ "image"
30
+ ],
31
+ "output": [
32
+ "text"
33
+ ]
24
34
  }
25
35
  },
26
36
  {
@@ -38,6 +48,17 @@
38
48
  "limit": {
39
49
  "context": 200000,
40
50
  "output": 8192
51
+ },
52
+ "attachment": true,
53
+ "modalities": {
54
+ "input": [
55
+ "text",
56
+ "image",
57
+ "pdf"
58
+ ],
59
+ "output": [
60
+ "text"
61
+ ]
41
62
  }
42
63
  },
43
64
  {
@@ -62,6 +83,17 @@
62
83
  "limit": {
63
84
  "context": 1000000,
64
85
  "output": 32000
86
+ },
87
+ "attachment": true,
88
+ "modalities": {
89
+ "input": [
90
+ "text",
91
+ "image",
92
+ "pdf"
93
+ ],
94
+ "output": [
95
+ "text"
96
+ ]
65
97
  }
66
98
  },
67
99
  {
@@ -86,6 +118,16 @@
86
118
  "limit": {
87
119
  "context": 1000000,
88
120
  "output": 65536
121
+ },
122
+ "attachment": true,
123
+ "modalities": {
124
+ "input": [
125
+ "text",
126
+ "image"
127
+ ],
128
+ "output": [
129
+ "text"
130
+ ]
89
131
  }
90
132
  },
91
133
  {
@@ -110,6 +152,16 @@
110
152
  "limit": {
111
153
  "context": 1000000,
112
154
  "output": 65536
155
+ },
156
+ "attachment": true,
157
+ "modalities": {
158
+ "input": [
159
+ "text",
160
+ "image"
161
+ ],
162
+ "output": [
163
+ "text"
164
+ ]
113
165
  }
114
166
  },
115
167
  {
@@ -134,6 +186,17 @@
134
186
  "limit": {
135
187
  "context": 1000000,
136
188
  "output": 16000
189
+ },
190
+ "attachment": true,
191
+ "modalities": {
192
+ "input": [
193
+ "text",
194
+ "image",
195
+ "pdf"
196
+ ],
197
+ "output": [
198
+ "text"
199
+ ]
137
200
  }
138
201
  },
139
202
  {
@@ -158,6 +221,16 @@
158
221
  "limit": {
159
222
  "context": 1000000,
160
223
  "output": 65536
224
+ },
225
+ "attachment": true,
226
+ "modalities": {
227
+ "input": [
228
+ "text",
229
+ "image"
230
+ ],
231
+ "output": [
232
+ "text"
233
+ ]
161
234
  }
162
235
  },
163
236
  {
@@ -180,6 +253,16 @@
180
253
  "limit": {
181
254
  "context": 400000,
182
255
  "output": 128000
256
+ },
257
+ "attachment": true,
258
+ "modalities": {
259
+ "input": [
260
+ "text",
261
+ "image"
262
+ ],
263
+ "output": [
264
+ "text"
265
+ ]
183
266
  }
184
267
  },
185
268
  {
@@ -202,6 +285,17 @@
202
285
  "limit": {
203
286
  "context": 400000,
204
287
  "output": 128000
288
+ },
289
+ "attachment": true,
290
+ "modalities": {
291
+ "input": [
292
+ "text",
293
+ "image",
294
+ "pdf"
295
+ ],
296
+ "output": [
297
+ "text"
298
+ ]
205
299
  }
206
300
  },
207
301
  {
@@ -223,6 +317,16 @@
223
317
  "limit": {
224
318
  "context": 400000,
225
319
  "output": 128000
320
+ },
321
+ "attachment": true,
322
+ "modalities": {
323
+ "input": [
324
+ "text",
325
+ "image"
326
+ ],
327
+ "output": [
328
+ "text"
329
+ ]
226
330
  }
227
331
  },
228
332
  {
@@ -245,6 +349,16 @@
245
349
  "limit": {
246
350
  "context": 400000,
247
351
  "output": 128000
352
+ },
353
+ "attachment": true,
354
+ "modalities": {
355
+ "input": [
356
+ "text",
357
+ "image"
358
+ ],
359
+ "output": [
360
+ "text"
361
+ ]
248
362
  }
249
363
  },
250
364
  {
@@ -265,6 +379,15 @@
265
379
  "limit": {
266
380
  "context": 1000000,
267
381
  "output": 384000
382
+ },
383
+ "attachment": false,
384
+ "modalities": {
385
+ "input": [
386
+ "text"
387
+ ],
388
+ "output": [
389
+ "text"
390
+ ]
268
391
  }
269
392
  },
270
393
  {
@@ -285,6 +408,16 @@
285
408
  "limit": {
286
409
  "context": 1000000,
287
410
  "output": 65536
411
+ },
412
+ "attachment": true,
413
+ "modalities": {
414
+ "input": [
415
+ "text",
416
+ "image"
417
+ ],
418
+ "output": [
419
+ "text"
420
+ ]
288
421
  }
289
422
  },
290
423
  {
@@ -305,6 +438,15 @@
305
438
  "limit": {
306
439
  "context": 1000000,
307
440
  "output": 384000
441
+ },
442
+ "attachment": false,
443
+ "modalities": {
444
+ "input": [
445
+ "text"
446
+ ],
447
+ "output": [
448
+ "text"
449
+ ]
308
450
  }
309
451
  },
310
452
  {
@@ -325,6 +467,16 @@
325
467
  "limit": {
326
468
  "context": 1000000,
327
469
  "output": 65536
470
+ },
471
+ "attachment": true,
472
+ "modalities": {
473
+ "input": [
474
+ "text",
475
+ "image"
476
+ ],
477
+ "output": [
478
+ "text"
479
+ ]
328
480
  }
329
481
  },
330
482
  {
@@ -346,6 +498,19 @@
346
498
  "limit": {
347
499
  "context": 1000000,
348
500
  "output": 65536
501
+ },
502
+ "attachment": true,
503
+ "modalities": {
504
+ "input": [
505
+ "text",
506
+ "image",
507
+ "video",
508
+ "audio",
509
+ "pdf"
510
+ ],
511
+ "output": [
512
+ "text"
513
+ ]
349
514
  }
350
515
  },
351
516
  {
@@ -367,6 +532,19 @@
367
532
  "limit": {
368
533
  "context": 1000000,
369
534
  "output": 65536
535
+ },
536
+ "attachment": true,
537
+ "modalities": {
538
+ "input": [
539
+ "text",
540
+ "image",
541
+ "video",
542
+ "audio",
543
+ "pdf"
544
+ ],
545
+ "output": [
546
+ "text"
547
+ ]
370
548
  }
371
549
  },
372
550
  {
@@ -388,6 +566,19 @@
388
566
  "limit": {
389
567
  "context": 1000000,
390
568
  "output": 65536
569
+ },
570
+ "attachment": true,
571
+ "modalities": {
572
+ "input": [
573
+ "text",
574
+ "image",
575
+ "video",
576
+ "audio",
577
+ "pdf"
578
+ ],
579
+ "output": [
580
+ "text"
581
+ ]
391
582
  }
392
583
  },
393
584
  {
@@ -409,6 +600,19 @@
409
600
  "limit": {
410
601
  "context": 1000000,
411
602
  "output": 65536
603
+ },
604
+ "attachment": true,
605
+ "modalities": {
606
+ "input": [
607
+ "text",
608
+ "image",
609
+ "video",
610
+ "audio",
611
+ "pdf"
612
+ ],
613
+ "output": [
614
+ "text"
615
+ ]
412
616
  }
413
617
  },
414
618
  {
@@ -431,6 +635,19 @@
431
635
  "limit": {
432
636
  "context": 1048576,
433
637
  "output": 65536
638
+ },
639
+ "attachment": true,
640
+ "modalities": {
641
+ "input": [
642
+ "text",
643
+ "image",
644
+ "video",
645
+ "audio",
646
+ "pdf"
647
+ ],
648
+ "output": [
649
+ "text"
650
+ ]
434
651
  }
435
652
  },
436
653
  {
@@ -447,6 +664,15 @@
447
664
  "limit": {
448
665
  "context": 200000,
449
666
  "output": 131072
667
+ },
668
+ "attachment": false,
669
+ "modalities": {
670
+ "input": [
671
+ "text"
672
+ ],
673
+ "output": [
674
+ "text"
675
+ ]
450
676
  }
451
677
  },
452
678
  {
@@ -463,6 +689,15 @@
463
689
  "limit": {
464
690
  "context": 200000,
465
691
  "output": 131072
692
+ },
693
+ "attachment": false,
694
+ "modalities": {
695
+ "input": [
696
+ "text"
697
+ ],
698
+ "output": [
699
+ "text"
700
+ ]
466
701
  }
467
702
  },
468
703
  {
@@ -483,6 +718,15 @@
483
718
  "limit": {
484
719
  "context": 1000000,
485
720
  "output": 65536
721
+ },
722
+ "attachment": false,
723
+ "modalities": {
724
+ "input": [
725
+ "text"
726
+ ],
727
+ "output": [
728
+ "text"
729
+ ]
486
730
  }
487
731
  },
488
732
  {
@@ -499,6 +743,16 @@
499
743
  "limit": {
500
744
  "context": 1000000,
501
745
  "output": 65536
746
+ },
747
+ "attachment": true,
748
+ "modalities": {
749
+ "input": [
750
+ "text",
751
+ "image"
752
+ ],
753
+ "output": [
754
+ "text"
755
+ ]
502
756
  }
503
757
  },
504
758
  {
@@ -520,6 +774,15 @@
520
774
  "limit": {
521
775
  "context": 1000000,
522
776
  "output": 65536
777
+ },
778
+ "attachment": false,
779
+ "modalities": {
780
+ "input": [
781
+ "text"
782
+ ],
783
+ "output": [
784
+ "text"
785
+ ]
523
786
  }
524
787
  },
525
788
  {
@@ -540,7 +803,18 @@
540
803
  },
541
804
  "limit": {
542
805
  "context": 1048576,
543
- "output": 65536
806
+ "output": 131072
807
+ },
808
+ "attachment": true,
809
+ "modalities": {
810
+ "input": [
811
+ "text",
812
+ "image",
813
+ "video"
814
+ ],
815
+ "output": [
816
+ "text"
817
+ ]
544
818
  }
545
819
  },
546
820
  {
@@ -565,6 +839,16 @@
565
839
  "limit": {
566
840
  "context": 1050000,
567
841
  "output": 65536
842
+ },
843
+ "attachment": true,
844
+ "modalities": {
845
+ "input": [
846
+ "text",
847
+ "image"
848
+ ],
849
+ "output": [
850
+ "text"
851
+ ]
568
852
  }
569
853
  },
570
854
  {
@@ -589,6 +873,16 @@
589
873
  "limit": {
590
874
  "context": 1050000,
591
875
  "output": 65536
876
+ },
877
+ "attachment": true,
878
+ "modalities": {
879
+ "input": [
880
+ "text",
881
+ "image"
882
+ ],
883
+ "output": [
884
+ "text"
885
+ ]
592
886
  }
593
887
  },
594
888
  {
@@ -613,6 +907,16 @@
613
907
  "limit": {
614
908
  "context": 1050000,
615
909
  "output": 65536
910
+ },
911
+ "attachment": true,
912
+ "modalities": {
913
+ "input": [
914
+ "text",
915
+ "image"
916
+ ],
917
+ "output": [
918
+ "text"
919
+ ]
616
920
  }
617
921
  },
618
922
  {
@@ -634,6 +938,16 @@
634
938
  "limit": {
635
939
  "context": 500000,
636
940
  "output": 65536
941
+ },
942
+ "attachment": true,
943
+ "modalities": {
944
+ "input": [
945
+ "text",
946
+ "image"
947
+ ],
948
+ "output": [
949
+ "text"
950
+ ]
637
951
  }
638
952
  },
639
953
  {
@@ -656,6 +970,16 @@
656
970
  "limit": {
657
971
  "context": 500000,
658
972
  "output": 65536
973
+ },
974
+ "attachment": true,
975
+ "modalities": {
976
+ "input": [
977
+ "text",
978
+ "image"
979
+ ],
980
+ "output": [
981
+ "text"
982
+ ]
659
983
  }
660
984
  },
661
985
  {
@@ -672,6 +996,16 @@
672
996
  "limit": {
673
997
  "context": 256000,
674
998
  "output": 65536
999
+ },
1000
+ "attachment": true,
1001
+ "modalities": {
1002
+ "input": [
1003
+ "text",
1004
+ "image"
1005
+ ],
1006
+ "output": [
1007
+ "text"
1008
+ ]
675
1009
  }
676
1010
  },
677
1011
  {
@@ -688,6 +1022,16 @@
688
1022
  "limit": {
689
1023
  "context": 1000000,
690
1024
  "output": 65536
1025
+ },
1026
+ "attachment": true,
1027
+ "modalities": {
1028
+ "input": [
1029
+ "text",
1030
+ "image"
1031
+ ],
1032
+ "output": [
1033
+ "text"
1034
+ ]
691
1035
  }
692
1036
  },
693
1037
  {
@@ -704,6 +1048,16 @@
704
1048
  "limit": {
705
1049
  "context": 256000,
706
1050
  "output": 131072
1051
+ },
1052
+ "attachment": true,
1053
+ "modalities": {
1054
+ "input": [
1055
+ "text",
1056
+ "image"
1057
+ ],
1058
+ "output": [
1059
+ "text"
1060
+ ]
707
1061
  }
708
1062
  },
709
1063
  {
@@ -720,6 +1074,17 @@
720
1074
  "limit": {
721
1075
  "context": 256000,
722
1076
  "output": 131072
1077
+ },
1078
+ "attachment": true,
1079
+ "modalities": {
1080
+ "input": [
1081
+ "text",
1082
+ "image",
1083
+ "video"
1084
+ ],
1085
+ "output": [
1086
+ "text"
1087
+ ]
723
1088
  }
724
1089
  },
725
1090
  {
@@ -736,6 +1101,17 @@
736
1101
  "limit": {
737
1102
  "context": 256000,
738
1103
  "output": 65536
1104
+ },
1105
+ "attachment": true,
1106
+ "modalities": {
1107
+ "input": [
1108
+ "text",
1109
+ "image",
1110
+ "video"
1111
+ ],
1112
+ "output": [
1113
+ "text"
1114
+ ]
739
1115
  }
740
1116
  },
741
1117
  {
@@ -752,6 +1128,16 @@
752
1128
  "limit": {
753
1129
  "context": 262000,
754
1130
  "output": 65536
1131
+ },
1132
+ "attachment": true,
1133
+ "modalities": {
1134
+ "input": [
1135
+ "text",
1136
+ "image"
1137
+ ],
1138
+ "output": [
1139
+ "text"
1140
+ ]
755
1141
  }
756
1142
  },
757
1143
  {
@@ -768,6 +1154,17 @@
768
1154
  "limit": {
769
1155
  "context": 1000000,
770
1156
  "output": 65536
1157
+ },
1158
+ "attachment": true,
1159
+ "modalities": {
1160
+ "input": [
1161
+ "text",
1162
+ "image",
1163
+ "video"
1164
+ ],
1165
+ "output": [
1166
+ "text"
1167
+ ]
771
1168
  }
772
1169
  },
773
1170
  {
@@ -783,7 +1180,16 @@
783
1180
  },
784
1181
  "limit": {
785
1182
  "context": 256000,
786
- "output": 65536
1183
+ "output": 32768
1184
+ },
1185
+ "attachment": false,
1186
+ "modalities": {
1187
+ "input": [
1188
+ "text"
1189
+ ],
1190
+ "output": [
1191
+ "text"
1192
+ ]
787
1193
  }
788
1194
  },
789
1195
  {
@@ -798,7 +1204,16 @@
798
1204
  },
799
1205
  "limit": {
800
1206
  "context": 256000,
801
- "output": 65536
1207
+ "output": 32768
1208
+ },
1209
+ "attachment": false,
1210
+ "modalities": {
1211
+ "input": [
1212
+ "text"
1213
+ ],
1214
+ "output": [
1215
+ "text"
1216
+ ]
802
1217
  }
803
1218
  },
804
1219
  {
@@ -815,6 +1230,18 @@
815
1230
  "limit": {
816
1231
  "context": 1000000,
817
1232
  "output": 65536
1233
+ },
1234
+ "attachment": true,
1235
+ "modalities": {
1236
+ "input": [
1237
+ "text",
1238
+ "image",
1239
+ "audio",
1240
+ "video"
1241
+ ],
1242
+ "output": [
1243
+ "text"
1244
+ ]
818
1245
  }
819
1246
  },
820
1247
  {
@@ -831,6 +1258,15 @@
831
1258
  "limit": {
832
1259
  "context": 1000000,
833
1260
  "output": 65536
1261
+ },
1262
+ "attachment": false,
1263
+ "modalities": {
1264
+ "input": [
1265
+ "text"
1266
+ ],
1267
+ "output": [
1268
+ "text"
1269
+ ]
834
1270
  }
835
1271
  },
836
1272
  {
@@ -847,6 +1283,15 @@
847
1283
  "limit": {
848
1284
  "context": 200000,
849
1285
  "output": 131072
1286
+ },
1287
+ "attachment": false,
1288
+ "modalities": {
1289
+ "input": [
1290
+ "text"
1291
+ ],
1292
+ "output": [
1293
+ "text"
1294
+ ]
850
1295
  }
851
1296
  },
852
1297
  {
@@ -863,6 +1308,15 @@
863
1308
  "limit": {
864
1309
  "context": 1000000,
865
1310
  "output": 131072
1311
+ },
1312
+ "attachment": false,
1313
+ "modalities": {
1314
+ "input": [
1315
+ "text"
1316
+ ],
1317
+ "output": [
1318
+ "text"
1319
+ ]
866
1320
  }
867
1321
  },
868
1322
  {
@@ -878,6 +1332,15 @@
878
1332
  "limit": {
879
1333
  "context": 197000,
880
1334
  "output": 65536
1335
+ },
1336
+ "attachment": false,
1337
+ "modalities": {
1338
+ "input": [
1339
+ "text"
1340
+ ],
1341
+ "output": [
1342
+ "text"
1343
+ ]
881
1344
  }
882
1345
  },
883
1346
  {
@@ -894,6 +1357,17 @@
894
1357
  "limit": {
895
1358
  "context": 1000000,
896
1359
  "output": 65536
1360
+ },
1361
+ "attachment": true,
1362
+ "modalities": {
1363
+ "input": [
1364
+ "text",
1365
+ "image",
1366
+ "video"
1367
+ ],
1368
+ "output": [
1369
+ "text"
1370
+ ]
897
1371
  }
898
1372
  },
899
1373
  {
@@ -909,6 +1383,17 @@
909
1383
  "limit": {
910
1384
  "context": 1000000,
911
1385
  "output": 65536
1386
+ },
1387
+ "attachment": true,
1388
+ "modalities": {
1389
+ "input": [
1390
+ "text",
1391
+ "image",
1392
+ "video"
1393
+ ],
1394
+ "output": [
1395
+ "text"
1396
+ ]
912
1397
  }
913
1398
  },
914
1399
  {
@@ -924,6 +1409,16 @@
924
1409
  "limit": {
925
1410
  "context": 1000000,
926
1411
  "output": 65536
1412
+ },
1413
+ "attachment": true,
1414
+ "modalities": {
1415
+ "input": [
1416
+ "text",
1417
+ "image"
1418
+ ],
1419
+ "output": [
1420
+ "text"
1421
+ ]
927
1422
  }
928
1423
  },
929
1424
  {
@@ -940,6 +1435,19 @@
940
1435
  "limit": {
941
1436
  "context": 1048576,
942
1437
  "output": 65536
1438
+ },
1439
+ "attachment": true,
1440
+ "modalities": {
1441
+ "input": [
1442
+ "text",
1443
+ "image",
1444
+ "video",
1445
+ "pdf",
1446
+ "audio"
1447
+ ],
1448
+ "output": [
1449
+ "text"
1450
+ ]
943
1451
  }
944
1452
  },
945
1453
  {
@@ -956,6 +1464,19 @@
956
1464
  "limit": {
957
1465
  "context": 1048576,
958
1466
  "output": 65536
1467
+ },
1468
+ "attachment": true,
1469
+ "modalities": {
1470
+ "input": [
1471
+ "text",
1472
+ "image",
1473
+ "video",
1474
+ "pdf",
1475
+ "audio"
1476
+ ],
1477
+ "output": [
1478
+ "text"
1479
+ ]
959
1480
  }
960
1481
  },
961
1482
  {
@@ -972,6 +1493,19 @@
972
1493
  "limit": {
973
1494
  "context": 1048576,
974
1495
  "output": 65536
1496
+ },
1497
+ "attachment": true,
1498
+ "modalities": {
1499
+ "input": [
1500
+ "text",
1501
+ "image",
1502
+ "video",
1503
+ "pdf",
1504
+ "audio"
1505
+ ],
1506
+ "output": [
1507
+ "text"
1508
+ ]
975
1509
  }
976
1510
  },
977
1511
  {
@@ -988,6 +1522,15 @@
988
1522
  "limit": {
989
1523
  "context": 1000000,
990
1524
  "output": 65536
1525
+ },
1526
+ "attachment": false,
1527
+ "modalities": {
1528
+ "input": [
1529
+ "text"
1530
+ ],
1531
+ "output": [
1532
+ "text"
1533
+ ]
991
1534
  }
992
1535
  },
993
1536
  {
@@ -1005,6 +1548,15 @@
1005
1548
  "limit": {
1006
1549
  "context": 1000000,
1007
1550
  "output": 131072
1551
+ },
1552
+ "attachment": false,
1553
+ "modalities": {
1554
+ "input": [
1555
+ "text"
1556
+ ],
1557
+ "output": [
1558
+ "text"
1559
+ ]
1008
1560
  }
1009
1561
  },
1010
1562
  {
@@ -1021,6 +1573,17 @@
1021
1573
  "limit": {
1022
1574
  "context": 1000000,
1023
1575
  "output": 131072
1576
+ },
1577
+ "attachment": true,
1578
+ "modalities": {
1579
+ "input": [
1580
+ "text",
1581
+ "image",
1582
+ "video"
1583
+ ],
1584
+ "output": [
1585
+ "text"
1586
+ ]
1024
1587
  }
1025
1588
  },
1026
1589
  {
@@ -1038,6 +1601,17 @@
1038
1601
  "limit": {
1039
1602
  "context": 1000000,
1040
1603
  "output": 65536
1604
+ },
1605
+ "attachment": true,
1606
+ "modalities": {
1607
+ "input": [
1608
+ "text",
1609
+ "image",
1610
+ "video"
1611
+ ],
1612
+ "output": [
1613
+ "text"
1614
+ ]
1041
1615
  }
1042
1616
  },
1043
1617
  {
@@ -1055,6 +1629,15 @@
1055
1629
  "limit": {
1056
1630
  "context": 1000000,
1057
1631
  "output": 131072
1632
+ },
1633
+ "attachment": false,
1634
+ "modalities": {
1635
+ "input": [
1636
+ "text"
1637
+ ],
1638
+ "output": [
1639
+ "text"
1640
+ ]
1058
1641
  }
1059
1642
  },
1060
1643
  {
@@ -1072,6 +1655,17 @@
1072
1655
  "limit": {
1073
1656
  "context": 1000000,
1074
1657
  "output": 65536
1658
+ },
1659
+ "attachment": true,
1660
+ "modalities": {
1661
+ "input": [
1662
+ "text",
1663
+ "image",
1664
+ "video"
1665
+ ],
1666
+ "output": [
1667
+ "text"
1668
+ ]
1075
1669
  }
1076
1670
  },
1077
1671
  {
@@ -1092,7 +1686,17 @@
1092
1686
  },
1093
1687
  "limit": {
1094
1688
  "context": 262144,
1095
- "output": 65536
1689
+ "output": 32768
1690
+ },
1691
+ "attachment": true,
1692
+ "modalities": {
1693
+ "input": [
1694
+ "text",
1695
+ "image"
1696
+ ],
1697
+ "output": [
1698
+ "text"
1699
+ ]
1096
1700
  }
1097
1701
  },
1098
1702
  {
@@ -1114,6 +1718,17 @@
1114
1718
  "limit": {
1115
1719
  "context": 1000000,
1116
1720
  "output": 65536
1721
+ },
1722
+ "attachment": true,
1723
+ "modalities": {
1724
+ "input": [
1725
+ "text",
1726
+ "image",
1727
+ "video"
1728
+ ],
1729
+ "output": [
1730
+ "text"
1731
+ ]
1117
1732
  }
1118
1733
  },
1119
1734
  {
@@ -1136,6 +1751,17 @@
1136
1751
  "limit": {
1137
1752
  "context": 1000000,
1138
1753
  "output": 65536
1754
+ },
1755
+ "attachment": true,
1756
+ "modalities": {
1757
+ "input": [
1758
+ "text",
1759
+ "image",
1760
+ "video"
1761
+ ],
1762
+ "output": [
1763
+ "text"
1764
+ ]
1139
1765
  }
1140
1766
  },
1141
1767
  {
@@ -1152,6 +1778,15 @@
1152
1778
  "limit": {
1153
1779
  "context": 1000000,
1154
1780
  "output": 131072
1781
+ },
1782
+ "attachment": false,
1783
+ "modalities": {
1784
+ "input": [
1785
+ "text"
1786
+ ],
1787
+ "output": [
1788
+ "text"
1789
+ ]
1155
1790
  }
1156
1791
  },
1157
1792
  {
@@ -1168,6 +1803,17 @@
1168
1803
  "limit": {
1169
1804
  "context": 256000,
1170
1805
  "output": 65536
1806
+ },
1807
+ "attachment": true,
1808
+ "modalities": {
1809
+ "input": [
1810
+ "text",
1811
+ "image",
1812
+ "video"
1813
+ ],
1814
+ "output": [
1815
+ "text"
1816
+ ]
1171
1817
  }
1172
1818
  },
1173
1819
  {
@@ -1184,6 +1830,15 @@
1184
1830
  "limit": {
1185
1831
  "context": 262144,
1186
1832
  "output": 65536
1833
+ },
1834
+ "attachment": false,
1835
+ "modalities": {
1836
+ "input": [
1837
+ "text"
1838
+ ],
1839
+ "output": [
1840
+ "text"
1841
+ ]
1187
1842
  }
1188
1843
  },
1189
1844
  {
@@ -1199,6 +1854,15 @@
1199
1854
  "limit": {
1200
1855
  "context": 262144,
1201
1856
  "output": 65536
1857
+ },
1858
+ "attachment": false,
1859
+ "modalities": {
1860
+ "input": [
1861
+ "text"
1862
+ ],
1863
+ "output": [
1864
+ "text"
1865
+ ]
1202
1866
  }
1203
1867
  },
1204
1868
  {
@@ -1220,6 +1884,15 @@
1220
1884
  "limit": {
1221
1885
  "context": 1048576,
1222
1886
  "output": 65536
1887
+ },
1888
+ "attachment": false,
1889
+ "modalities": {
1890
+ "input": [
1891
+ "text"
1892
+ ],
1893
+ "output": [
1894
+ "text"
1895
+ ]
1223
1896
  }
1224
1897
  }
1225
1898
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/opencode-commandcode",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Command Code API provider for opencode — use Claude, GPT, Gemini, DeepSeek, Qwen, Kimi, GLM, MiniMax, and Step models via Command Code",
5
5
  "keywords": [
6
6
  "ai",
@@ -69,7 +69,7 @@
69
69
  "catalog:ci": "bun run scripts/catalog-sync-ci.ts"
70
70
  },
71
71
  "devDependencies": {
72
- "@semantic-release/commit-analyzer": "13.0.1",
72
+ "@semantic-release/exec": "7.1.0",
73
73
  "@semantic-release/github": "12.0.9",
74
74
  "@semantic-release/npm": "13.1.5",
75
75
  "@semantic-release/release-notes-generator": "14.1.1",
@@ -89,9 +89,8 @@ export function renderCatalogReleaseNotes(input: CatalogReleaseInput): string {
89
89
  const sections = [
90
90
  headline(input.status),
91
91
  "",
92
- "| | |",
93
- "| --- | --- |",
94
92
  `| Plugin | ${input.pluginVersion} |`,
93
+ "| --- | --- |",
95
94
  `| Command Code | ${input.commandCodeVersion} |`,
96
95
  `| Models | ${input.modelCount} (${input.reasoningModelCount} with reasoning) |`,
97
96
  `| Prices | ${priceSummary(input.costSources)} |`,
@@ -157,9 +156,10 @@ export function renderCatalogReleaseNotes(input: CatalogReleaseInput): string {
157
156
  export function catalogReleaseNotesFromFiles(input: {
158
157
  manifest: CatalogManifest;
159
158
  models: PricedModel[];
159
+ pluginVersion?: string;
160
160
  }): string {
161
161
  return renderCatalogReleaseNotes({
162
- pluginVersion: input.manifest.pluginVersion,
162
+ pluginVersion: input.pluginVersion ?? input.manifest.pluginVersion,
163
163
  commandCodeVersion: input.manifest.commandCodeVersion,
164
164
  modelCount: input.manifest.modelCount,
165
165
  reasoningModelCount: input.manifest.reasoningModelCount,
package/src/catalog.ts CHANGED
@@ -15,6 +15,8 @@ export interface ModelEntry {
15
15
  tool_call: boolean;
16
16
  cost: { input: number; output: number; cache_read?: number; cache_write?: number };
17
17
  limit: { context: number; output: number };
18
+ attachment?: boolean;
19
+ modalities?: { input: string[]; output: string[] };
18
20
  }
19
21
 
20
22
  export interface CostEntry {
@@ -38,6 +40,8 @@ export interface SnEntry {
38
40
  reasoning?: boolean;
39
41
  reasoningEfforts?: string[];
40
42
  contextWindow?: number;
43
+ inputModalities?: string[];
44
+ maxOutputTokens?: number;
41
45
  }
42
46
 
43
47
  export interface ResolvedCommandCodePackage {
@@ -484,11 +488,21 @@ export function buildModelEntry(
484
488
  cost = { input: 0.5, output: 2 };
485
489
  }
486
490
 
487
- const limit = entry.contextWindow
488
- ? { context: entry.contextWindow, output: FALLBACK_LIMITS[entry.id]?.output ?? 65536 }
489
- : (FALLBACK_LIMITS[entry.id] ?? { context: 200000, output: 65536 });
491
+ const fallback = FALLBACK_LIMITS[entry.id];
492
+ const limit = {
493
+ context: entry.contextWindow ?? fallback?.context ?? 200000,
494
+ output: entry.maxOutputTokens ?? fallback?.output ?? 65536,
495
+ };
490
496
 
491
497
  const efforts = entry.reasoningEfforts?.length ? [...entry.reasoningEfforts] : undefined;
498
+ const input = entry.inputModalities?.filter((x) => typeof x === "string") ?? [];
499
+ const fromCli =
500
+ input.length > 0
501
+ ? {
502
+ attachment: input.includes("image"),
503
+ modalities: { input: [...input], output: ["text"] },
504
+ }
505
+ : {};
492
506
 
493
507
  return {
494
508
  id: entry.id,
@@ -499,6 +513,7 @@ export function buildModelEntry(
499
513
  tool_call: true,
500
514
  cost,
501
515
  limit,
516
+ ...fromCli,
502
517
  };
503
518
  }
504
519
 
@@ -740,6 +755,8 @@ export function generateOpencodeModels(entries: ModelEntry[]): Record<string, un
740
755
  name: entry.name,
741
756
  reasoning: entry.reasoning,
742
757
  tool_call: entry.tool_call,
758
+ attachment: entry.attachment ?? false,
759
+ modalities: entry.modalities ?? { input: ["text"], output: ["text"] },
743
760
  cost: costObj,
744
761
  limit: entry.limit,
745
762
  };
@@ -2,17 +2,22 @@ import type { ModelEntry } from "./catalog.js";
2
2
 
3
3
  export const MODELS_DEV_URL = "https://models.dev/api.json";
4
4
  export const FREE_COST = { input: 0, output: 0 } as const;
5
+ export const TEXT_ONLY_MODALITIES = { input: ["text"], output: ["text"] } as const;
5
6
 
6
7
  export type ModelsDevRow = {
7
8
  id: string;
8
9
  name: string;
9
10
  cost: { input: number; output: number; cache_read?: number; cache_write?: number };
11
+ attachment?: boolean;
12
+ modalities?: { input: string[]; output: string[] };
10
13
  };
11
14
 
12
15
  type ModelsDevModel = {
13
16
  id?: string;
14
17
  name?: string;
15
18
  cost?: { input?: number; output?: number; cache_read?: number; cache_write?: number };
19
+ attachment?: boolean;
20
+ modalities?: { input?: string[]; output?: string[] };
16
21
  };
17
22
 
18
23
  type ModelsDevProvider = { models?: Record<string, ModelsDevModel> };
@@ -42,7 +47,17 @@ export function parseModelsDev(json: string): ModelsDevRow[] {
42
47
  const cost: ModelsDevRow["cost"] = { input: model.cost.input, output: model.cost.output };
43
48
  if (model.cost.cache_read !== undefined) cost.cache_read = model.cost.cache_read;
44
49
  if (model.cost.cache_write !== undefined) cost.cache_write = model.cost.cache_write;
45
- rows.push({ id: model.id, name: model.name ?? model.id, cost });
50
+ const row: ModelsDevRow = { id: model.id, name: model.name ?? model.id, cost };
51
+ if (typeof model.attachment === "boolean") row.attachment = model.attachment;
52
+ const input = model.modalities?.input?.filter((x) => typeof x === "string");
53
+ const output = model.modalities?.output?.filter((x) => typeof x === "string");
54
+ if (input?.length || output?.length) {
55
+ row.modalities = {
56
+ input: input?.length ? input : [...TEXT_ONLY_MODALITIES.input],
57
+ output: output?.length ? output : [...TEXT_ONLY_MODALITIES.output],
58
+ };
59
+ }
60
+ rows.push(row);
46
61
  }
47
62
  }
48
63
  return rows;
@@ -86,6 +101,43 @@ export function applyFreeCosts(
86
101
  return filled;
87
102
  }
88
103
 
104
+ function textOnly(): { input: string[]; output: string[] } {
105
+ return { input: [...TEXT_ONLY_MODALITIES.input], output: [...TEXT_ONLY_MODALITIES.output] };
106
+ }
107
+
108
+ export function applyModelsDevModalities(models: ModelEntry[], rows: ModelsDevRow[]): number {
109
+ const index = indexRows(rows);
110
+ let filled = 0;
111
+ for (const model of models) {
112
+ const row = findRow(model, index);
113
+ const current = model.modalities;
114
+ if (current && model.attachment !== undefined) {
115
+ const extra = row?.modalities?.input?.filter((x) => !current.input.includes(x)) ?? [];
116
+ if (extra.length > 0) {
117
+ model.modalities = {
118
+ input: [...current.input, ...extra],
119
+ output: [...current.output],
120
+ };
121
+ if (model.modalities.input.includes("image")) model.attachment = true;
122
+ filled++;
123
+ }
124
+ continue;
125
+ }
126
+ if (row && (row.modalities || row.attachment !== undefined)) {
127
+ const modalities = row.modalities
128
+ ? { input: [...row.modalities.input], output: [...row.modalities.output] }
129
+ : textOnly();
130
+ model.modalities = modalities;
131
+ model.attachment = row.attachment ?? modalities.input.includes("image");
132
+ filled++;
133
+ } else {
134
+ model.attachment = false;
135
+ model.modalities = textOnly();
136
+ }
137
+ }
138
+ return filled;
139
+ }
140
+
89
141
  export function applyModelsDevCosts(
90
142
  models: ModelEntry[],
91
143
  rows: ModelsDevRow[],
@@ -0,0 +1,40 @@
1
+ const UNRELEASED = /^## \[Unreleased\]\s*$/;
2
+ const VERSION = /^## \[/;
3
+
4
+ export function cutKeepAChangelog(markdown: string, version: string, date: string): string {
5
+ if (new RegExp(`^## \\[${escapeRegExp(version)}\\]`, "m").test(markdown)) return markdown;
6
+
7
+ const lines = markdown.split(/(?<=\n)/);
8
+ let start: number | null = null;
9
+ for (let i = 0; i < lines.length; i++) {
10
+ const line = lines[i];
11
+ if (line !== undefined && UNRELEASED.test(line.replace(/\n$/, ""))) {
12
+ start = i;
13
+ break;
14
+ }
15
+ }
16
+ if (start === null) throw new Error("CHANGELOG.md has no ## [Unreleased] heading");
17
+
18
+ let end = lines.length;
19
+ for (let j = start + 1; j < lines.length; j++) {
20
+ const line = lines[j];
21
+ if (line === undefined) continue;
22
+ const stripped = line.replace(/\n$/, "");
23
+ if (VERSION.test(stripped) && !UNRELEASED.test(stripped)) {
24
+ end = j;
25
+ break;
26
+ }
27
+ }
28
+
29
+ const before = lines.slice(0, start + 1).join("");
30
+ const body = lines
31
+ .slice(start + 1, end)
32
+ .join("")
33
+ .replace(/^\n+/, "\n");
34
+ const after = lines.slice(end).join("");
35
+ return `${before}\n## [${version}] - ${date}\n${body}${after}`;
36
+ }
37
+
38
+ function escapeRegExp(value: string): string {
39
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
40
+ }