openrouter-genimage-kote-opencode 0.1.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.
Files changed (163) hide show
  1. package/.opencode/skills/openrouter-image-generation/SKILL.md +379 -0
  2. package/CHANGELOG.md +10 -0
  3. package/LICENSE +21 -0
  4. package/README.md +229 -0
  5. package/README.ru.md +229 -0
  6. package/SECURITY.md +31 -0
  7. package/THIRD_PARTY_NOTICES.md +16 -0
  8. package/dist/cli.d.ts +20 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +277 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/commands/balance-command.d.ts +5 -0
  13. package/dist/commands/balance-command.d.ts.map +1 -0
  14. package/dist/commands/balance-command.js +20 -0
  15. package/dist/commands/balance-command.js.map +1 -0
  16. package/dist/config/resolve.d.ts +5 -0
  17. package/dist/config/resolve.d.ts.map +1 -0
  18. package/dist/config/resolve.js +113 -0
  19. package/dist/config/resolve.js.map +1 -0
  20. package/dist/config/schema.d.ts +188 -0
  21. package/dist/config/schema.d.ts.map +1 -0
  22. package/dist/config/schema.js +144 -0
  23. package/dist/config/schema.js.map +1 -0
  24. package/dist/config/types.d.ts +75 -0
  25. package/dist/config/types.d.ts.map +1 -0
  26. package/dist/config/types.js +30 -0
  27. package/dist/config/types.js.map +1 -0
  28. package/dist/logging.d.ts +46 -0
  29. package/dist/logging.d.ts.map +1 -0
  30. package/dist/logging.js +58 -0
  31. package/dist/logging.js.map +1 -0
  32. package/dist/openrouter/capabilities.d.ts +22 -0
  33. package/dist/openrouter/capabilities.d.ts.map +1 -0
  34. package/dist/openrouter/capabilities.js +137 -0
  35. package/dist/openrouter/capabilities.js.map +1 -0
  36. package/dist/openrouter/client.d.ts +54 -0
  37. package/dist/openrouter/client.d.ts.map +1 -0
  38. package/dist/openrouter/client.js +440 -0
  39. package/dist/openrouter/client.js.map +1 -0
  40. package/dist/openrouter/errors.d.ts +22 -0
  41. package/dist/openrouter/errors.d.ts.map +1 -0
  42. package/dist/openrouter/errors.js +75 -0
  43. package/dist/openrouter/errors.js.map +1 -0
  44. package/dist/openrouter/models.d.ts +37 -0
  45. package/dist/openrouter/models.d.ts.map +1 -0
  46. package/dist/openrouter/models.js +113 -0
  47. package/dist/openrouter/models.js.map +1 -0
  48. package/dist/openrouter/requests.d.ts +6 -0
  49. package/dist/openrouter/requests.d.ts.map +1 -0
  50. package/dist/openrouter/requests.js +74 -0
  51. package/dist/openrouter/requests.js.map +1 -0
  52. package/dist/openrouter/schemas.d.ts +37 -0
  53. package/dist/openrouter/schemas.d.ts.map +1 -0
  54. package/dist/openrouter/schemas.js +2 -0
  55. package/dist/openrouter/schemas.js.map +1 -0
  56. package/dist/output/attachments.d.ts +10 -0
  57. package/dist/output/attachments.d.ts.map +1 -0
  58. package/dist/output/attachments.js +13 -0
  59. package/dist/output/attachments.js.map +1 -0
  60. package/dist/output/formats.d.ts +42 -0
  61. package/dist/output/formats.d.ts.map +1 -0
  62. package/dist/output/formats.js +126 -0
  63. package/dist/output/formats.js.map +1 -0
  64. package/dist/output/index.d.ts +5 -0
  65. package/dist/output/index.d.ts.map +1 -0
  66. package/dist/output/index.js +5 -0
  67. package/dist/output/index.js.map +1 -0
  68. package/dist/output/paths.d.ts +38 -0
  69. package/dist/output/paths.d.ts.map +1 -0
  70. package/dist/output/paths.js +296 -0
  71. package/dist/output/paths.js.map +1 -0
  72. package/dist/output/writer.d.ts +33 -0
  73. package/dist/output/writer.d.ts.map +1 -0
  74. package/dist/output/writer.js +176 -0
  75. package/dist/output/writer.js.map +1 -0
  76. package/dist/references/attachments.d.ts +82 -0
  77. package/dist/references/attachments.d.ts.map +1 -0
  78. package/dist/references/attachments.js +238 -0
  79. package/dist/references/attachments.js.map +1 -0
  80. package/dist/references/data-url.d.ts +12 -0
  81. package/dist/references/data-url.d.ts.map +1 -0
  82. package/dist/references/data-url.js +75 -0
  83. package/dist/references/data-url.js.map +1 -0
  84. package/dist/references/formats.d.ts +13 -0
  85. package/dist/references/formats.d.ts.map +1 -0
  86. package/dist/references/formats.js +50 -0
  87. package/dist/references/formats.js.map +1 -0
  88. package/dist/references/index.d.ts +7 -0
  89. package/dist/references/index.d.ts.map +1 -0
  90. package/dist/references/index.js +7 -0
  91. package/dist/references/index.js.map +1 -0
  92. package/dist/references/limits.d.ts +15 -0
  93. package/dist/references/limits.d.ts.map +1 -0
  94. package/dist/references/limits.js +62 -0
  95. package/dist/references/limits.js.map +1 -0
  96. package/dist/references/project-files.d.ts +13 -0
  97. package/dist/references/project-files.d.ts.map +1 -0
  98. package/dist/references/project-files.js +148 -0
  99. package/dist/references/project-files.js.map +1 -0
  100. package/dist/references/remote-urls.d.ts +3 -0
  101. package/dist/references/remote-urls.d.ts.map +1 -0
  102. package/dist/references/remote-urls.js +22 -0
  103. package/dist/references/remote-urls.js.map +1 -0
  104. package/dist/server.d.ts +8 -0
  105. package/dist/server.d.ts.map +1 -0
  106. package/dist/server.js +97 -0
  107. package/dist/server.js.map +1 -0
  108. package/dist/tools/balance.d.ts +8 -0
  109. package/dist/tools/balance.d.ts.map +1 -0
  110. package/dist/tools/balance.js +133 -0
  111. package/dist/tools/balance.js.map +1 -0
  112. package/dist/tools/common.d.ts +3 -0
  113. package/dist/tools/common.d.ts.map +1 -0
  114. package/dist/tools/common.js +18 -0
  115. package/dist/tools/common.js.map +1 -0
  116. package/dist/tools/edit-image.d.ts +90 -0
  117. package/dist/tools/edit-image.d.ts.map +1 -0
  118. package/dist/tools/edit-image.js +47 -0
  119. package/dist/tools/edit-image.js.map +1 -0
  120. package/dist/tools/generate-image.d.ts +70 -0
  121. package/dist/tools/generate-image.d.ts.map +1 -0
  122. package/dist/tools/generate-image.js +36 -0
  123. package/dist/tools/generate-image.js.map +1 -0
  124. package/dist/tools/generation.d.ts +19 -0
  125. package/dist/tools/generation.d.ts.map +1 -0
  126. package/dist/tools/generation.js +154 -0
  127. package/dist/tools/generation.js.map +1 -0
  128. package/dist/tools/schema.d.ts +127 -0
  129. package/dist/tools/schema.d.ts.map +1 -0
  130. package/dist/tools/schema.js +47 -0
  131. package/dist/tools/schema.js.map +1 -0
  132. package/dist/tools/types.d.ts +18 -0
  133. package/dist/tools/types.d.ts.map +1 -0
  134. package/dist/tools/types.js +2 -0
  135. package/dist/tools/types.js.map +1 -0
  136. package/dist/transport/direct.d.ts +10 -0
  137. package/dist/transport/direct.d.ts.map +1 -0
  138. package/dist/transport/direct.js +15 -0
  139. package/dist/transport/direct.js.map +1 -0
  140. package/dist/transport/index.d.ts +4 -0
  141. package/dist/transport/index.d.ts.map +1 -0
  142. package/dist/transport/index.js +4 -0
  143. package/dist/transport/index.js.map +1 -0
  144. package/dist/transport/kote-gateway.d.ts +19 -0
  145. package/dist/transport/kote-gateway.d.ts.map +1 -0
  146. package/dist/transport/kote-gateway.js +224 -0
  147. package/dist/transport/kote-gateway.js.map +1 -0
  148. package/dist/transport/types.d.ts +10 -0
  149. package/dist/transport/types.d.ts.map +1 -0
  150. package/dist/transport/types.js +9 -0
  151. package/dist/transport/types.js.map +1 -0
  152. package/dist/utils/abort.d.ts +19 -0
  153. package/dist/utils/abort.d.ts.map +1 -0
  154. package/dist/utils/abort.js +121 -0
  155. package/dist/utils/abort.js.map +1 -0
  156. package/docs/architecture.md +75 -0
  157. package/docs/configuration.md +110 -0
  158. package/docs/image-to-image.md +101 -0
  159. package/docs/security.md +49 -0
  160. package/docs/testing.md +81 -0
  161. package/docs/troubleshooting.md +73 -0
  162. package/package.json +88 -0
  163. package/schema/plugin-options.schema.json +182 -0
