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.
- package/.opencode/skills/openrouter-image-generation/SKILL.md +379 -0
- package/CHANGELOG.md +10 -0
- package/LICENSE +21 -0
- package/README.md +229 -0
- package/README.ru.md +229 -0
- package/SECURITY.md +31 -0
- package/THIRD_PARTY_NOTICES.md +16 -0
- package/dist/cli.d.ts +20 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +277 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/balance-command.d.ts +5 -0
- package/dist/commands/balance-command.d.ts.map +1 -0
- package/dist/commands/balance-command.js +20 -0
- package/dist/commands/balance-command.js.map +1 -0
- package/dist/config/resolve.d.ts +5 -0
- package/dist/config/resolve.d.ts.map +1 -0
- package/dist/config/resolve.js +113 -0
- package/dist/config/resolve.js.map +1 -0
- package/dist/config/schema.d.ts +188 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +144 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/types.d.ts +75 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +30 -0
- package/dist/config/types.js.map +1 -0
- package/dist/logging.d.ts +46 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +58 -0
- package/dist/logging.js.map +1 -0
- package/dist/openrouter/capabilities.d.ts +22 -0
- package/dist/openrouter/capabilities.d.ts.map +1 -0
- package/dist/openrouter/capabilities.js +137 -0
- package/dist/openrouter/capabilities.js.map +1 -0
- package/dist/openrouter/client.d.ts +54 -0
- package/dist/openrouter/client.d.ts.map +1 -0
- package/dist/openrouter/client.js +440 -0
- package/dist/openrouter/client.js.map +1 -0
- package/dist/openrouter/errors.d.ts +22 -0
- package/dist/openrouter/errors.d.ts.map +1 -0
- package/dist/openrouter/errors.js +75 -0
- package/dist/openrouter/errors.js.map +1 -0
- package/dist/openrouter/models.d.ts +37 -0
- package/dist/openrouter/models.d.ts.map +1 -0
- package/dist/openrouter/models.js +113 -0
- package/dist/openrouter/models.js.map +1 -0
- package/dist/openrouter/requests.d.ts +6 -0
- package/dist/openrouter/requests.d.ts.map +1 -0
- package/dist/openrouter/requests.js +74 -0
- package/dist/openrouter/requests.js.map +1 -0
- package/dist/openrouter/schemas.d.ts +37 -0
- package/dist/openrouter/schemas.d.ts.map +1 -0
- package/dist/openrouter/schemas.js +2 -0
- package/dist/openrouter/schemas.js.map +1 -0
- package/dist/output/attachments.d.ts +10 -0
- package/dist/output/attachments.d.ts.map +1 -0
- package/dist/output/attachments.js +13 -0
- package/dist/output/attachments.js.map +1 -0
- package/dist/output/formats.d.ts +42 -0
- package/dist/output/formats.d.ts.map +1 -0
- package/dist/output/formats.js +126 -0
- package/dist/output/formats.js.map +1 -0
- package/dist/output/index.d.ts +5 -0
- package/dist/output/index.d.ts.map +1 -0
- package/dist/output/index.js +5 -0
- package/dist/output/index.js.map +1 -0
- package/dist/output/paths.d.ts +38 -0
- package/dist/output/paths.d.ts.map +1 -0
- package/dist/output/paths.js +296 -0
- package/dist/output/paths.js.map +1 -0
- package/dist/output/writer.d.ts +33 -0
- package/dist/output/writer.d.ts.map +1 -0
- package/dist/output/writer.js +176 -0
- package/dist/output/writer.js.map +1 -0
- package/dist/references/attachments.d.ts +82 -0
- package/dist/references/attachments.d.ts.map +1 -0
- package/dist/references/attachments.js +238 -0
- package/dist/references/attachments.js.map +1 -0
- package/dist/references/data-url.d.ts +12 -0
- package/dist/references/data-url.d.ts.map +1 -0
- package/dist/references/data-url.js +75 -0
- package/dist/references/data-url.js.map +1 -0
- package/dist/references/formats.d.ts +13 -0
- package/dist/references/formats.d.ts.map +1 -0
- package/dist/references/formats.js +50 -0
- package/dist/references/formats.js.map +1 -0
- package/dist/references/index.d.ts +7 -0
- package/dist/references/index.d.ts.map +1 -0
- package/dist/references/index.js +7 -0
- package/dist/references/index.js.map +1 -0
- package/dist/references/limits.d.ts +15 -0
- package/dist/references/limits.d.ts.map +1 -0
- package/dist/references/limits.js +62 -0
- package/dist/references/limits.js.map +1 -0
- package/dist/references/project-files.d.ts +13 -0
- package/dist/references/project-files.d.ts.map +1 -0
- package/dist/references/project-files.js +148 -0
- package/dist/references/project-files.js.map +1 -0
- package/dist/references/remote-urls.d.ts +3 -0
- package/dist/references/remote-urls.d.ts.map +1 -0
- package/dist/references/remote-urls.js +22 -0
- package/dist/references/remote-urls.js.map +1 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +97 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/balance.d.ts +8 -0
- package/dist/tools/balance.d.ts.map +1 -0
- package/dist/tools/balance.js +133 -0
- package/dist/tools/balance.js.map +1 -0
- package/dist/tools/common.d.ts +3 -0
- package/dist/tools/common.d.ts.map +1 -0
- package/dist/tools/common.js +18 -0
- package/dist/tools/common.js.map +1 -0
- package/dist/tools/edit-image.d.ts +90 -0
- package/dist/tools/edit-image.d.ts.map +1 -0
- package/dist/tools/edit-image.js +47 -0
- package/dist/tools/edit-image.js.map +1 -0
- package/dist/tools/generate-image.d.ts +70 -0
- package/dist/tools/generate-image.d.ts.map +1 -0
- package/dist/tools/generate-image.js +36 -0
- package/dist/tools/generate-image.js.map +1 -0
- package/dist/tools/generation.d.ts +19 -0
- package/dist/tools/generation.d.ts.map +1 -0
- package/dist/tools/generation.js +154 -0
- package/dist/tools/generation.js.map +1 -0
- package/dist/tools/schema.d.ts +127 -0
- package/dist/tools/schema.d.ts.map +1 -0
- package/dist/tools/schema.js +47 -0
- package/dist/tools/schema.js.map +1 -0
- package/dist/tools/types.d.ts +18 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/transport/direct.d.ts +10 -0
- package/dist/transport/direct.d.ts.map +1 -0
- package/dist/transport/direct.js +15 -0
- package/dist/transport/direct.js.map +1 -0
- package/dist/transport/index.d.ts +4 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +4 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/kote-gateway.d.ts +19 -0
- package/dist/transport/kote-gateway.d.ts.map +1 -0
- package/dist/transport/kote-gateway.js +224 -0
- package/dist/transport/kote-gateway.js.map +1 -0
- package/dist/transport/types.d.ts +10 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/transport/types.js +9 -0
- package/dist/transport/types.js.map +1 -0
- package/dist/utils/abort.d.ts +19 -0
- package/dist/utils/abort.d.ts.map +1 -0
- package/dist/utils/abort.js +121 -0
- package/dist/utils/abort.js.map +1 -0
- package/docs/architecture.md +75 -0
- package/docs/configuration.md +110 -0
- package/docs/image-to-image.md +101 -0
- package/docs/security.md +49 -0
- package/docs/testing.md +81 -0
- package/docs/troubleshooting.md +73 -0
- package/package.json +88 -0
- package/schema/plugin-options.schema.json +182 -0
package/README.ru.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# openrouter-genimage-kote-opencode
|
|
2
|
+
|
|
3
|
+
Инструменты генерации и редактирования изображений через OpenRouter для OpenCode с опциональной fail-closed-маршрутизацией через KoteGateway. Основной сценарий — image-to-image: вложения, файлы проекта и публичные HTTPS URL передаются настроенной image-модели OpenRouter как упорядоченные `input_references`. Text-to-image доступен как дополнительный режим без визуальных референсов.
|
|
4
|
+
|
|
5
|
+
Плагин регистрирует:
|
|
6
|
+
|
|
7
|
+
- `openrouter_edit_image` — редактирование или создание по одному или нескольким визуальным референсам;
|
|
8
|
+
- `openrouter_generate_image` — новое изображение только по тексту;
|
|
9
|
+
- `openrouter_balance` — usage текущего ключа и, при наличии прав, credits аккаунта;
|
|
10
|
+
- `/openrouter-balance` — вызов balance tool без генерации изображения.
|
|
11
|
+
|
|
12
|
+
Операция может расходовать средства OpenRouter. Модель, API keys и режим маршрутизации задаются только в конфигурации и не являются аргументами tools.
|
|
13
|
+
|
|
14
|
+
## Установка
|
|
15
|
+
|
|
16
|
+
Добавьте npm-пакет tuple-записью в массив `plugin` файла `opencode.jsonc`, как показано ниже. OpenCode устанавливает npm-плагины из своей конфигурации.
|
|
17
|
+
|
|
18
|
+
Рекомендуемые permissions запрашивают подтверждение платной генерации, но разрешают проверку баланса:
|
|
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-конфигурация
|
|
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 отправляет HTTPS-запросы прямо на фиксированный OpenRouter API origin. Он не получает descriptor KoteGateway и не использует gateway как fallback.
|
|
56
|
+
|
|
57
|
+
## Proxy-конфигурация
|
|
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 получает подписанный descriptor KoteGateway и использует HTTPS CONNECT для каждого OpenRouter endpoint плагина. Режим fail-closed: ошибки bootstrap, подписи, CONNECT или timeout завершают запрос без прямого retry. OpenRouter keys, prompt, references и результат остаются внутри TLS-соединения до OpenRouter и не передаются как proxy headers.
|
|
83
|
+
|
|
84
|
+
## API keys
|
|
85
|
+
|
|
86
|
+
Создайте generation key OpenRouter и передайте его как `OPENROUTER_API_KEY`. Порядок разрешения: `apiKey` в options, затем environment variable. Отсутствующий ключ даёт `GENIMAGE_OPENROUTER_KEY_MISSING` до платного запроса.
|
|
87
|
+
|
|
88
|
+
Для полных credits аккаунта нужен management key: `managementApiKey` или `OPENROUTER_MANAGEMENT_API_KEY`. Generation key можно использовать для credits только если `/key` явно сообщает, что это management key. Не коммитьте ключи в `opencode.jsonc`; используйте подстановку OpenCode `{env:NAME}`.
|
|
89
|
+
|
|
90
|
+
## Выбор image-модели
|
|
91
|
+
|
|
92
|
+
Укажите OpenRouter model ID в `model`. Модель намеренно недоступна в arguments tools, поэтому агент не может незаметно выбрать другую или более дорогую модель. Перед первым платным запросом плагин получает capabilities и проверяет image output, image input для edit и переданные параметры. Автоматической подмены модели нет.
|
|
93
|
+
|
|
94
|
+
Конкретный provider endpoint может поддерживать меньше параметров или результатов, чем общие лимиты OpenRouter Images API.
|
|
95
|
+
|
|
96
|
+
## Image-to-image — основной сценарий
|
|
97
|
+
|
|
98
|
+
`openrouter_edit_image` требует хотя бы одно изображение и никогда не переходит в text-to-image. Если `references` не передан, используются все image attachments родительского user message с сохранением порядка. При их отсутствии возвращается `GENIMAGE_REFERENCE_REQUIRED`.
|
|
99
|
+
|
|
100
|
+
### Attached images
|
|
101
|
+
|
|
102
|
+
Приложите изображения к текущему user message и попросите OpenCode изменить их. Для явного выбора используется нумерация с единицы только среди image attachments:
|
|
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
|
+
Поддерживаются доверенные представления attachments, полученные от OpenCode. Произвольные `file:`, `data:` и `blob:` URL в tool arguments запрещены.
|
|
115
|
+
|
|
116
|
+
### Project files
|
|
117
|
+
|
|
118
|
+
Пути задаются относительно текущего 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 и WebP принимаются после проверки размера и magic bytes. Абсолютные пути, traversal, symlink escape, директории и файлы за пределами worktree отклоняются. Исходники и существующие результаты не перезаписываются.
|
|
131
|
+
|
|
132
|
+
### Несколько references и HTTPS URL
|
|
133
|
+
|
|
134
|
+
Порядок references сохраняется точно. Первый считается основным; роль каждого изображения нужно описать в prompt — плагин не сортирует, не склеивает и не придумывает роли.
|
|
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
|
+
Разрешены только публичные HTTPS URL без credentials. Явные HTTPS references передаются OpenRouter без изменения; локальные изображения кодируются в памяти как base64 data URL. Внешнее хранилище не требуется.
|
|
148
|
+
|
|
149
|
+
Подробнее: [Image-to-image](docs/image-to-image.md).
|
|
150
|
+
|
|
151
|
+
## Text-to-image
|
|
152
|
+
|
|
153
|
+
`openrouter_generate_image` используется только для полностью нового изображения без визуального референса. Он принимает prompt и output parameters, но не references, paths, attachment indexes, base64 или URL.
|
|
154
|
+
|
|
155
|
+
## Установка skill
|
|
156
|
+
|
|
157
|
+
Skill входит в npm tarball, но OpenCode ищет skills в директориях проекта или пользователя. Поэтому установите его явно:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
npx openrouter-genimage-kote-opencode install-skill
|
|
161
|
+
npx openrouter-genimage-kote-opencode check-skill
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Глобально для пользователя:
|
|
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 пишет `.opencode/skills/openrouter-image-generation/SKILL.md`; global install всегда пишет `~/.config/opencode/skills/openrouter-image-generation/SKILL.md`, в том числе на Windows. Одинаковый SHA-256 означает no-op. `check-skill` завершается с nonzero code для отсутствующего или изменённого skill. `--force` нужен только для атомарной замены локально изменённого skill. CLI не использует postinstall, не требует API key и не обращается в сеть.
|
|
172
|
+
|
|
173
|
+
## Balance и usage
|
|
174
|
+
|
|
175
|
+
Запустите `/openrouter-balance` или `openrouter_balance`. Результат разделяет два понятия:
|
|
176
|
+
|
|
177
|
+
- `/key` возвращает usage и spending limit настроенного API key, включая remaining API-key limit;
|
|
178
|
+
- `/credits` возвращает total credits и total usage аккаунта и требует management key.
|
|
179
|
+
|
|
180
|
+
Оставшийся лимит отдельного ключа — не баланс аккаунта OpenRouter. Без management authorization account credits показываются как unavailable. Если `/credits` упал, успешные данные `/key` всё равно возвращаются.
|
|
181
|
+
|
|
182
|
+
## Безопасность
|
|
183
|
+
|
|
184
|
+
- Production origin фиксирован: `https://openrouter.ai/api/v1`; пользовательские base URLs запрещены.
|
|
185
|
+
- Redirects отклоняются. Платный `POST /images` автоматически не повторяется.
|
|
186
|
+
- Proxy mode работает fail-closed и не повторяет запрос напрямую.
|
|
187
|
+
- Плагин не заменяет `globalThis.fetch` и не перехватывает другие providers.
|
|
188
|
+
- Keys, полный prompt, base64, binary data, полный upstream body и URL с query не попадают в logs/metadata.
|
|
189
|
+
- Input/output paths ограничены worktree; real paths проверяются против symlink escape.
|
|
190
|
+
- Результаты пишутся атомарно и не перезаписывают исходники или существующие файлы.
|
|
191
|
+
|
|
192
|
+
Подробнее: [Безопасность](docs/security.md) и [SECURITY.md](SECURITY.md).
|
|
193
|
+
|
|
194
|
+
## Ограничения версии 0.1.0
|
|
195
|
+
|
|
196
|
+
Нет masks и гарантированного локального inpainting, интерактивного редактора, LoRA, video, streaming, SVG, provider-specific options, автоматической покупки credits, автоматического выбора модели, скрытых fallback и внешнего object storage. Поддерживаются только PNG, JPEG и WebP. Seed не гарантирует воспроизводимость между providers. OpenRouter может вернуть меньше изображений, чем запрошено; валидные partial results сохраняются с warning.
|
|
197
|
+
|
|
198
|
+
## Troubleshooting
|
|
199
|
+
|
|
200
|
+
- `GENIMAGE_REFERENCE_REQUIRED`: приложите изображение или передайте минимум один ordered reference в `openrouter_edit_image`.
|
|
201
|
+
- `GENIMAGE_MODEL_DOES_NOT_SUPPORT_IMAGE_INPUT`: настройте image-to-image capable model; плагин не сменит её сам.
|
|
202
|
+
- `GENIMAGE_PARAMETER_UNSUPPORTED`: уберите неподдерживаемый argument/default либо настройте совместимую модель.
|
|
203
|
+
- `GENIMAGE_OPENROUTER_KEY_MISSING`: передайте `OPENROUTER_API_KEY` процессу OpenCode либо задайте `apiKey` через environment substitution.
|
|
204
|
+
- `GENIMAGE_*_TOO_LARGE` / `GENIMAGE_TOTAL_REFERENCE_SIZE_EXCEEDED`: сожмите/уменьшите inputs, сократите references или используйте публичный HTTPS URL.
|
|
205
|
+
- `GENIMAGE_GATEWAY_*`: исправьте KoteGateway/bootstrap/connectivity; proxy mode намеренно не использует direct fallback.
|
|
206
|
+
- Ошибка output path: используйте относительный путь внутри worktree, который не существует и не совпадает с source image.
|
|
207
|
+
|
|
208
|
+
Полная таблица: [Troubleshooting](docs/troubleshooting.md). Также см. [Configuration](docs/configuration.md) и [Testing](docs/testing.md).
|
|
209
|
+
|
|
210
|
+
## Статус совместимости
|
|
211
|
+
|
|
212
|
+
- Baseline OpenCode smoke tests: **1.18.21**. CI проверяет установленный npm tarball на baseline и latest stable. Attachments в TUI и Desktop всё ещё требуют ручной release-проверки; Web — если доступен.
|
|
213
|
+
- Этот пакет использует только reusable export `/core` из `@koteye/kote-gateway-opencode` **0.1.1**. Gateway adapter объявляет потолок OpenCode/SDK **1.18.18**, поэтому здесь зафиксирован `@opencode-ai/plugin` **1.18.18**, удовлетворяющий peer metadata. Core export не импортирует OpenCode adapter во время выполнения, а полный установленный tarball проходит smoke tests на OpenCode **1.18.21** и latest.
|
|
214
|
+
- Synthetic TLS/CONNECT tests проходят для signed bootstrap, fail-closed routing, одного CONNECT и обоих порядков загрузки. Они дополняют реальные OpenCode registration smokes; платный OpenRouter E2E и отображение attachments в клиентском UI остаются отдельными opt-in/manual проверками.
|
|
215
|
+
- Package объявляет Node.js 20+. Реализация рассчитана на Bun и Windows/macOS/Linux, но release artifacts должны быть проверены на поддерживаемой матрице.
|
|
216
|
+
|
|
217
|
+
## Документация
|
|
218
|
+
|
|
219
|
+
- [Архитектура](docs/architecture.md)
|
|
220
|
+
- [Конфигурация](docs/configuration.md)
|
|
221
|
+
- [Image-to-image](docs/image-to-image.md)
|
|
222
|
+
- [Безопасность](docs/security.md)
|
|
223
|
+
- [Тестирование](docs/testing.md)
|
|
224
|
+
- [Troubleshooting](docs/troubleshooting.md)
|
|
225
|
+
- [English README](README.md)
|
|
226
|
+
|
|
227
|
+
## Лицензия
|
|
228
|
+
|
|
229
|
+
MIT. См. [LICENSE](LICENSE) и [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
Security fixes are provided for the latest published release. Version `0.1.0` targets the initial public release. Older prerelease/source snapshots are not supported unless a maintainer explicitly says otherwise.
|
|
6
|
+
|
|
7
|
+
## Reporting a vulnerability
|
|
8
|
+
|
|
9
|
+
Report vulnerabilities privately through the repository owner's private security-reporting channel (for example, GitHub Security Advisories when enabled). If no private channel is visible, contact the package owner through the contact information published on the npm package profile and ask for a secure reporting address before sending sensitive details.
|
|
10
|
+
|
|
11
|
+
Do not open a public issue with:
|
|
12
|
+
|
|
13
|
+
- an OpenRouter or management API key;
|
|
14
|
+
- authorization/proxy headers;
|
|
15
|
+
- a full prompt, private reference, or generated image;
|
|
16
|
+
- base64 or binary payloads;
|
|
17
|
+
- an unredacted upstream response;
|
|
18
|
+
- a gateway bootstrap document or descriptor;
|
|
19
|
+
- a private URL or query string.
|
|
20
|
+
|
|
21
|
+
Include the affected version, OpenCode/runtime version, OS, routing mode, impact, minimal redacted reproduction, and whether a key or private asset may have been exposed. Maintainers should acknowledge receipt, coordinate remediation and disclosure, and avoid asking for production secrets.
|
|
22
|
+
|
|
23
|
+
If a key may have been exposed, revoke it in OpenRouter immediately and replace the environment value before further testing.
|
|
24
|
+
|
|
25
|
+
## Security boundaries
|
|
26
|
+
|
|
27
|
+
Production OpenRouter origin is fixed; redirects fail; paid image POSTs are not retried; proxy mode is fail-closed; and the plugin must not install a global fetch interceptor. Project input/output is confined to the OpenCode worktree with lexical and realpath checks. Source and existing output files are never overwritten. PNG/JPEG/WebP content is checked by size and magic bytes.
|
|
28
|
+
|
|
29
|
+
The plugin must not persist or log keys, full prompts, base64, binary data, unredacted request/response bodies, full external URLs with query strings, or gateway bootstrap data. In proxy mode, keys and image content remain inside TLS to OpenRouter and are not proxy credentials.
|
|
30
|
+
|
|
31
|
+
See [`docs/security.md`](docs/security.md) for the detailed threat model and controls.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Third-Party Notices
|
|
2
|
+
|
|
3
|
+
This project depends on third-party software. The authoritative license texts and copyright notices are the files distributed with each installed package and its source repository; those notices remain in force and are not replaced by this summary.
|
|
4
|
+
|
|
5
|
+
Runtime dependencies declared for version 0.1.0:
|
|
6
|
+
|
|
7
|
+
| Package | Pinned version | Manifest license | Project |
|
|
8
|
+
|---|---:|---|---|
|
|
9
|
+
| `@koteye/kote-gateway-opencode` | `0.1.1` | MIT | KoteGateway integration/core ([source](https://github.com/koteyye/opencode-kote-gateway)) |
|
|
10
|
+
| `@opencode-ai/plugin` | `1.18.18` | MIT | OpenCode plugin API |
|
|
11
|
+
| `undici` | `6.28.0` | MIT | HTTP client primitives |
|
|
12
|
+
| `zod` | `4.1.8` | MIT | Runtime schema validation |
|
|
13
|
+
|
|
14
|
+
Development dependencies include `@eslint/js`, `@types/bun`, `eslint`, `typescript`, and `typescript-eslint` at the exact versions recorded in `package.json` and the package lock.
|
|
15
|
+
|
|
16
|
+
Binary distributions and npm tarballs should retain license/notice files required by these dependencies. Before release, generate or audit the production dependency inventory from the resolved lockfile and verify every dependency's license metadata. This document does not claim compatibility or certification by any third-party project.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export interface CliRuntime {
|
|
3
|
+
cwd?: string;
|
|
4
|
+
homeDirectory?: string;
|
|
5
|
+
packageRoot?: string;
|
|
6
|
+
stderr?: (line: string) => void;
|
|
7
|
+
stdout?: (line: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export interface SkillPaths {
|
|
10
|
+
source: string;
|
|
11
|
+
target: string;
|
|
12
|
+
targetRoot: string;
|
|
13
|
+
}
|
|
14
|
+
export type InstallSkillResult = "current" | "installed" | "updated";
|
|
15
|
+
export type CheckSkillResult = "current" | "missing" | "modified";
|
|
16
|
+
export declare function resolveSkillPaths(global: boolean, runtime?: Pick<CliRuntime, "cwd" | "homeDirectory" | "packageRoot">): SkillPaths;
|
|
17
|
+
export declare function installSkill(paths: SkillPaths, force: boolean): Promise<InstallSkillResult>;
|
|
18
|
+
export declare function checkSkill(paths: SkillPaths): Promise<CheckSkillResult>;
|
|
19
|
+
export declare function runCli(arguments_: readonly string[], runtime?: CliRuntime): Promise<number>;
|
|
20
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAkDA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAA;AACpE,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAA;AAYjE,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,OAAO,EACf,OAAO,GAAE,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG,eAAe,GAAG,aAAa,CAAM,GACtE,UAAU,CAcZ;AA2ID,wBAAsB,YAAY,CAChC,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,kBAAkB,CAAC,CAyB7B;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAc7E;AA0CD,wBAAsB,MAAM,CAC1B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,MAAM,CAAC,CAoDjB"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
+
import { constants, realpathSync } from "node:fs";
|
|
4
|
+
import { copyFile, lstat, mkdir, readFile, realpath, rename, unlink, writeFile, } from "node:fs/promises";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
const SKILL_NAME = "openrouter-image-generation";
|
|
9
|
+
const SKILL_RELATIVE_PATH = join(".opencode", "skills", SKILL_NAME, "SKILL.md");
|
|
10
|
+
const GLOBAL_SKILL_RELATIVE_PATH = join(".config", "opencode", "skills", SKILL_NAME, "SKILL.md");
|
|
11
|
+
const USAGE = `Usage:
|
|
12
|
+
openrouter-genimage-kote-opencode install-skill [--global] [--force]
|
|
13
|
+
openrouter-genimage-kote-opencode check-skill [--global]
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
--global Use ~/.config/opencode instead of the current project.
|
|
17
|
+
--force Replace a modified installed skill (install-skill only).
|
|
18
|
+
-h, --help Show this help.`;
|
|
19
|
+
class UsageError extends Error {
|
|
20
|
+
}
|
|
21
|
+
function isNodeError(error) {
|
|
22
|
+
return error instanceof Error && "code" in error;
|
|
23
|
+
}
|
|
24
|
+
function packageRootFromModule() {
|
|
25
|
+
return fileURLToPath(new URL("../", import.meta.url));
|
|
26
|
+
}
|
|
27
|
+
export function resolveSkillPaths(global, runtime = {}) {
|
|
28
|
+
const packageRoot = resolve(runtime.packageRoot ?? packageRootFromModule());
|
|
29
|
+
const targetRoot = global
|
|
30
|
+
? resolve(runtime.homeDirectory ?? homedir())
|
|
31
|
+
: resolve(runtime.cwd ?? process.cwd());
|
|
32
|
+
return {
|
|
33
|
+
source: join(packageRoot, SKILL_RELATIVE_PATH),
|
|
34
|
+
target: join(targetRoot, global ? GLOBAL_SKILL_RELATIVE_PATH : SKILL_RELATIVE_PATH),
|
|
35
|
+
targetRoot,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function isPathInside(root, candidate) {
|
|
39
|
+
const difference = relative(root, candidate);
|
|
40
|
+
return (difference === "" ||
|
|
41
|
+
(difference !== ".." &&
|
|
42
|
+
!difference.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) &&
|
|
43
|
+
!isAbsolute(difference)));
|
|
44
|
+
}
|
|
45
|
+
async function nearestExistingAncestor(candidate) {
|
|
46
|
+
let current = resolve(candidate);
|
|
47
|
+
for (;;) {
|
|
48
|
+
try {
|
|
49
|
+
await lstat(current);
|
|
50
|
+
return current;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (!isNodeError(error) || error.code !== "ENOENT")
|
|
54
|
+
throw error;
|
|
55
|
+
const parent = dirname(current);
|
|
56
|
+
if (parent === current)
|
|
57
|
+
throw error;
|
|
58
|
+
current = parent;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function secureTargetPath(paths, createParent) {
|
|
63
|
+
const lexicalRoot = resolve(paths.targetRoot);
|
|
64
|
+
const lexicalTarget = resolve(paths.target);
|
|
65
|
+
if (!isPathInside(lexicalRoot, lexicalTarget)) {
|
|
66
|
+
throw new Error("The skill destination escapes its configured root.");
|
|
67
|
+
}
|
|
68
|
+
const canonicalRoot = await realpath(lexicalRoot);
|
|
69
|
+
const targetParent = dirname(lexicalTarget);
|
|
70
|
+
const existingAncestor = await nearestExistingAncestor(targetParent);
|
|
71
|
+
const canonicalAncestor = await realpath(existingAncestor);
|
|
72
|
+
if (!isPathInside(canonicalRoot, canonicalAncestor)) {
|
|
73
|
+
throw new Error("The skill destination resolves outside its configured root through a symbolic link or junction.");
|
|
74
|
+
}
|
|
75
|
+
if (createParent)
|
|
76
|
+
await mkdir(targetParent, { recursive: true });
|
|
77
|
+
try {
|
|
78
|
+
const canonicalParent = await realpath(targetParent);
|
|
79
|
+
if (!isPathInside(canonicalRoot, canonicalParent)) {
|
|
80
|
+
throw new Error("The skill destination resolves outside its configured root through a symbolic link or junction.");
|
|
81
|
+
}
|
|
82
|
+
const secureTarget = join(canonicalParent, basename(lexicalTarget));
|
|
83
|
+
try {
|
|
84
|
+
const targetStats = await lstat(secureTarget);
|
|
85
|
+
if (targetStats.isSymbolicLink()) {
|
|
86
|
+
throw new Error("Refusing to read or replace a symbolic-link skill destination.");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (!isNodeError(error) || error.code !== "ENOENT")
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
return secureTarget;
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (!isNodeError(error) || error.code !== "ENOENT" || createParent)
|
|
97
|
+
throw error;
|
|
98
|
+
return lexicalTarget;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function sha256(content) {
|
|
102
|
+
return createHash("sha256").update(content).digest("hex");
|
|
103
|
+
}
|
|
104
|
+
async function readOptional(path) {
|
|
105
|
+
try {
|
|
106
|
+
return await readFile(path);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async function copyWithoutOverwrite(source, target) {
|
|
116
|
+
try {
|
|
117
|
+
await copyFile(source, target, constants.COPYFILE_EXCL);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
if (!isNodeError(error) || error.code !== "EEXIST") {
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
const [sourceContent, targetContent] = await Promise.all([
|
|
124
|
+
readFile(source),
|
|
125
|
+
readFile(target),
|
|
126
|
+
]);
|
|
127
|
+
if (sha256(sourceContent) !== sha256(targetContent)) {
|
|
128
|
+
throw new Error("The destination appeared during installation and differs from the packaged skill. Run the command again after reviewing it.");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function replaceAtomically(target, content) {
|
|
133
|
+
const temporary = join(dirname(target), `.${SKILL_NAME}-${process.pid}-${randomUUID()}.tmp`);
|
|
134
|
+
try {
|
|
135
|
+
await writeFile(temporary, content, { flag: "wx", mode: 0o644 });
|
|
136
|
+
await rename(temporary, target);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
try {
|
|
140
|
+
await unlink(temporary);
|
|
141
|
+
}
|
|
142
|
+
catch (cleanupError) {
|
|
143
|
+
if (!isNodeError(cleanupError) || cleanupError.code !== "ENOENT") {
|
|
144
|
+
throw new AggregateError([error, cleanupError], "Failed to replace the skill and clean up its temporary file.");
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
export async function installSkill(paths, force) {
|
|
151
|
+
const sourceContent = await readFile(paths.source);
|
|
152
|
+
const target = await secureTargetPath(paths, true);
|
|
153
|
+
const targetContent = await readOptional(target);
|
|
154
|
+
if (targetContent !== undefined &&
|
|
155
|
+
sha256(sourceContent) === sha256(targetContent)) {
|
|
156
|
+
return "current";
|
|
157
|
+
}
|
|
158
|
+
if (targetContent !== undefined && !force) {
|
|
159
|
+
throw new Error("The destination contains a modified skill. Refusing to overwrite it without --force.");
|
|
160
|
+
}
|
|
161
|
+
if (targetContent === undefined) {
|
|
162
|
+
await copyWithoutOverwrite(paths.source, target);
|
|
163
|
+
return "installed";
|
|
164
|
+
}
|
|
165
|
+
await replaceAtomically(target, sourceContent);
|
|
166
|
+
return "updated";
|
|
167
|
+
}
|
|
168
|
+
export async function checkSkill(paths) {
|
|
169
|
+
const target = await secureTargetPath(paths, false);
|
|
170
|
+
const [sourceContent, targetContent] = await Promise.all([
|
|
171
|
+
readFile(paths.source),
|
|
172
|
+
readOptional(target),
|
|
173
|
+
]);
|
|
174
|
+
if (targetContent === undefined) {
|
|
175
|
+
return "missing";
|
|
176
|
+
}
|
|
177
|
+
return sha256(sourceContent) === sha256(targetContent)
|
|
178
|
+
? "current"
|
|
179
|
+
: "modified";
|
|
180
|
+
}
|
|
181
|
+
function parseArguments(arguments_) {
|
|
182
|
+
if (arguments_.includes("--help") || arguments_.includes("-h")) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
const [command, ...flags] = arguments_;
|
|
186
|
+
if (command !== "install-skill" && command !== "check-skill") {
|
|
187
|
+
throw new UsageError(command === undefined
|
|
188
|
+
? "A command is required."
|
|
189
|
+
: `Unknown command: ${command}`);
|
|
190
|
+
}
|
|
191
|
+
for (const flag of flags) {
|
|
192
|
+
if (flag !== "--global" && flag !== "--force") {
|
|
193
|
+
throw new UsageError(`Unknown option: ${flag}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const force = flags.includes("--force");
|
|
197
|
+
if (command === "check-skill" && force) {
|
|
198
|
+
throw new UsageError("--force is only valid with install-skill.");
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
command,
|
|
202
|
+
force,
|
|
203
|
+
global: flags.includes("--global"),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function formatFailure(error) {
|
|
207
|
+
if (error instanceof Error) {
|
|
208
|
+
return error.message;
|
|
209
|
+
}
|
|
210
|
+
return "Unknown CLI error.";
|
|
211
|
+
}
|
|
212
|
+
export async function runCli(arguments_, runtime = {}) {
|
|
213
|
+
const stdout = runtime.stdout ?? ((line) => console.log(line));
|
|
214
|
+
const stderr = runtime.stderr ?? ((line) => console.error(line));
|
|
215
|
+
try {
|
|
216
|
+
const parsed = parseArguments(arguments_);
|
|
217
|
+
if (parsed === null) {
|
|
218
|
+
stdout(USAGE);
|
|
219
|
+
return 0;
|
|
220
|
+
}
|
|
221
|
+
const paths = resolveSkillPaths(parsed.global, runtime);
|
|
222
|
+
stdout(`Source: ${paths.source}`);
|
|
223
|
+
stdout(`Destination: ${paths.target}`);
|
|
224
|
+
if (parsed.command === "install-skill") {
|
|
225
|
+
const result = await installSkill(paths, parsed.force);
|
|
226
|
+
if (result === "current") {
|
|
227
|
+
stdout("Skill is already current; no files were changed.");
|
|
228
|
+
}
|
|
229
|
+
else if (result === "installed") {
|
|
230
|
+
stdout("Skill installed.");
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
stdout("Skill updated with --force.");
|
|
234
|
+
}
|
|
235
|
+
return 0;
|
|
236
|
+
}
|
|
237
|
+
const result = await checkSkill(paths);
|
|
238
|
+
if (result === "current") {
|
|
239
|
+
stdout("Skill status: current (SHA-256 matches the packaged skill).");
|
|
240
|
+
return 0;
|
|
241
|
+
}
|
|
242
|
+
if (result === "missing") {
|
|
243
|
+
stderr("Skill status: missing. Run install-skill to install it.");
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
stderr("Skill status: modified. Review it or run install-skill --force to restore the packaged version.");
|
|
247
|
+
}
|
|
248
|
+
return 1;
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
stderr(`Error: ${formatFailure(error)}`);
|
|
252
|
+
if (error instanceof UsageError) {
|
|
253
|
+
stderr(USAGE);
|
|
254
|
+
return 2;
|
|
255
|
+
}
|
|
256
|
+
return 1;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function isDirectExecution() {
|
|
260
|
+
const entrypoint = process.argv[1];
|
|
261
|
+
if (entrypoint === undefined) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
const modulePath = fileURLToPath(import.meta.url);
|
|
265
|
+
try {
|
|
266
|
+
return realpathSync(entrypoint) === realpathSync(modulePath);
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return resolve(entrypoint) === resolve(modulePath);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (isDirectExecution()) {
|
|
273
|
+
void runCli(process.argv.slice(2)).then((exitCode) => {
|
|
274
|
+
process.exitCode = exitCode;
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"balance-command.d.ts","sourceRoot":"","sources":["../../src/commands/balance-command.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,0BAA0B;;;CAmB7B,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const OPENROUTER_BALANCE_COMMAND = {
|
|
2
|
+
description: "Show OpenRouter usage, key limits, and account credits when available",
|
|
3
|
+
template: `
|
|
4
|
+
Call the openrouter_balance tool exactly once.
|
|
5
|
+
|
|
6
|
+
Present the returned values in the user's language.
|
|
7
|
+
|
|
8
|
+
Clearly distinguish:
|
|
9
|
+
- API-key usage;
|
|
10
|
+
- API-key spending limit;
|
|
11
|
+
- remaining API-key spending limit;
|
|
12
|
+
- full account credits.
|
|
13
|
+
|
|
14
|
+
Do not treat the remaining key limit as the full account balance.
|
|
15
|
+
Do not invent unavailable values.
|
|
16
|
+
Do not call image generation tools.
|
|
17
|
+
Show monetary values with at least six decimal places and do not round a small non-zero value to zero.
|
|
18
|
+
`.trim(),
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=balance-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"balance-command.js","sourceRoot":"","sources":["../../src/commands/balance-command.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,WAAW,EACT,uEAAuE;IACzE,QAAQ,EAAE;;;;;;;;;;;;;;;GAeT,CAAC,IAAI,EAAE;CACA,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ConfigEnvironment, PluginConfigState, ResolvedPluginOptions } from "./types.js";
|
|
2
|
+
export declare function resolvePluginOptions(rawOptions: unknown, environment?: ConfigEnvironment): ResolvedPluginOptions;
|
|
3
|
+
export declare function resolvePluginConfig(rawOptions: unknown, environment?: ConfigEnvironment): PluginConfigState;
|
|
4
|
+
export declare function requireResolvedPluginOptions(state: PluginConfigState): ResolvedPluginOptions;
|
|
5
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,YAAY,CAAA;AAmCnB,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,OAAO,EACnB,WAAW,GAAE,iBAIZ,GACA,qBAAqB,CAiFvB;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,OAAO,EACnB,WAAW,GAAE,iBAIZ,GACA,iBAAiB,CAanB;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,iBAAiB,GACvB,qBAAqB,CAMvB"}
|