@@ -0,0 +1,379 @@
1
+ ---
2
+ name: openrouter-image-generation
3
+ description: Use when the user explicitly asks to generate, create, draw, render, edit, transform, redraw, or restyle an image, or requests new visual assets for a project.
4
+ license: MIT
5
+ compatibility: opencode
6
+ metadata:
7
+ plugin: openrouter-genimage-kote-opencode
8
+ edit-tool: openrouter_edit_image
9
+ generate-tool: openrouter_generate_image
10
+ ---
11
+
12
+ # OpenRouter Image Generation
13
+
14
+ Use the image tools provided by `openrouter-genimage-kote-opencode`.
15
+
16
+ Image-to-image is the primary workflow.
17
+
18
+ ## Available tools
19
+
20
+ ### `openrouter_edit_image`
21
+
22
+ Use when one or more existing images should influence the result.
23
+
24
+ Typical scenarios:
25
+
26
+ - edit an attached image;
27
+ - redraw or restyle an image;
28
+ - create a variation;
29
+ - change the background;
30
+ - recolor an asset;
31
+ - add or remove an object;
32
+ - preserve a character while changing the pose;
33
+ - preserve an object while changing its state;
34
+ - create another asset in the same style;
35
+ - use several visual references;
36
+ - create a new asset based on an existing image.
37
+
38
+ ### `openrouter_generate_image`
39
+
40
+ Use only when the user requests a completely new image and no existing image
41
+ needs to be preserved or used as a visual reference.
42
+
43
+ ## When to use image tools
44
+
45
+ Use an image tool when:
46
+
47
+ 1. The user explicitly asks to generate, create, draw, render, edit, transform,
48
+ redraw, or restyle an image.
49
+ 2. The user requests new visual assets.
50
+ 3. The user requests game assets such as:
51
+ - characters;
52
+ - sprites;
53
+ - inventory icons;
54
+ - ability icons;
55
+ - textures;
56
+ - backgrounds;
57
+ - environment art;
58
+ - concept art;
59
+ - loading screens;
60
+ - promotional art.
61
+ 4. The user requests application or website assets such as:
62
+ - UI illustrations;
63
+ - empty-state illustrations;
64
+ - thumbnails;
65
+ - banners;
66
+ - avatars;
67
+ - hero images;
68
+ - decorative graphics.
69
+ 5. The user attaches an image and requests a visible change.
70
+
71
+ The request may be written in any language. Follow the user's intent rather
72
+ than relying on exact English trigger words.
73
+
74
+ ## When not to use image tools
75
+
76
+ Do not call image tools when:
77
+
78
+ - the user only asks to discuss an idea;
79
+ - the user asks to analyze an image without changing it;
80
+ - the user asks to find an existing image online;
81
+ - the user asks for factual information about an image;
82
+ - the task should be solved with deterministic SVG, HTML, CSS, a chart, or a
83
+ technical diagram;
84
+ - the user did not request a new or modified visual result.
85
+
86
+ Do not call `openrouter_balance` after every generation. Use it only when the
87
+ user asks about balance, usage, credits, spending, or limits.
88
+
89
+ ## Choosing the correct tool
90
+
91
+ Use `openrouter_edit_image` when:
92
+
93
+ - an image is attached;
94
+ - the user references an image inside the project;
95
+ - the user provides an image URL;
96
+ - the user asks to preserve visual properties;
97
+ - the user asks for a variation;
98
+ - the user asks to match an existing style.
99
+
100
+ Use `openrouter_generate_image` when:
101
+
102
+ - the user requests a completely new image;
103
+ - no visual reference is required;
104
+ - nothing from an existing image must be preserved.
105
+
106
+ When the user attaches images and asks to edit "this image", omit the
107
+ `references` argument. The tool will use all image attachments from the current
108
+ user message.
109
+
110
+ When only some attached images should be used, pass explicit attachment
111
+ indexes.
112
+
113
+ ## Image-to-image prompt structure
114
+
115
+ Clearly separate:
116
+
117
+ 1. The role of every reference.
118
+ 2. What must be preserved.
119
+ 3. What must be changed.
120
+ 4. What may change if necessary.
121
+ 5. What must not appear.
122
+ 6. The intended use of the result.
123
+
124
+ Recommended structure:
125
+
126
+ > Reference image 1 is the primary source.
127
+ >
128
+ > Preserve: [identity, face, hairstyle, silhouette, proportions, camera angle,
129
+ > composition, art style, palette, lighting, materials].
130
+ >
131
+ > Change: [specific requested changes].
132
+ >
133
+ > Final result: [pose, composition, background, framing, asset purpose].
134
+ >
135
+ > Avoid: [unwanted changes or additions].
136
+
137
+ Do not describe the entire source image from scratch when the user wants most
138
+ of it preserved. Excessive redescription can cause the image model to replace
139
+ details that should remain unchanged.
140
+
141
+ Use explicit preservation phrases:
142
+
143
+ - preserve the same character identity;
144
+ - keep the facial features unchanged;
145
+ - preserve the original proportions;
146
+ - keep the camera angle;
147
+ - maintain the same illustration style;
148
+ - retain the original color palette;
149
+ - change only the requested element;
150
+ - do not add extra characters;
151
+ - do not crop the subject.
152
+
153
+ ## Multiple references
154
+
155
+ Always explain the role of every reference by order.
156
+
157
+ Example:
158
+
159
+ - Reference image 1: character identity and face.
160
+ - Reference image 2: clothing design only.
161
+ - Reference image 3: pose only.
162
+ - Reference image 4: visual style and color palette.
163
+ - Reference image 5: background composition.
164
+
165
+ Do not assume that the image model knows why each reference was supplied.
166
+
167
+ The first reference should normally be the primary subject.
168
+
169
+ ## Text-to-image prompt structure
170
+
171
+ Build the prompt in this order:
172
+
173
+ 1. Asset type and intended use.
174
+ 2. Main subject.
175
+ 3. Action, pose, or state.
176
+ 4. Composition, camera, viewpoint, and crop.
177
+ 5. Environment or background.
178
+ 6. Visual style and shape language.
179
+ 7. Materials and important details.
180
+ 8. Color palette and lighting.
181
+ 9. Technical constraints.
182
+ 10. Short exclusions.
183
+
184
+ Template:
185
+
186
+ > [Asset type and purpose]. [Main subject and action]. [Composition and
187
+ > viewpoint]. [Environment]. [Visual style and shape language]. [Materials and
188
+ > details]. [Palette and lighting]. [Technical constraints]. [Short
189
+ > exclusions].
190
+
191
+ ## General prompt rules
192
+
193
+ ### Be concrete
194
+
195
+ Specify:
196
+
197
+ - how many subjects are present;
198
+ - what they are doing;
199
+ - where they are positioned;
200
+ - whether the result is full-body, portrait, top-down, side-view, isometric,
201
+ or orthographic;
202
+ - whether cropping is allowed;
203
+ - what the background should contain;
204
+ - where empty space is required.
205
+
206
+ Avoid prompts consisting only of adjectives such as:
207
+
208
+ > beautiful, epic, amazing, highly detailed, cinematic
209
+
210
+ Replace vague adjectives with visible instructions.
211
+
212
+ ### State the asset purpose
213
+
214
+ Mention whether the result is:
215
+
216
+ - an inventory icon;
217
+ - a character portrait;
218
+ - a full-body character;
219
+ - a sprite;
220
+ - a side-scrolling background;
221
+ - a seamless texture;
222
+ - a loading screen;
223
+ - a UI illustration;
224
+ - a thumbnail;
225
+ - promotional art.
226
+
227
+ The purpose affects composition, padding, readability, and detail level.
228
+
229
+ ### Use tool parameters
230
+
231
+ Do not rely on prompt text alone for:
232
+
233
+ - aspect ratio;
234
+ - transparent background;
235
+ - output format;
236
+ - resolution;
237
+ - number of results.
238
+
239
+ Describe the visual requirement in the prompt and also pass the appropriate
240
+ tool arguments.
241
+
242
+ ### Transparent assets
243
+
244
+ For isolated assets:
245
+
246
+ - request one isolated subject;
247
+ - request a clean silhouette;
248
+ - leave padding around the subject;
249
+ - avoid cropped edges;
250
+ - avoid unwanted shadows extending beyond the asset;
251
+ - use PNG or WebP;
252
+ - set `background` to `transparent`.
253
+
254
+ ### Game sprites
255
+
256
+ Specify:
257
+
258
+ - side-view, front-view, top-down, or isometric orientation;
259
+ - full body and no cropping;
260
+ - neutral or explicit pose;
261
+ - consistent scale;
262
+ - readable silhouette;
263
+ - intended gameplay context.
264
+
265
+ Generate separate assets instead of a sprite sheet unless the user explicitly
266
+ requests a sprite sheet.
267
+
268
+ ### UI icons
269
+
270
+ Specify:
271
+
272
+ - one central object;
273
+ - strong silhouette;
274
+ - controlled detail;
275
+ - clear margins;
276
+ - no text;
277
+ - no watermark;
278
+ - transparent background when appropriate;
279
+ - readability at small sizes.
280
+
281
+ ### Backgrounds
282
+
283
+ Specify:
284
+
285
+ - aspect ratio;
286
+ - viewpoint;
287
+ - depth layers;
288
+ - areas that should remain visually quiet for UI overlays;
289
+ - whether characters or text must be absent.
290
+
291
+ ### Seamless textures
292
+
293
+ Explicitly request:
294
+
295
+ - seamless;
296
+ - tileable;
297
+ - uniform scale;
298
+ - no borders;
299
+ - no perspective;
300
+ - no large lighting gradient;
301
+ - no unique object that makes repetition obvious.
302
+
303
+ ### Text inside images
304
+
305
+ Keep text to a minimum.
306
+
307
+ When text is required:
308
+
309
+ - include the exact text in quotation marks;
310
+ - specify placement;
311
+ - specify typography;
312
+ - inspect the generated result;
313
+ - do not claim that the spelling is correct without checking it.
314
+
315
+ ### Consistent asset series
316
+
317
+ Preserve a reusable style block containing:
318
+
319
+ - visual medium;
320
+ - shape language;
321
+ - outline treatment;
322
+ - palette;
323
+ - lighting direction;
324
+ - camera or viewpoint;
325
+ - level of detail;
326
+ - background treatment.
327
+
328
+ Change only the subject-specific section.
329
+
330
+ Use separate tool calls for separate assets unless the user explicitly requests
331
+ a combined sheet.
332
+
333
+ ### Exclusions
334
+
335
+ Keep exclusions short and specific.
336
+
337
+ Good example:
338
+
339
+ > no text, no watermark, no additional objects, no cropped edges
340
+
341
+ Avoid long and contradictory negative-prompt lists.
342
+
343
+ ## Number of results
344
+
345
+ Generate one image by default.
346
+
347
+ Use `n > 1` only when the user explicitly requests:
348
+
349
+ - alternatives;
350
+ - variations;
351
+ - several concepts;
352
+ - multiple options.
353
+
354
+ Remember that additional images may increase cost.
355
+
356
+ ## Output path
357
+
358
+ Use an existing project asset directory when it is obvious.
359
+
360
+ Otherwise save under:
361
+
362
+ `assets/generated`
363
+
364
+ Use a meaningful filename.
365
+
366
+ Never overwrite the source image.
367
+
368
+ ## After generation
369
+
370
+ 1. Report the exact paths returned by the tool.
371
+ 2. Report how many images were requested and returned.
372
+ 3. Report the configured image model when available.
373
+ 4. Report routing mode when available.
374
+ 5. Report OpenRouter cost only when the tool provides it.
375
+ 6. Inspect returned image attachments when the active model supports image
376
+ input.
377
+ 7. Do not invent visual details that were not inspected.
378
+ 8. Do not claim success when no file was returned.
379
+ 9. Clearly report partial success and warnings.
package/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ ## 0.1.0 - 2026-08-23
6
+
7
+ - Publish the initial release.
8
+ - Add image-to-image and text-to-image OpenRouter tools for OpenCode.
9
+ - Add direct and fail-closed KoteGateway routing.
10
+ - Add balance reporting, skill installer, and package verification.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Koteyye
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 ADDED
@@ -0,0 +1,229 @@
1
+ # openrouter-genimage-kote-opencode
2
+
3
+ OpenRouter image generation and image-to-image tools for OpenCode, with optional fail-closed routing through KoteGateway. Image-to-image is the primary workflow: attached images, project files, and public HTTPS URLs are sent to the configured OpenRouter image model as ordered `input_references`. Text-to-image is also available when no visual reference is needed.
4
+
5
+ The plugin registers:
6
+
7
+ - `openrouter_edit_image` — edit or create from one or more visual references;
8
+ - `openrouter_generate_image` — create a new image from text only;
9
+ - `openrouter_balance` — show current-key usage and, when authorized, account credits;
10
+ - `/openrouter-balance` — invoke the balance tool without generating an image.
11
+
12
+ The operation may incur OpenRouter charges. The OpenRouter model, API keys, and routing mode are configuration only; they are never tool arguments.
13
+
14
+ ## Installation
15
+
16
+ Add the npm package to the `plugin` array in `opencode.jsonc`, then configure it as a tuple as shown below. OpenCode installs npm plugins referenced by its configuration.
17
+
18
+ Use permissions that ask before paid image operations while allowing balance checks:
19
+
20
+ ```jsonc
21
+ {
22
+ "$schema": "https://opencode.ai/config.json",
23
+ "permission": {
24
+ "openrouter_edit_image": "ask",
25
+ "openrouter_generate_image": "ask",
26
+ "openrouter_balance": "allow"
27
+ }
28
+ }
29
+ ```
30
+
31
+ ## Direct configuration
32
+
33
+ ```jsonc
34
+ {
35
+ "$schema": "https://opencode.ai/config.json",
36
+ "plugin": [
37
+ [
38
+ "openrouter-genimage-kote-opencode@0.1.0",
39
+ {
40
+ "routing": "direct",
41
+ "model": "openai/gpt-image-1",
42
+ "apiKey": "{env:OPENROUTER_API_KEY}",
43
+ "managementApiKey": "{env:OPENROUTER_MANAGEMENT_API_KEY}",
44
+ "outputDirectory": "assets/generated",
45
+ "defaults": {
46
+ "n": 1,
47
+ "output_format": "png"
48
+ }
49
+ }
50
+ ]
51
+ ]
52
+ }
53
+ ```
54
+
55
+ Direct mode sends HTTPS requests straight to the fixed OpenRouter API origin. It does not obtain a KoteGateway descriptor or use the gateway as a fallback.
56
+
57
+ ## Proxy configuration
58
+
59
+ ```jsonc
60
+ {
61
+ "$schema": "https://opencode.ai/config.json",
62
+ "plugin": [
63
+ [
64
+ "openrouter-genimage-kote-opencode@0.1.0",
65
+ {
66
+ "routing": "proxy",
67
+ "model": "openai/gpt-image-1",
68
+ "apiKey": "{env:OPENROUTER_API_KEY}",
69
+ "outputDirectory": "assets/generated",
70
+ "input": {
71
+ "maxReferences": 16,
72
+ "maxFileBytes": 20971520,
73
+ "maxTotalBytes": 52428800
74
+ },
75
+ "requestTimeoutMs": 300000
76
+ }
77
+ ]
78
+ ]
79
+ }
80
+ ```
81
+
82
+ Proxy mode obtains a signed KoteGateway descriptor and uses an HTTPS CONNECT tunnel for every OpenRouter endpoint used by this plugin. It is fail-closed: bootstrap, signature, CONNECT, or proxy timeout errors end the request and never trigger a direct retry. OpenRouter keys, prompts, references, and results remain inside the TLS connection to OpenRouter and are not proxy headers.
83
+
84
+ ## API keys
85
+
86
+ Create an OpenRouter generation key and expose it as `OPENROUTER_API_KEY`. Resolution order is `apiKey` in plugin options, then the environment variable. An absent key produces `GENIMAGE_OPENROUTER_KEY_MISSING` before any paid request.
87
+
88
+ Full account credits require a management key. Set `managementApiKey` or `OPENROUTER_MANAGEMENT_API_KEY`. The generation key may be used for credits only if `/key` explicitly reports that it is a management key. Do not commit either key to `opencode.jsonc`; use OpenCode's `{env:NAME}` substitution.
89
+
90
+ ## Choosing an image model
91
+
92
+ Set `model` to an OpenRouter image-model ID. The model is deliberately not exposed to tools, so an agent cannot silently select a different or more expensive model. Before the first paid request, the plugin discovers image-model capabilities and checks image output, image input for edit calls, and requested parameters. It does not substitute another model when a capability is missing.
93
+
94
+ Provider support can be narrower than the OpenRouter API limits. In particular, a provider may accept fewer results or fewer parameters than another endpoint for the same model.
95
+
96
+ ## Image-to-image (primary workflow)
97
+
98
+ `openrouter_edit_image` requires at least one image input. It never falls back to text-to-image. If `references` is omitted, the plugin uses all image attachments from the parent user message, in their original order. If none exist, it returns `GENIMAGE_REFERENCE_REQUIRED`.
99
+
100
+ ### Attached images
101
+
102
+ Attach one or more images to the current user message and ask OpenCode to edit them. To select specific image attachments, references use one-based indexing among image attachments only:
103
+
104
+ ```json
105
+ {
106
+ "prompt": "Reference image 1 defines the character. Reference image 2 defines clothing only. Preserve the face and illustration style.",
107
+ "references": [
108
+ { "type": "message_attachment", "index": 1 },
109
+ { "type": "message_attachment", "index": 2 }
110
+ ]
111
+ }
112
+ ```
113
+
114
+ The plugin supports trusted attachment representations supplied by OpenCode. It does not accept arbitrary `file:`, `data:`, or `blob:` URLs as tool arguments.
115
+
116
+ ### Project files
117
+
118
+ Paths are relative to the current OpenCode worktree:
119
+
120
+ ```json
121
+ {
122
+ "prompt": "Preserve the isometric angle, proportions, and palette. Create a damaged version with broken boards.",
123
+ "references": [
124
+ { "type": "project_file", "path": "assets/props/crate.png" }
125
+ ],
126
+ "output_path": "assets/props/crate-damaged.png"
127
+ }
128
+ ```
129
+
130
+ PNG, JPEG, and WebP inputs are accepted after size and magic-byte validation. Absolute paths, traversal, symlink escapes, directories, and files outside the worktree are rejected. Source images and existing outputs are never overwritten.
131
+
132
+ ### Multiple references and HTTPS URLs
133
+
134
+ References are sent in exactly the order supplied. The first is the primary reference; describe each reference's role in the prompt because the plugin does not reorder, combine, or infer roles.
135
+
136
+ ```json
137
+ {
138
+ "prompt": "Reference 1 defines identity and face. Reference 2 defines clothing only. Reference 3 defines palette and lighting.",
139
+ "references": [
140
+ { "type": "project_file", "path": "assets/character.png" },
141
+ { "type": "message_attachment", "index": 1 },
142
+ { "type": "https_url", "url": "https://example.com/palette.webp" }
143
+ ]
144
+ }
145
+ ```
146
+
147
+ Only public HTTPS URLs without embedded credentials are accepted. Explicit HTTPS references are passed to OpenRouter unchanged; local images are encoded in memory as base64 data URLs. No external storage service is required.
148
+
149
+ See [Image-to-image guide](docs/image-to-image.md) for prompt patterns and limits.
150
+
151
+ ## Text-to-image
152
+
153
+ Use `openrouter_generate_image` only for a completely new image with no visual reference. It accepts a prompt and output parameters, but no references, paths, attachment indexes, base64, or URLs.
154
+
155
+ ## Install the model skill
156
+
157
+ The skill ships in the npm tarball but OpenCode discovers skills from project or user skill directories. Install it explicitly:
158
+
159
+ ```bash
160
+ npx openrouter-genimage-kote-opencode install-skill
161
+ npx openrouter-genimage-kote-opencode check-skill
162
+ ```
163
+
164
+ For the user-wide directory:
165
+
166
+ ```bash
167
+ npx openrouter-genimage-kote-opencode install-skill --global
168
+ npx openrouter-genimage-kote-opencode check-skill --global
169
+ ```
170
+
171
+ Project install writes `.opencode/skills/openrouter-image-generation/SKILL.md`; global install always writes `~/.config/opencode/skills/openrouter-image-generation/SKILL.md`, including on Windows. An identical SHA-256 is a no-op. `check-skill` exits nonzero when the skill is missing or modified. Use `--force` only to atomically replace a locally modified skill. The CLI has no postinstall hook, needs no API key, and performs no network request.
172
+
173
+ ## Balance and usage
174
+
175
+ Run `/openrouter-balance` or call `openrouter_balance`. The result keeps two concepts separate:
176
+
177
+ - `/key` reports usage and the spending limit of the configured API key, including the remaining API-key limit;
178
+ - `/credits` reports total account credits and total account usage, and requires a management key.
179
+
180
+ The remaining spending limit of one key is not the OpenRouter account balance. Without management authorization, account credits are reported as unavailable. A successful `/key` response is still returned if `/credits` fails.
181
+
182
+ ## Security
183
+
184
+ - Production requests are fixed to `https://openrouter.ai/api/v1`; custom base URLs are rejected.
185
+ - Redirects are rejected. Paid `POST /images` requests are never retried automatically.
186
+ - Proxy mode is fail-closed and never retries directly.
187
+ - The plugin does not replace `globalThis.fetch` or intercept other providers.
188
+ - Keys, full prompts, base64, binary data, unredacted upstream bodies, and full URLs with query strings are excluded from logs and metadata.
189
+ - Local input and output paths are confined to the worktree; real paths are checked to prevent symlink escape.
190
+ - Output uses atomic writes and never overwrites a source or existing file.
191
+
192
+ See [Security](docs/security.md) and [SECURITY.md](SECURITY.md).
193
+
194
+ ## Version 0.1.0 limitations
195
+
196
+ No masks or pixel-local inpainting, interactive editor, LoRA training, video, streaming generation, SVG results, provider-specific options, automatic credit purchase, automatic model selection, hidden fallback, or external object storage are included. Only PNG, JPEG, and WebP raster inputs/results are supported. Seeds do not promise reproducibility across providers. OpenRouter may return fewer images than requested; valid partial results are preserved with warnings.
197
+
198
+ ## Troubleshooting
199
+
200
+ - `GENIMAGE_REFERENCE_REQUIRED`: attach an image or pass at least one ordered reference to `openrouter_edit_image`.
201
+ - `GENIMAGE_MODEL_DOES_NOT_SUPPORT_IMAGE_INPUT`: choose an image-to-image capable model in configuration; the plugin will not switch models.
202
+ - `GENIMAGE_PARAMETER_UNSUPPORTED`: remove the unsupported argument/default or choose a compatible configured model.
203
+ - `GENIMAGE_OPENROUTER_KEY_MISSING`: expose `OPENROUTER_API_KEY` to the OpenCode process or set `apiKey` through an environment substitution.
204
+ - `GENIMAGE_*_TOO_LARGE` / `GENIMAGE_TOTAL_REFERENCE_SIZE_EXCEEDED`: compress or resize inputs, use fewer references, or supply a public HTTPS URL.
205
+ - `GENIMAGE_GATEWAY_*`: repair KoteGateway/bootstrap/connectivity; proxy mode intentionally does not fall back to direct.
206
+ - Output path errors: use a relative worktree path that neither exists nor names a source image.
207
+
208
+ See the complete [Troubleshooting guide](docs/troubleshooting.md), [Configuration reference](docs/configuration.md), and [Testing guide](docs/testing.md).
209
+
210
+ ## Compatibility status
211
+
212
+ - OpenCode smoke-test baseline: **1.18.21**. CI verifies the installed npm tarball on that baseline and the latest stable release. TUI and Desktop attachment rendering still require manual release checks; Web is tested when available.
213
+ - This package consumes only the reusable `/core` export from `@koteye/kote-gateway-opencode` **0.1.1**. The gateway adapter package declares an OpenCode/SDK ceiling of **1.18.18**, so this package pins `@opencode-ai/plugin` **1.18.18** to satisfy that peer metadata. The core export does not import the OpenCode adapter at runtime, and the complete installed tarball is smoke-tested on OpenCode **1.18.21** and latest.
214
+ - Synthetic TLS/CONNECT tests pass for signed bootstrap, fail-closed routing, one CONNECT, and both plugin load orders. They complement the real OpenCode registration smokes; paid OpenRouter E2E and client UI attachment rendering remain separate opt-in/manual checks.
215
+ - Node.js 20 or newer is declared by the package. The implementation is intended to be Bun-compatible and to support Windows, macOS, and Linux; release artifacts must be tested on the supported matrix.
216
+
217
+ ## Documentation
218
+
219
+ - [Architecture](docs/architecture.md)
220
+ - [Configuration](docs/configuration.md)
221
+ - [Image-to-image](docs/image-to-image.md)
222
+ - [Security](docs/security.md)
223
+ - [Testing](docs/testing.md)
224
+ - [Troubleshooting](docs/troubleshooting.md)
225
+ - [Русская версия](README.ru.md)
226
+
227
+ ## License
228
+
229
+ MIT. See [LICENSE](LICENSE) and [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).