imgrelay 0.2.0 → 0.3.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/README.md CHANGED
@@ -1,192 +1,139 @@
1
1
  # ImgRelay
2
2
 
3
- 通过统一 CLI 和 Codex Skill 调用多家 OpenAI Images 兼容中转站。用户级配置跨项目复用,
4
- 生成结果默认保存在当前工作目录的 `output/imagegen/`。
3
+ 在 Codex 中用自然语言调用第三方中转站生成图片,保存并展示原图。
4
+ 配置一次供应商、密钥和默认模型,即可在不同项目中复用。
5
5
 
6
- 首版支持文生图、供应商与凭据管理、模型列表缓存、只读检查、原图保存和 JSON 输出。
7
- 图片编辑、Responses、Chat Completions 与非标准异步协议属于后续范围。
6
+ ImgRelay 提供负责配置和生图的 CLI,以及负责准备提示词、调用 CLI 和展示结果的 Codex Skill。
7
+ 支持 OpenAI Images 兼容接口的文生图。
8
8
 
9
- ## 安装与开发
9
+ ## 快速上手
10
10
 
11
- 需要 Node.js 22.20+(22.x)或 24.x。发布到 npm 后:
11
+ ### 1. 安装 CLI 和 Skill
12
+
13
+ 需要 Node.js 22.20+(22.x)或 24.x。在终端运行:
12
14
 
13
15
  ```bash
14
16
  npm install -g imgrelay
15
- npx skills add bingwu-devkit/imgrelay --skill imgrelay --agent codex --global --copy
17
+ npx skills add bingwu-devkit/imgrelay --skill imgrelay
16
18
  ```
17
19
 
18
- CLI 与 Skill 分开安装;npm 安装不会改动 Codex 配置。当前源码可直接构建运行:
20
+ 按 Skills CLI 的提示选择 Codex、安装范围和安装方式。
21
+
22
+ ### 2. 配置中转站
23
+
24
+ 打开终端运行,`relay` 是你为供应商取的名称:
19
25
 
20
26
  ```bash
21
- pnpm install
22
- pnpm build
23
- node packages/cli/dist/index.mjs --help
24
- npx skills add ./skills --skill imgrelay --agent codex --global --copy
27
+ imgrelay provider add relay --default
25
28
  ```
26
29
 
27
- 开发使用 pnpm 11.15.1。以下示例中的 `imgrelay` 可替换为上述 Node 命令。
28
-
29
- ## 首次配置
30
+ 按提示填写 API 基础地址、API Key 和默认模型。地址通常形如
31
+ `https://relay.example/v1`;密钥通过隐藏输入填写,模型列表不可用时可手动输入模型 ID。
30
32
 
31
- 交互式配置直接隐藏输入密钥并保存到 `config.json`,随后查询模型列表并设置默认项。
32
- 查询失败时可手动填入模型 ID,配置流程不生成图片:
33
+ 使用 Cubence 时,可通过预设填写地址和默认参数:
33
34
 
34
35
  ```bash
35
- imgrelay provider add cubence --preset cubence
36
- imgrelay provider use cubence
37
- imgrelay doctor --provider cubence
36
+ imgrelay provider add cubence --preset cubence --default
38
37
  ```
39
38
 
40
- 修改密钥同样使用交互式隐藏输入,留空保留当前密钥:
39
+ 配置保存在用户主目录的 `~/.imgrelay/`,跨项目复用。API Key 以明文保存在本机配置中,
40
+ 通过上述交互命令输入即可。
41
41
 
42
- ```bash
43
- imgrelay provider edit cubence
44
- ```
42
+ ### 3. 在 Codex 中生成图片
45
43
 
46
- 新增供应商和输入新密钥须在交互终端中运行,不加 `--json`。密钥明文保存在配置中,
47
- 不要求以 `sk-` 开头;删除供应商会一并移除其密钥。
48
- 非交互命令可修改已有供应商的其他参数或显式清除密钥:
44
+ 进入要保存图片的项目,向 Codex 发出请求,例如:
49
45
 
50
- ```bash
51
- imgrelay provider edit cubence --model vendor-model --json
52
- imgrelay provider edit cubence --clear-key --json
46
+ ```text
47
+ $imgrelay 生成一张戴宇航员头盔的猫,用作博客封面,横版。
48
+
49
+ 用 imgrelay 的 relay 供应商生成两张极简风格的森林插画,保存到 ./images。
50
+
51
+ 用 imgrelay 生图,提示词请原样使用:一只橘猫趴在窗边,午后自然光。
53
52
  ```
54
53
 
55
- ## 命令
54
+ 可在请求中指定供应商、模型、数量、尺寸或保存位置,其余设置沿用本机默认配置。
55
+ 对于简短需求,Codex 会围绕用途补足提示词;需要使用现成提示词时,说明“原样使用”即可。
56
56
 
57
- | 命令 | 用途 |
58
- | -------------------------------------- | ----------------------------------------- |
59
- | `provider add <名称>` | 添加供应商;可显式选择 `--preset cubence` |
60
- | `provider list` | 列出摘要及默认项 |
61
- | `provider show <名称>` | 查看脱敏配置 |
62
- | `provider edit <名称>` | 修改配置与凭据,`--clear-key` 清除凭据 |
63
- | `provider use <名称>` | 设置默认供应商 |
64
- | `provider remove <名称>` | 移除供应商及配置中保存的密钥 |
65
- | `models [--provider 名称] [--refresh]` | 查询模型或查看 15 分钟缓存 |
66
- | `doctor [--provider 名称]` | 检查配置、鉴权和模型查询,不生成图片 |
67
- | `generate` | 生成并保存图片及记录 |
57
+ 生成后,Codex 会展示已保存的图片,并说明供应商、请求模型和保存位置。
58
+ 默认输出在当前项目的 `output/imagegen/`,包含原图和生成记录。
68
59
 
69
- 所有命令支持 `--json` 和 `--help`,根命令支持 `--version`。
70
- JSON 模式禁用交互,标准输出仅包含一个最终 JSON,进度在标准错误。
60
+ ## 直接使用 CLI
71
61
 
72
- ## 生成图片
62
+ ### 从提示词文件生成
63
+
64
+ 新建 `prompt.txt`,写入想要生成的内容,例如:
65
+
66
+ ```text
67
+ 一只戴宇航员头盔的猫,蓝色背景。
68
+ 完整角色,横向构图,适合作为博客封面。
69
+ ```
70
+
71
+ 在文件所在目录运行:
73
72
 
74
73
  ```bash
75
- imgrelay generate --prompt "一只戴宇航员头盔的猫"
76
- imgrelay generate --prompt "一只戴宇航员头盔的猫" --provider cubence --n 2 --json
77
- imgrelay generate --prompt "一只戴宇航员头盔的猫" --model vendor-model --size auto --quality high --output-format png
78
- imgrelay generate --prompt "一只戴宇航员头盔的猫" --output-dir ./images --filename cat.png --timeout 600
74
+ imgrelay generate --prompt-file ./prompt.txt
79
75
  ```
80
76
 
81
- 生成时必须通过 `--prompt` 提供非空文本。CLI 原样发送内容,保留换行及首尾空白,
82
- 不自动添加风格或约束。长提示词也通过此选项传递,按当前 shell 正确引用以保留特殊字符。
83
-
84
- 单次参数覆盖不会改动持久配置。参数值按“命令 → 供应商默认 → 工具默认”合并;
85
- 工具仅默认数量为 1,不强制尺寸、质量或格式。未知模型允许调用,模型列表缺失不阻断生成。
86
-
87
- 图片保留原始字节;Base64 优先于 URL,图片下载及重定向不带 API Key。
88
- 记录实际格式、尺寸和字节数。默认文件名包含 UUID 和序号;自定义文件名的扩展名按实际格式,
89
- 多图追加序号。默认不覆盖文件,显式 `--overwrite` 才允许覆盖。
90
-
91
- 默认生成超时为 600 秒;只读请求最多重试一次,生成 POST 不自动重试。
92
- 超时或断网意味着结果未知,上游可能仍在生成。不会自动换模型、降参数或拆成多次付费请求。
93
- 每张图片最多 32 MiB,上游 JSON 最多 128 MiB;某项失败后继续保存其他结果。
94
-
95
- ## 中转站兼容配置
96
-
97
- 同协议中转站通过 `provider add` 接入,不新增品牌客户端。
98
- Base URL 支持主机地址、`/v1`、自定义前缀及标准完整生成 URL,并集中处理路径拼接。
99
- `doctor` 展示最终地址;认证模型接口成功只证明模型查询可用,不证明生成及全部参数可用。
100
-
101
- `provider add/edit` 还支持 `--generation-path`、`--models-path`、默认生成参数、
102
- `--timeout` 和 `--capabilities-file`。端点覆盖仅接受路径,不能更换主机。
103
- 能力覆盖文件是按模型 ID 索引的 JSON:
104
-
105
- ```json
106
- {
107
- "vendor-model": {
108
- "source": "provider_override",
109
- "parameters": {
110
- "n": { "min": 1, "max": 1 },
111
- "quality": { "values": ["high"] },
112
- "outputFormat": { "values": ["png", "webp"] },
113
- "responseFormat": { "supported": false }
114
- }
115
- }
116
- }
77
+ ### 指定保存位置
78
+
79
+ ```bash
80
+ imgrelay generate --prompt-file ./prompt.txt --output-dir ./images --filename cat.png
117
81
  ```
118
82
 
119
- 校验按“供应商覆盖 → 已知模型能力 → 上游验证”执行,显式命令参数同样受覆盖约束。
120
- 内置 GPT Image 1/mini 的已知参数;供应商可覆盖具体差异。Cubence 预设来自需求中的一次
121
- 成功调用,仅提供默认组合,不推断其全部能力。GPT Image 默认不发送 `response_format`;
122
- 确需配置兼容返回格式的站点可通过供应商默认值与能力覆盖明确表达。
123
-
124
- ## 配置与输出
125
-
126
- Windows、Linux 和 macOS 的配置目录统一为当前用户主目录下的 `~/.imgrelay/`。
127
- `IMGRELAY_CONFIG_DIR` 可覆盖目录,相对路径基于当前工作目录解析。
128
-
129
- 供应商配置与明文 API Key 集中保存在版本 1 的 `config.json`,模型缓存保存在同目录的
130
- `models-cache.json`。文件使用系统默认权限,不做加密、专用 ACL 或权限校验。
131
- 隐藏输入的密钥保存在供应商的 `apiKey` 字段。配置结构例如:
132
-
133
- ```json
134
- {
135
- "schemaVersion": 1,
136
- "defaultProvider": "relay",
137
- "providers": {
138
- "relay": {
139
- "protocol": "openai-images",
140
- "baseUrl": "https://relay.example/v1",
141
- "apiKey": "your-api-key",
142
- "defaultModel": "vendor-model"
143
- }
144
- }
145
- }
83
+ ### 选择供应商、模型或数量
84
+
85
+ ```bash
86
+ imgrelay generate --prompt-file ./prompt.txt --provider relay --model vendor-model --n 2
146
87
  ```
147
88
 
148
- 模型缓存索引为供应商、配置修订、端点和实际凭据的 SHA-256 摘要,地址或实际凭据变化后
149
- 不会复用旧查询。CLI 输出、日志、JSON 和生成记录保持脱敏,不保存密钥明文、鉴权头、
150
- 原始 Base64 或带访问凭据的下载链接。图片和生成记录默认保存在当前工作目录的
151
- `output/imagegen/`,可通过 `--output-dir` 指定。
152
- 生成记录含提示词及请求参数,应按本机文件管理方式处理。
153
-
154
- JSON 外层固定为 `schemaVersion`、`command`、`status`、`data`、`error`。
155
- 生成结果的 `data.images` 包含本地路径、实际格式/尺寸/字节数,另有请求模型、上游报告模型
156
- (仅在返回时)、失败项、用量和 `recordPath`。使用 `error.category` 判断失败类型。
157
- 请求提交前保存记录,单项保存失败保留其他图片,记录保存失败仍返回已保存路径。
158
- `data.endpoint` 是本次实际生成地址,`data.capabilityEvidence` 保留已知模型与供应商覆盖的
159
- 来源及已有验证时间;未知能力显示为空,不从一次成功调用推断其他能力。
160
-
161
- | 退出码 | 含义 |
162
- | ------ | ------------------------------------ |
163
- | 0 | 成功 |
164
- | 1 | 内部错误 |
165
- | 2 | 输入、配置、凭据或本地能力校验错误 |
166
- | 3 | 上游错误、无效图片响应或生成结果未知 |
167
- | 4 | 图片或记录保存失败 |
168
- | 5 | 部分图片成功 |
169
- | 130 | 用户中断;不能保证取消上游请求 |
170
-
171
- ## 验证与发布
89
+ `relay` 使用你已配置的供应商名称,`vendor-model` 替换为该供应商提供的模型 ID。
90
+ 本次指定的设置仅用于这次生成。尺寸、质量和格式等选项见 [CLI 参考](https://github.com/bingwu-devkit/imgrelay/blob/main/docs/cli-reference.md)。
91
+
92
+ ### 先预览配置(可选)
93
+
94
+ 想先查看本次使用的模型、参数和保存位置时,加上 `--dry-run`:
172
95
 
173
96
  ```bash
174
- pnpm check
175
- node scripts/package-smoke.mjs
97
+ imgrelay generate --prompt-file ./prompt.txt --dry-run --json
176
98
  ```
177
99
 
178
- 测试使用本地模拟中转站和真实 CLI 子进程,不消耗真实 API 额度。
179
- CI 覆盖 Windows、Linux、macOS 和 Node.js 22、24,包括凭据权限及独立打包安装检查。
180
- Skill 使用 skill-creator 校验器检查;Skills CLI 可用 `npx skills add ./skills --list` 验证发现。
100
+ 这条命令只预览配置,不生成图片,也不消耗生图额度。
101
+
102
+ ## 管理配置
103
+
104
+ | 常用命令 | 用途 |
105
+ | ---------------------------------- | ------------------------------ |
106
+ | `imgrelay provider list` | 查看供应商和默认项 |
107
+ | `imgrelay provider show relay` | 查看供应商配置 |
108
+ | `imgrelay provider edit relay` | 修改地址、密钥、模型和默认参数 |
109
+ | `imgrelay provider use relay` | 切换默认供应商 |
110
+ | `imgrelay models --provider relay` | 查询可用模型 |
111
+ | `imgrelay doctor --provider relay` | 检查配置和模型接口连接 |
112
+
113
+ 命令后加 `--help` 可查看完整选项。需要在脚本中读取结果时加 `--json`;
114
+ 添加供应商和更新密钥时,使用上表中的交互命令。
115
+
116
+ ## 常见问题
117
+
118
+ **图片保存在哪里?** 默认在运行命令的目录下的 `output/imagegen/`。
119
+ 用 `--output-dir` 指定其他目录,生成结果中也会显示保存路径。
120
+
121
+ **文件已经存在怎么办?** 更换 `--filename`,或在需要覆盖时加 `--overwrite`。
122
+
123
+ **找不到想用的模型怎么办?** 根据供应商提供的模型 ID,用 `--model` 指定;
124
+ 也可以运行 `provider edit` 修改默认模型。
125
+
126
+ **生成等了很久怎么办?** 默认等待 10 分钟,可用 `--timeout` 调整等待秒数。
127
+ 超时或断网后,先到供应商后台确认请求状态,再决定是否重新生成。
128
+
129
+ **只有部分图片成功怎么办?** 已保存的图片仍可使用,查看结果中的失败原因,
130
+ 再决定是否需要生成更多图片。
181
131
 
182
- 真实 Cubence 单张生成作为发布前人工验收,在用户明确要求并提供凭据来源后执行。
183
- 自动发布使用 npm Trusted Publishing,需在 npm 配置对应仓库和 `release.yml`,并允许 GitHub Actions 创建 PR。
184
- 提交 changeset 到 `main` 后会创建或更新版本 PR;合并版本 PR 后自动发布 npm 包和 GitHub Release。
132
+ ## 详细文档
185
133
 
186
- 需求及设计依据见
187
- [需求文档](https://github.com/bingwu-devkit/imgrelay/blob/main/docs/image-relay-requirements.md)、
188
- [兼容性参考](https://github.com/bingwu-devkit/imgrelay/blob/main/docs/provider-compatibility-design.md)。
134
+ - [CLI 参考](https://github.com/bingwu-devkit/imgrelay/blob/main/docs/cli-reference.md):按场景使用命令、配置选项、脚本调用与问题处理。
135
+ - [开发与发布](https://github.com/bingwu-devkit/imgrelay/blob/main/docs/development.md):源码运行、验证、打包和发布流程。
189
136
 
190
137
  ## 许可证
191
138
 
192
- [MIT](./LICENSE.md)。保留模板原有版权归属。
139
+ [MIT](./LICENSE.md)。
package/dist/index.mjs CHANGED
@@ -4,8 +4,8 @@ import { access, lstat, mkdir, open, readFile, rename, rmdir, unlink, writeFile
4
4
  import { basename, dirname, join, parse, resolve } from "node:path";
5
5
  import { fileTypeFromBuffer } from "file-type";
6
6
  import { imageSize } from "image-size";
7
- import { z } from "zod";
8
7
  import { setTimeout } from "node:timers/promises";
8
+ import { z } from "zod";
9
9
  import { homedir } from "node:os";
10
10
  import { Command, CommanderError } from "commander";
11
11
  import * as prompts from "@clack/prompts";
@@ -49,7 +49,7 @@ var Redactor = class {
49
49
  value(value) {
50
50
  if (typeof value === "string") return this.text(value);
51
51
  if (Array.isArray(value)) return value.map((item) => this.value(item));
52
- if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => [this.text(key), this.value(item)]));
52
+ if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => [this.text(key), key === "promptSha256" && typeof item === "string" && /^[a-f0-9]{64}$/.test(item) ? item : this.value(item)]));
53
53
  return value;
54
54
  }
55
55
  error(error) {
@@ -64,6 +64,110 @@ var Redactor = class {
64
64
  };
65
65
  }
66
66
  };
67
+ function isNotFound(error) {
68
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
69
+ }
70
+ async function assertRegular(path) {
71
+ const stat = await lstat(path);
72
+ if (!stat.isFile() || stat.isSymbolicLink()) throw new ImgRelayError("credential_error", "配置或凭据文件必须是普通文件,不能使用符号链接");
73
+ }
74
+ async function writeAtomic(path, value) {
75
+ const temporary = join(dirname(path), `.${randomUUID()}.tmp`);
76
+ const handle = await open(temporary, "wx");
77
+ try {
78
+ await handle.writeFile(`${JSON.stringify(value, null, 2)}\n`, "utf8");
79
+ await handle.sync();
80
+ await handle.close();
81
+ await rename(temporary, path);
82
+ } finally {
83
+ await handle.close().catch(() => {});
84
+ await unlink(temporary).catch(() => {});
85
+ }
86
+ }
87
+ async function readJson(path) {
88
+ await assertRegular(path);
89
+ return JSON.parse(await readFile(path, "utf8"));
90
+ }
91
+ const MAX_JSON_BYTES = 134217728;
92
+ const MAX_IMAGE_BYTES = 33554432;
93
+ async function readBounded(response, limit) {
94
+ if (Number(response.headers.get("content-length")) > limit) {
95
+ await response.body?.cancel();
96
+ throw new ImgRelayError("invalid_response", "上游响应超过大小限制", 3);
97
+ }
98
+ if (!response.body) return Buffer.alloc(0);
99
+ const reader = response.body.getReader();
100
+ const chunks = [];
101
+ let size = 0;
102
+ try {
103
+ for (;;) {
104
+ const { value, done } = await reader.read();
105
+ if (done) break;
106
+ size += value.byteLength;
107
+ if (size > limit) throw new ImgRelayError("invalid_response", "上游响应超过大小限制", 3);
108
+ chunks.push(value);
109
+ }
110
+ return Buffer.concat(chunks, size);
111
+ } finally {
112
+ await reader.cancel().catch(() => {});
113
+ reader.releaseLock();
114
+ }
115
+ }
116
+ function httpError(status, text, redactor) {
117
+ let detail = "";
118
+ try {
119
+ const parsed = JSON.parse(text);
120
+ if (parsed && typeof parsed === "object" && "error" in parsed) {
121
+ const error = parsed.error;
122
+ if (typeof error === "string") detail = error;
123
+ else if (error && typeof error === "object" && "message" in error && typeof error.message === "string") detail = error.message;
124
+ }
125
+ } catch {}
126
+ let category = "upstream_error";
127
+ if (status === 401 || status === 403) category = "auth_error";
128
+ else if (status === 429) category = "rate_limit";
129
+ else if (status === 402 || /insufficient.*(quota|balance)|余额不足/i.test(detail)) category = "quota_exceeded";
130
+ else if (/model.*(not found|not exist|unavailable|invalid)|模型.*(不存在|不可用)/i.test(detail)) category = "model_unavailable";
131
+ else if (/unsupported.*(param|size|quality|format)|unknown parameter|参数.*(不支持|无效)/i.test(detail)) category = "parameter_unsupported";
132
+ return new ImgRelayError(category, redactor.text(`上游返回 HTTP ${status}${detail ? `:${detail.slice(0, 1e3)}` : ",请检查接口、权限和请求参数"}`), 3, status);
133
+ }
134
+ async function requestJson(options) {
135
+ const method = options.method || "GET";
136
+ const attempts = method === "GET" && options.retry ? 2 : 1;
137
+ for (let attempt = 0; attempt < attempts; attempt++) {
138
+ const timeout = AbortSignal.timeout(Math.ceil((options.timeoutSeconds || 15) * 1e3));
139
+ const signal = options.signal ? AbortSignal.any([timeout, options.signal]) : timeout;
140
+ try {
141
+ const response = await fetch(options.url, {
142
+ method,
143
+ headers: {
144
+ Authorization: `Bearer ${options.key}`,
145
+ ...method === "POST" ? { "Content-Type": "application/json" } : {}
146
+ },
147
+ ...options.body === void 0 ? {} : { body: JSON.stringify(options.body) },
148
+ redirect: "manual",
149
+ signal
150
+ });
151
+ const text = (await readBounded(response, response.ok ? MAX_JSON_BYTES : 65536)).toString("utf8");
152
+ if (!response.ok) throw httpError(response.status, text, options.redactor);
153
+ try {
154
+ return JSON.parse(text);
155
+ } catch {
156
+ throw new ImgRelayError("invalid_response", "上游成功响应不是有效 JSON", 3);
157
+ }
158
+ } catch (error) {
159
+ if (options.signal?.aborted) throw new ImgRelayError("interrupted", method === "POST" ? "已停止本地等待,无法保证取消已提交的上游生成" : "用户中断请求", 130);
160
+ const retryable = !(error instanceof ImgRelayError) || error.httpStatus === 429 || error.httpStatus !== void 0 && error.httpStatus >= 500;
161
+ if (attempt + 1 < attempts && retryable) {
162
+ await setTimeout(150);
163
+ continue;
164
+ }
165
+ if (error instanceof ImgRelayError) throw error;
166
+ throw new ImgRelayError(method === "POST" ? "result_unknown" : "upstream_error", method === "POST" ? "生成请求超时或网络断开,结果未知;上游可能仍在生成,请勿直接重复提交" : "模型查询超时或网络失败,请检查地址和网络", 3);
167
+ }
168
+ }
169
+ throw new ImgRelayError("internal_error", "请求执行状态无效", 1);
170
+ }
67
171
  function parseApiUrl(value) {
68
172
  let url;
69
173
  try {
@@ -246,109 +350,86 @@ function resolveParameters(provider, model, supplied) {
246
350
  }
247
351
  return result;
248
352
  }
249
- function isNotFound(error) {
250
- return error instanceof Error && "code" in error && error.code === "ENOENT";
251
- }
252
- async function assertRegular(path) {
253
- const stat = await lstat(path);
254
- if (!stat.isFile() || stat.isSymbolicLink()) throw new ImgRelayError("credential_error", "配置或凭据文件必须是普通文件,不能使用符号链接");
255
- }
256
- async function writeAtomic(path, value) {
257
- const temporary = join(dirname(path), `.${randomUUID()}.tmp`);
258
- const handle = await open(temporary, "wx");
259
- try {
260
- await handle.writeFile(`${JSON.stringify(value, null, 2)}\n`, "utf8");
261
- await handle.sync();
262
- await handle.close();
263
- await rename(temporary, path);
264
- } finally {
265
- await handle.close().catch(() => {});
266
- await unlink(temporary).catch(() => {});
267
- }
268
- }
269
- async function readJson(path) {
270
- await assertRegular(path);
271
- return JSON.parse(await readFile(path, "utf8"));
272
- }
273
- const MAX_JSON_BYTES = 134217728;
274
- const MAX_IMAGE_BYTES = 33554432;
275
- async function readBounded(response, limit) {
276
- if (Number(response.headers.get("content-length")) > limit) {
277
- await response.body?.cancel();
278
- throw new ImgRelayError("invalid_response", "上游响应超过大小限制", 3);
279
- }
280
- if (!response.body) return Buffer.alloc(0);
281
- const reader = response.body.getReader();
282
- const chunks = [];
283
- let size = 0;
284
- try {
285
- for (;;) {
286
- const { value, done } = await reader.read();
287
- if (done) break;
288
- size += value.byteLength;
289
- if (size > limit) throw new ImgRelayError("invalid_response", "上游响应超过大小限制", 3);
290
- chunks.push(value);
291
- }
292
- return Buffer.concat(chunks, size);
293
- } finally {
294
- await reader.cancel().catch(() => {});
295
- reader.releaseLock();
353
+ const parameterNames = [
354
+ "size",
355
+ "n",
356
+ "quality",
357
+ "outputFormat",
358
+ "responseFormat"
359
+ ];
360
+ /** Resolve local configuration without requiring credentials, network or filesystem writes. */
361
+ async function prepareRequest(store, options) {
362
+ if (!options.prompt.trim()) throw new ImgRelayError("input_error", "提示词不能为空");
363
+ for (const name of [
364
+ "provider",
365
+ "model",
366
+ "outputDir"
367
+ ]) if (options[name] !== void 0 && !options[name].trim()) throw new ImgRelayError("input_error", `${name} 不能为空`);
368
+ if (options.timeoutSeconds !== void 0 && (!Number.isFinite(options.timeoutSeconds) || options.timeoutSeconds <= 0 || options.timeoutSeconds > 2147483)) throw new ImgRelayError("input_error", "超时必须是有效的正数秒数");
369
+ if (options.filename !== void 0 && (!options.filename || basename(options.filename) !== options.filename || /[<>:"/\\|?*]/.test(options.filename) || options.filename.split("").some((character) => character.charCodeAt(0) < 32) || !parse(options.filename).name || [".", ".."].includes(options.filename))) throw new ImgRelayError("input_error", "--filename 必须是普通文件名,保存目录使用 --output-dir");
370
+ const selected = await store.selected(options.provider);
371
+ const model = (options.model ?? selected.provider.defaultModel ?? "").trim();
372
+ if (!model) throw new ImgRelayError("config_error", "未配置默认模型,请通过 --model 指定或运行 provider edit");
373
+ const supplied = {};
374
+ const parameterSources = {};
375
+ for (const name of parameterNames) {
376
+ const value = options[name];
377
+ if (value !== void 0) Object.assign(supplied, { [name]: value });
378
+ if (value !== void 0) parameterSources[name] = "explicit";
379
+ else if (selected.provider.defaults[name] !== void 0) parameterSources[name] = "provider_default";
380
+ else if (name === "n") parameterSources.n = "tool_default";
296
381
  }
382
+ return {
383
+ details: {
384
+ promptSource: options.promptSource ?? { type: "api" },
385
+ promptSha256: createHash("sha256").update(options.prompt, "utf8").digest("hex"),
386
+ promptCharacters: options.prompt.length,
387
+ promptUtf8Bytes: Buffer.byteLength(options.prompt, "utf8"),
388
+ provider: selected.name,
389
+ requestedModel: model,
390
+ parameters: {
391
+ n: 1,
392
+ ...selected.provider.defaults,
393
+ ...supplied
394
+ },
395
+ endpoint: resolveEndpoint(selected.provider.baseUrl, selected.provider.endpoints.generate || "/v1/images/generations"),
396
+ capabilityEvidence: {
397
+ known: Object.hasOwn(KNOWN_MODEL_CAPABILITIES, model) ? KNOWN_MODEL_CAPABILITIES[model] || null : null,
398
+ provider: Object.hasOwn(selected.provider.modelOverrides, model) ? selected.provider.modelOverrides[model] || null : null
399
+ },
400
+ outputDir: resolve(options.outputDir ?? "output/imagegen"),
401
+ filename: options.filename ?? null,
402
+ overwrite: Boolean(options.overwrite),
403
+ timeoutSeconds: options.timeoutSeconds ?? selected.provider.timeoutSeconds,
404
+ sources: {
405
+ provider: options.provider !== void 0 ? "explicit" : "default",
406
+ model: options.model !== void 0 ? "explicit" : "provider_default",
407
+ parameters: parameterSources,
408
+ outputDir: options.outputDir !== void 0 ? "explicit" : "tool_default",
409
+ filename: options.filename !== void 0 ? "explicit" : "tool_default",
410
+ overwrite: options.overwrite ? "explicit" : "tool_default",
411
+ timeoutSeconds: options.timeoutSeconds !== void 0 ? "explicit" : "provider_default"
412
+ }
413
+ },
414
+ provider: selected.provider,
415
+ supplied
416
+ };
297
417
  }
298
- function httpError(status, text, redactor) {
299
- let detail = "";
300
- try {
301
- const parsed = JSON.parse(text);
302
- if (parsed && typeof parsed === "object" && "error" in parsed) {
303
- const error = parsed.error;
304
- if (typeof error === "string") detail = error;
305
- else if (error && typeof error === "object" && "message" in error && typeof error.message === "string") detail = error.message;
306
- }
307
- } catch {}
308
- let category = "upstream_error";
309
- if (status === 401 || status === 403) category = "auth_error";
310
- else if (status === 429) category = "rate_limit";
311
- else if (status === 402 || /insufficient.*(quota|balance)|余额不足/i.test(detail)) category = "quota_exceeded";
312
- else if (/model.*(not found|not exist|unavailable|invalid)|模型.*(不存在|不可用)/i.test(detail)) category = "model_unavailable";
313
- else if (/unsupported.*(param|size|quality|format)|unknown parameter|参数.*(不支持|无效)/i.test(detail)) category = "parameter_unsupported";
314
- return new ImgRelayError(category, redactor.text(`上游返回 HTTP ${status}${detail ? `:${detail.slice(0, 1e3)}` : ",请检查接口、权限和请求参数"}`), 3, status);
418
+ function validateRequest(prepared) {
419
+ prepared.details.parameters = resolveParameters(prepared.provider, prepared.details.requestedModel, prepared.supplied);
420
+ for (const name of parameterNames) if (prepared.details.parameters[name] === void 0) delete prepared.details.sources.parameters[name];
315
421
  }
316
- async function requestJson(options) {
317
- const method = options.method || "GET";
318
- const attempts = method === "GET" && options.retry ? 2 : 1;
319
- for (let attempt = 0; attempt < attempts; attempt++) {
320
- const timeout = AbortSignal.timeout(Math.ceil((options.timeoutSeconds || 15) * 1e3));
321
- const signal = options.signal ? AbortSignal.any([timeout, options.signal]) : timeout;
322
- try {
323
- const response = await fetch(options.url, {
324
- method,
325
- headers: {
326
- Authorization: `Bearer ${options.key}`,
327
- ...method === "POST" ? { "Content-Type": "application/json" } : {}
328
- },
329
- ...options.body === void 0 ? {} : { body: JSON.stringify(options.body) },
330
- redirect: "manual",
331
- signal
332
- });
333
- const text = (await readBounded(response, response.ok ? MAX_JSON_BYTES : 65536)).toString("utf8");
334
- if (!response.ok) throw httpError(response.status, text, options.redactor);
335
- try {
336
- return JSON.parse(text);
337
- } catch {
338
- throw new ImgRelayError("invalid_response", "上游成功响应不是有效 JSON", 3);
339
- }
340
- } catch (error) {
341
- if (options.signal?.aborted) throw new ImgRelayError("interrupted", method === "POST" ? "已停止本地等待,无法保证取消已提交的上游生成" : "用户中断请求", 130);
342
- const retryable = !(error instanceof ImgRelayError) || error.httpStatus === 429 || error.httpStatus !== void 0 && error.httpStatus >= 500;
343
- if (attempt + 1 < attempts && retryable) {
344
- await setTimeout(150);
345
- continue;
346
- }
347
- if (error instanceof ImgRelayError) throw error;
348
- throw new ImgRelayError(method === "POST" ? "result_unknown" : "upstream_error", method === "POST" ? "生成请求超时或网络断开,结果未知;上游可能仍在生成,请勿直接重复提交" : "模型查询超时或网络失败,请检查地址和网络", 3);
349
- }
350
- }
351
- throw new ImgRelayError("internal_error", "请求执行状态无效", 1);
422
+ async function previewGenerate(store, options) {
423
+ const prepared = await prepareRequest(store, options);
424
+ validateRequest(prepared);
425
+ if (options.signal?.aborted) throw new ImgRelayError("interrupted", "用户中断,未提交生成请求", 130);
426
+ return {
427
+ ...prepared.details,
428
+ dryRun: true,
429
+ credentialConfigured: Boolean(prepared.provider.apiKey),
430
+ submissionStatus: "not_submitted",
431
+ willSubmitNetworkRequest: false
432
+ };
352
433
  }
353
434
  function base64Bytes(value) {
354
435
  const encoded = value.replace(/^data:image\/[^;,]+;base64,/, "").replace(/\s/g, "");
@@ -400,42 +481,16 @@ function usageNumbers(value, depth = 0) {
400
481
  return entries.length ? Object.fromEntries(entries) : void 0;
401
482
  }
402
483
  async function generate(store, options) {
403
- if (!options.prompt.trim()) throw new ImgRelayError("input_error", "提示词不能为空");
404
- if (options.timeoutSeconds !== void 0 && (!Number.isFinite(options.timeoutSeconds) || options.timeoutSeconds <= 0 || options.timeoutSeconds > 2147483)) throw new ImgRelayError("input_error", "超时必须是有效的正数秒数");
405
- if (options.filename && (basename(options.filename) !== options.filename || /[<>:"/\\|?*]/.test(options.filename) || options.filename.split("").some((character) => character.charCodeAt(0) < 32) || !parse(options.filename).name || [".", ".."].includes(options.filename))) throw new ImgRelayError("input_error", "--filename 必须是普通文件名,保存目录使用 --output-dir");
406
- const selected = await store.selected(options.provider);
407
- const model = (options.model || selected.provider.defaultModel || "").trim();
408
- if (!model) throw new ImgRelayError("config_error", "未配置默认模型,请通过 --model 指定或运行 provider edit");
409
- const key = await store.key(selected.provider);
410
- const outputDir = resolve(options.outputDir || "output/imagegen");
484
+ const prepared = await prepareRequest(store, options);
485
+ const { outputDir, requestedModel: model } = prepared.details;
486
+ const key = await store.key(prepared.provider);
411
487
  const requestId = randomUUID();
412
488
  const recordPath = join(outputDir, `${requestId}-report.json`);
413
- const supplied = {};
414
- for (const name of [
415
- "size",
416
- "n",
417
- "quality",
418
- "outputFormat",
419
- "responseFormat"
420
- ]) {
421
- const value = options[name];
422
- if (value !== void 0) Object.assign(supplied, { [name]: value });
423
- }
424
489
  const data = {
490
+ ...prepared.details,
425
491
  requestId,
426
- provider: selected.name,
427
- requestedModel: model,
428
- requestedCount: supplied.n || selected.provider.defaults.n || 1,
492
+ requestedCount: prepared.details.parameters.n || 1,
429
493
  returnedCount: 0,
430
- parameters: {
431
- ...selected.provider.defaults,
432
- ...supplied
433
- },
434
- endpoint: resolveEndpoint(selected.provider.baseUrl, selected.provider.endpoints.generate || "/v1/images/generations"),
435
- capabilityEvidence: {
436
- known: Object.hasOwn(KNOWN_MODEL_CAPABILITIES, model) ? KNOWN_MODEL_CAPABILITIES[model] || null : null,
437
- provider: Object.hasOwn(selected.provider.modelOverrides, model) ? selected.provider.modelOverrides[model] || null : null
438
- },
439
494
  images: [],
440
495
  failures: [],
441
496
  recordPath,
@@ -468,7 +523,8 @@ async function generate(store, options) {
468
523
  }
469
524
  let outcome;
470
525
  try {
471
- data.parameters = resolveParameters(selected.provider, model, supplied);
526
+ validateRequest(prepared);
527
+ data.parameters = prepared.details.parameters;
472
528
  const body = {
473
529
  model,
474
530
  prompt: options.prompt
@@ -489,7 +545,7 @@ async function generate(store, options) {
489
545
  redactor: store.redactor,
490
546
  method: "POST",
491
547
  body,
492
- timeoutSeconds: options.timeoutSeconds || selected.provider.timeoutSeconds,
548
+ timeoutSeconds: data.timeoutSeconds,
493
549
  ...options.signal ? { signal: options.signal } : {}
494
550
  });
495
551
  data.submissionStatus = "result_received";
@@ -862,7 +918,63 @@ var Store = class {
862
918
  };
863
919
  //#endregion
864
920
  //#region package.json
865
- var version = "0.2.0";
921
+ var version = "0.3.0";
922
+ //#endregion
923
+ //#region src/prompt.ts
924
+ function interrupted() {
925
+ return new ImgRelayError("interrupted", "用户中断读取提示词,未提交生成请求", 130);
926
+ }
927
+ async function readPrompt(flags, signal, stdin = process.stdin) {
928
+ if (Number(flags.promptFile !== void 0) + Number(Boolean(flags.promptStdin)) !== 1) throw new ImgRelayError("input_error", "必须且只能指定 --prompt-file 或 --prompt-stdin");
929
+ if (signal?.aborted) throw interrupted();
930
+ let bytes;
931
+ let promptSource;
932
+ if (flags.promptFile !== void 0) {
933
+ if (!flags.promptFile.trim()) throw new ImgRelayError("input_error", "--prompt-file 路径不能为空");
934
+ const path = resolve(flags.promptFile);
935
+ try {
936
+ bytes = await readFile(path, signal ? { signal } : {});
937
+ } catch {
938
+ if (signal?.aborted) throw interrupted();
939
+ throw new ImgRelayError("input_error", "无法读取 --prompt-file;请检查文件路径及访问权限");
940
+ }
941
+ promptSource = {
942
+ type: "file",
943
+ path
944
+ };
945
+ } else {
946
+ if (stdin.isTTY) throw new ImgRelayError("input_error", "--prompt-stdin 需要管道或重定向输入;也可使用 --prompt-file");
947
+ const abort = () => stdin.destroy(interrupted());
948
+ signal?.addEventListener("abort", abort, { once: true });
949
+ const chunks = [];
950
+ try {
951
+ for await (const chunk of stdin) chunks.push(Buffer.from(chunk));
952
+ bytes = Buffer.concat(chunks);
953
+ } catch {
954
+ if (signal?.aborted) throw interrupted();
955
+ throw new ImgRelayError("input_error", "无法读取 stdin 提示词");
956
+ } finally {
957
+ signal?.removeEventListener("abort", abort);
958
+ }
959
+ promptSource = { type: "stdin" };
960
+ }
961
+ if (signal?.aborted) throw interrupted();
962
+ let prompt;
963
+ try {
964
+ prompt = new TextDecoder("utf-8", {
965
+ fatal: true,
966
+ ignoreBOM: true
967
+ }).decode(bytes);
968
+ } catch {
969
+ throw new ImgRelayError("input_error", "提示词必须是有效 UTF-8 文本");
970
+ }
971
+ if (prompt.startsWith("")) prompt = prompt.slice(1);
972
+ if (!prompt.trim()) throw new ImgRelayError("input_error", "提示词不能为空或全空白");
973
+ return {
974
+ prompt,
975
+ promptSource
976
+ };
977
+ }
866
978
  //#endregion
867
979
  //#region src/provider.ts
868
980
  function answer(value) {
@@ -1085,13 +1197,12 @@ program.command("doctor").description("检查配置与模型接口,不生成
1085
1197
  ...result.error ? { error: result.error } : {}
1086
1198
  });
1087
1199
  });
1088
- program.command("generate").description("生成图片并保存原图和记录").option("--prompt <文本>", "直接提供非空提示词(必填)").option("--provider <名称>", "本次使用的供应商").option("--model <ID>", "本次使用的模型").option("--size <尺寸>", "图片尺寸,如 auto 或 1024x1024").option("--n <数量>", "请求图片数量,不自动拆单").option("--quality <质量>", "请求质量").option("--output-format <格式>", "请求图片格式").option("--output-dir <目录>", "保存目录,默认 output/imagegen").option("--filename <名称>", "文件名;多图追加序号,扩展名按实际格式").option("--overwrite", "允许覆盖图片文件").option("--timeout <秒数>", "生成等待超时,默认 600 秒").action(async (flags) => {
1200
+ program.command("generate").description("生成图片并保存原图和记录").allowExcessArguments(false).option("--prompt-file <路径>", "读取 UTF-8 提示词文件,与 --prompt-stdin 互斥").option("--prompt-stdin", "从管道或重定向读取 UTF-8 提示词,与 --prompt-file 互斥").option("--dry-run", "离线预览有效请求,不联网、不写文件,无需密钥").option("--provider <名称>", "本次使用的供应商").option("--model <ID>", "本次使用的模型").option("--size <尺寸>", "图片尺寸,如 auto 或 1024x1024").option("--n <数量>", "请求图片数量,不自动拆单").option("--quality <质量>", "请求质量").option("--output-format <格式>", "请求图片格式").option("--output-dir <目录>", "保存目录,默认 output/imagegen").option("--filename <名称>", "文件名;多图追加序号,扩展名按实际格式").option("--overwrite", "允许覆盖图片文件").option("--timeout <秒数>", "生成等待超时,默认 600 秒").action(async (flags) => {
1089
1201
  const current = active("generate");
1090
- if (flags.prompt === void 0) throw new ImgRelayError("input_error", "请通过 --prompt 提供非空提示词");
1091
- const result = await generate(current, {
1092
- prompt: flags.prompt,
1093
- ...flags.provider ? { provider: flags.provider } : {},
1094
- ...flags.model ? { model: flags.model } : {},
1202
+ const options = {
1203
+ ...await readPrompt(flags, controller.signal),
1204
+ ...flags.provider !== void 0 ? { provider: flags.provider } : {},
1205
+ ...flags.model !== void 0 ? { model: flags.model } : {},
1095
1206
  ...flags.size !== void 0 ? { size: flags.size } : {},
1096
1207
  ...flags.n !== void 0 ? { n: Number(flags.n) } : {},
1097
1208
  ...flags.quality !== void 0 ? { quality: flags.quality } : {},
@@ -1102,7 +1213,12 @@ program.command("generate").description("生成图片并保存原图和记录").
1102
1213
  overwrite: Boolean(flags.overwrite),
1103
1214
  signal: controller.signal,
1104
1215
  progress: (message) => process.stderr.write(`${message}\n`)
1105
- });
1216
+ };
1217
+ if (flags.dryRun) {
1218
+ output(await previewGenerate(current, options));
1219
+ return;
1220
+ }
1221
+ const result = await generate(current, options);
1106
1222
  output(result.data, {
1107
1223
  status: result.status,
1108
1224
  exitCode: result.exitCode,
@@ -1120,7 +1236,9 @@ try {
1120
1236
  if (json) output({ help: helpOutput.trim() });
1121
1237
  process.exitCode = 0;
1122
1238
  } else {
1123
- const failure = error instanceof CommanderError ? new ImgRelayError("input_error", error.message) : error;
1239
+ const removedPrompt = error instanceof CommanderError && error.code === "commander.unknownOption" && (error.message.includes("'--prompt'") || error.message.includes("'--prompt="));
1240
+ if (removedPrompt) commandName = "generate";
1241
+ const failure = error instanceof CommanderError ? new ImgRelayError("input_error", removedPrompt ? "--prompt 已移除,请改用 --prompt-file <路径> 或 --prompt-stdin" : error.message) : error;
1124
1242
  const info = store ? store.redactor.error(failure) : {
1125
1243
  category: failure instanceof ImgRelayError ? failure.category : "internal_error",
1126
1244
  message: failure instanceof Error ? failure.message : "发生未知错误"
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["packageJson.version"],"sources":["../../core/dist/index.mjs","../package.json","../src/provider.ts","../src/index.ts"],"sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { access, lstat, mkdir, open, readFile, rename, rmdir, unlink, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join, parse, resolve } from \"node:path\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport { imageSize } from \"image-size\";\nimport { z } from \"zod\";\nimport { setTimeout } from \"node:timers/promises\";\nimport { homedir } from \"node:os\";\n\n//#region src/errors.ts\nvar ImgRelayError = class extends Error {\n\tcategory;\n\texitCode;\n\thttpStatus;\n\tconstructor(category, message, exitCode = 2, httpStatus) {\n\t\tsuper(message);\n\t\tthis.name = \"ImgRelayError\";\n\t\tthis.category = category;\n\t\tthis.exitCode = exitCode;\n\t\tthis.httpStatus = httpStatus;\n\t}\n};\n/** Redact before serialization; never retain an upstream response as a diagnostic. */\nvar Redactor = class {\n\tsecrets = /* @__PURE__ */ new Set();\n\tadd(secret) {\n\t\tif (secret) this.secrets.add(secret);\n\t}\n\ttext(value) {\n\t\tlet text = value;\n\t\tfor (const secret of [...this.secrets].toSorted((a, b) => b.length - a.length)) text = text.replaceAll(secret, \"[REDACTED]\");\n\t\treturn text.replace(/https?:\\/\\/[^\\s<>\"']+/gi, (raw) => {\n\t\t\ttry {\n\t\t\t\tconst url = new URL(raw);\n\t\t\t\tif (url.username || url.password) {\n\t\t\t\t\turl.username = \"REDACTED\";\n\t\t\t\t\turl.password = \"\";\n\t\t\t\t}\n\t\t\t\tif (url.search) url.search = \"?REDACTED\";\n\t\t\t\tif (url.hash) url.hash = \"#REDACTED\";\n\t\t\t\treturn url.toString();\n\t\t\t} catch {\n\t\t\t\treturn \"[REDACTED_URL]\";\n\t\t\t}\n\t\t});\n\t}\n\tvalue(value) {\n\t\tif (typeof value === \"string\") return this.text(value);\n\t\tif (Array.isArray(value)) return value.map((item) => this.value(item));\n\t\tif (value && typeof value === \"object\") return Object.fromEntries(Object.entries(value).map(([key, item]) => [this.text(key), this.value(item)]));\n\t\treturn value;\n\t}\n\terror(error) {\n\t\tif (error instanceof ImgRelayError) return {\n\t\t\tcategory: error.category,\n\t\t\tmessage: this.text(error.message),\n\t\t\t...error.httpStatus === void 0 ? {} : { httpStatus: error.httpStatus }\n\t\t};\n\t\treturn {\n\t\t\tcategory: \"internal_error\",\n\t\t\tmessage: this.text(error instanceof Error ? error.message : \"发生未知错误\")\n\t\t};\n\t}\n};\n\n//#endregion\n//#region src/urls.ts\nfunction parseApiUrl(value) {\n\tlet url;\n\ttry {\n\t\turl = new URL(value);\n\t} catch {\n\t\tthrow new ImgRelayError(\"config_error\", \"API 地址必须是完整的 HTTP 或 HTTPS URL\");\n\t}\n\tif (![\"http:\", \"https:\"].includes(url.protocol) || url.username || url.password || url.search || url.hash) throw new ImgRelayError(\"config_error\", \"API 地址只能使用 HTTP(S),不能包含凭据、查询参数或片段\");\n\treturn url;\n}\nfunction normalizeBaseUrl(value) {\n\treturn normalizeAddress(value).baseUrl;\n}\nfunction normalizeAddress(value) {\n\tconst url = parseApiUrl(value);\n\tconst path = url.pathname.replace(/\\/+$/, \"\");\n\tconst isGeneration = path.endsWith(\"/images/generations\");\n\turl.pathname = isGeneration ? path.slice(0, -19) : path;\n\treturn {\n\t\tbaseUrl: url.toString().replace(/\\/+$/, \"\"),\n\t\t...isGeneration ? { generationPath: \"/images/generations\" } : {}\n\t};\n}\nfunction validateEndpoint(path) {\n\ttry {\n\t\treturn path.startsWith(\"/\") && !/[?#\\\\]/.test(path) && !path.includes(\"//\") && !path.split(\"/\").some((part) => [\"..\", \".\"].includes(decodeURIComponent(part)));\n\t} catch {\n\t\treturn false;\n\t}\n}\nfunction resolveEndpoint(baseUrl, endpoint) {\n\tif (!validateEndpoint(endpoint)) throw new ImgRelayError(\"config_error\", \"端点必须是路径,不能包含主机、查询参数或上级目录\");\n\tconst url = parseApiUrl(baseUrl);\n\tconst basePath = url.pathname.replace(/\\/+$/, \"\");\n\turl.pathname = `${basePath}${basePath.endsWith(\"/v1\") && endpoint.startsWith(\"/v1/\") ? endpoint.slice(3) : endpoint}`;\n\treturn url.toString();\n}\n\n//#endregion\n//#region src/schema.ts\nconst shortText = z.string().trim().min(1).max(256);\nconst providerNameSchema = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/);\nconst parameterSchema = z.strictObject({\n\tsize: shortText.optional(),\n\tn: z.number().int().positive().optional(),\n\tquality: shortText.optional(),\n\toutputFormat: shortText.optional(),\n\tresponseFormat: z.enum([\"url\", \"b64_json\"]).optional()\n});\nconst parameterCapabilitySchema = z.strictObject({\n\tsupported: z.boolean().optional(),\n\tvalues: z.array(shortText).min(1).optional(),\n\tmin: z.number().optional(),\n\tmax: z.number().optional()\n});\nconst modelCapabilitySchema = z.strictObject({\n\tsource: z.enum([\n\t\t\"official_documentation\",\n\t\t\"provider_override\",\n\t\t\"call_verification\"\n\t]).default(\"provider_override\"),\n\tsourceUrl: z.url().optional(),\n\tverifiedAt: z.iso.datetime().optional(),\n\tparameters: z.strictObject({\n\t\tsize: parameterCapabilitySchema.optional(),\n\t\tn: parameterCapabilitySchema.optional(),\n\t\tquality: parameterCapabilitySchema.optional(),\n\t\toutputFormat: parameterCapabilitySchema.optional(),\n\t\tresponseFormat: parameterCapabilitySchema.optional()\n\t})\n});\nconst endpointSchema = z.string().max(1024).refine((value) => {\n\ttry {\n\t\treturn validateEndpoint(value);\n\t} catch {\n\t\treturn false;\n\t}\n}, \"端点必须是有效路径\");\nconst providerSchema = z.strictObject({\n\tprotocol: z.literal(\"openai-images\"),\n\tbaseUrl: z.string(),\n\tapiKey: z.string().trim().min(1).refine((key) => !/[\\r\\n\\0]/.test(key), \"密钥不能包含换行或空字符\").optional(),\n\tdefaultModel: shortText.optional(),\n\tdefaults: parameterSchema.default({}),\n\tendpoints: z.strictObject({\n\t\tgenerate: endpointSchema.optional(),\n\t\tmodels: endpointSchema.optional()\n\t}).default({}),\n\tmodelOverrides: z.record(shortText, modelCapabilitySchema).default({}),\n\ttimeoutSeconds: z.number().positive().max(2147483).finite().default(600),\n\trevision: z.number().int().positive().default(1)\n}).transform((provider) => {\n\tconst address = normalizeAddress(provider.baseUrl);\n\treturn {\n\t\t...provider,\n\t\tbaseUrl: address.baseUrl,\n\t\tendpoints: address.generationPath && !provider.endpoints.generate ? {\n\t\t\t...provider.endpoints,\n\t\t\tgenerate: address.generationPath\n\t\t} : provider.endpoints\n\t};\n});\nconst configSchema = z.strictObject({\n\tschemaVersion: z.literal(1),\n\tdefaultProvider: providerNameSchema.optional(),\n\tproviders: z.record(providerNameSchema, providerSchema)\n});\nfunction parseProvider(input) {\n\tconst result = providerSchema.safeParse(input);\n\tif (!result.success) throw new ImgRelayError(\"config_error\", `供应商配置无效:${result.error.issues.map((issue) => `${issue.path.join(\".\")} ${issue.message}`).join(\";\")}`);\n\treturn result.data;\n}\nconst CUBENCE_PRESET = {\n\tprotocol: \"openai-images\",\n\tbaseUrl: \"https://api-lb.cubence.ai/v1\",\n\tdefaultModel: \"gpt-image-2.5-flare\",\n\tdefaults: {\n\t\tsize: \"auto\",\n\t\tn: 1,\n\t\tquality: \"high\",\n\t\toutputFormat: \"png\"\n\t}\n};\n\n//#endregion\n//#region src/capabilities.ts\nconst GPT_IMAGE_CAPABILITY = {\n\tsource: \"official_documentation\",\n\tsourceUrl: \"https://developers.openai.com/api/reference/python/resources/images/methods/generate\",\n\tverifiedAt: \"2026-10-10T10:03:00.000Z\",\n\tparameters: {\n\t\tn: {\n\t\t\tmin: 1,\n\t\t\tmax: 10\n\t\t},\n\t\tsize: { values: [\n\t\t\t\"auto\",\n\t\t\t\"1024x1024\",\n\t\t\t\"1536x1024\",\n\t\t\t\"1024x1536\"\n\t\t] },\n\t\tquality: { values: [\n\t\t\t\"auto\",\n\t\t\t\"low\",\n\t\t\t\"medium\",\n\t\t\t\"high\"\n\t\t] },\n\t\toutputFormat: { values: [\n\t\t\t\"png\",\n\t\t\t\"jpeg\",\n\t\t\t\"webp\"\n\t\t] },\n\t\tresponseFormat: { supported: false }\n\t}\n};\nconst KNOWN_MODEL_CAPABILITIES = {\n\t\"gpt-image-1\": GPT_IMAGE_CAPABILITY,\n\t\"gpt-image-1-mini\": GPT_IMAGE_CAPABILITY\n};\nfunction resolveParameters(provider, model, supplied) {\n\tconst parsed = parameterSchema.safeParse({\n\t\tn: 1,\n\t\t...provider.defaults,\n\t\t...supplied\n\t});\n\tif (!parsed.success) throw new ImgRelayError(\"input_error\", \"生成参数无效:数量必须是正整数,各参数必须是非空字符串\");\n\tconst result = parsed.data;\n\tconst known = Object.hasOwn(KNOWN_MODEL_CAPABILITIES, model) ? KNOWN_MODEL_CAPABILITIES[model] : void 0;\n\tconst override = Object.hasOwn(provider.modelOverrides, model) ? provider.modelOverrides[model] : void 0;\n\tconst limits = {\n\t\t...known?.parameters,\n\t\t...override?.parameters\n\t};\n\tfor (const name of [\n\t\t\"size\",\n\t\t\"n\",\n\t\t\"quality\",\n\t\t\"outputFormat\",\n\t\t\"responseFormat\"\n\t]) {\n\t\tconst value = result[name];\n\t\tconst limit = limits[name];\n\t\tif (value === void 0 || !limit) continue;\n\t\tif (limit.supported === false && name === \"n\" && supplied.n === void 0 && provider.defaults.n === void 0) {\n\t\t\tdelete result.n;\n\t\t\tcontinue;\n\t\t}\n\t\tif (limit.supported === false || limit.values && !limit.values.includes(String(value)) || typeof value === \"number\" && (limit.min !== void 0 && value < limit.min || limit.max !== void 0 && value > limit.max)) throw new ImgRelayError(\"parameter_unsupported\", `模型 ${model} 不支持参数 ${name}=${value};请检查模型能力或供应商覆盖`, 2);\n\t}\n\treturn result;\n}\n\n//#endregion\n//#region src/files.ts\nfunction isNotFound(error) {\n\treturn error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\nasync function assertRegular(path) {\n\tconst stat = await lstat(path);\n\tif (!stat.isFile() || stat.isSymbolicLink()) throw new ImgRelayError(\"credential_error\", \"配置或凭据文件必须是普通文件,不能使用符号链接\");\n}\nasync function writeAtomic(path, value) {\n\tconst temporary = join(dirname(path), `.${randomUUID()}.tmp`);\n\tconst handle = await open(temporary, \"wx\");\n\ttry {\n\t\tawait handle.writeFile(`${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n\t\tawait handle.sync();\n\t\tawait handle.close();\n\t\tawait rename(temporary, path);\n\t} finally {\n\t\tawait handle.close().catch(() => {});\n\t\tawait unlink(temporary).catch(() => {});\n\t}\n}\nasync function readJson(path) {\n\tawait assertRegular(path);\n\treturn JSON.parse(await readFile(path, \"utf8\"));\n}\n\n//#endregion\n//#region src/http.ts\nconst MAX_JSON_BYTES = 134217728;\nconst MAX_IMAGE_BYTES = 33554432;\nasync function readBounded(response, limit) {\n\tif (Number(response.headers.get(\"content-length\")) > limit) {\n\t\tawait response.body?.cancel();\n\t\tthrow new ImgRelayError(\"invalid_response\", \"上游响应超过大小限制\", 3);\n\t}\n\tif (!response.body) return Buffer.alloc(0);\n\tconst reader = response.body.getReader();\n\tconst chunks = [];\n\tlet size = 0;\n\ttry {\n\t\tfor (;;) {\n\t\t\tconst { value, done } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tsize += value.byteLength;\n\t\t\tif (size > limit) throw new ImgRelayError(\"invalid_response\", \"上游响应超过大小限制\", 3);\n\t\t\tchunks.push(value);\n\t\t}\n\t\treturn Buffer.concat(chunks, size);\n\t} finally {\n\t\tawait reader.cancel().catch(() => {});\n\t\treader.releaseLock();\n\t}\n}\nfunction httpError(status, text, redactor) {\n\tlet detail = \"\";\n\ttry {\n\t\tconst parsed = JSON.parse(text);\n\t\tif (parsed && typeof parsed === \"object\" && \"error\" in parsed) {\n\t\t\tconst error = parsed.error;\n\t\t\tif (typeof error === \"string\") detail = error;\n\t\t\telse if (error && typeof error === \"object\" && \"message\" in error && typeof error.message === \"string\") detail = error.message;\n\t\t}\n\t} catch {}\n\tlet category = \"upstream_error\";\n\tif (status === 401 || status === 403) category = \"auth_error\";\n\telse if (status === 429) category = \"rate_limit\";\n\telse if (status === 402 || /insufficient.*(quota|balance)|余额不足/i.test(detail)) category = \"quota_exceeded\";\n\telse if (/model.*(not found|not exist|unavailable|invalid)|模型.*(不存在|不可用)/i.test(detail)) category = \"model_unavailable\";\n\telse if (/unsupported.*(param|size|quality|format)|unknown parameter|参数.*(不支持|无效)/i.test(detail)) category = \"parameter_unsupported\";\n\treturn new ImgRelayError(category, redactor.text(`上游返回 HTTP ${status}${detail ? `:${detail.slice(0, 1e3)}` : \",请检查接口、权限和请求参数\"}`), 3, status);\n}\nasync function requestJson(options) {\n\tconst method = options.method || \"GET\";\n\tconst attempts = method === \"GET\" && options.retry ? 2 : 1;\n\tfor (let attempt = 0; attempt < attempts; attempt++) {\n\t\tconst timeout = AbortSignal.timeout(Math.ceil((options.timeoutSeconds || 15) * 1e3));\n\t\tconst signal = options.signal ? AbortSignal.any([timeout, options.signal]) : timeout;\n\t\ttry {\n\t\t\tconst response = await fetch(options.url, {\n\t\t\t\tmethod,\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${options.key}`,\n\t\t\t\t\t...method === \"POST\" ? { \"Content-Type\": \"application/json\" } : {}\n\t\t\t\t},\n\t\t\t\t...options.body === void 0 ? {} : { body: JSON.stringify(options.body) },\n\t\t\t\tredirect: \"manual\",\n\t\t\t\tsignal\n\t\t\t});\n\t\t\tconst text = (await readBounded(response, response.ok ? MAX_JSON_BYTES : 65536)).toString(\"utf8\");\n\t\t\tif (!response.ok) throw httpError(response.status, text, options.redactor);\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(text);\n\t\t\t} catch {\n\t\t\t\tthrow new ImgRelayError(\"invalid_response\", \"上游成功响应不是有效 JSON\", 3);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (options.signal?.aborted) throw new ImgRelayError(\"interrupted\", method === \"POST\" ? \"已停止本地等待,无法保证取消已提交的上游生成\" : \"用户中断请求\", 130);\n\t\t\tconst retryable = !(error instanceof ImgRelayError) || error.httpStatus === 429 || error.httpStatus !== void 0 && error.httpStatus >= 500;\n\t\t\tif (attempt + 1 < attempts && retryable) {\n\t\t\t\tawait setTimeout(150);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (error instanceof ImgRelayError) throw error;\n\t\t\tthrow new ImgRelayError(method === \"POST\" ? \"result_unknown\" : \"upstream_error\", method === \"POST\" ? \"生成请求超时或网络断开,结果未知;上游可能仍在生成,请勿直接重复提交\" : \"模型查询超时或网络失败,请检查地址和网络\", 3);\n\t\t}\n\t}\n\tthrow new ImgRelayError(\"internal_error\", \"请求执行状态无效\", 1);\n}\n\n//#endregion\n//#region src/generate.ts\nfunction base64Bytes(value) {\n\tconst encoded = value.replace(/^data:image\\/[^;,]+;base64,/, \"\").replace(/\\s/g, \"\");\n\tif (encoded.length > Math.ceil(33554432 / 3) * 4 || !/^[A-Za-z0-9+/]+={0,2}$/.test(encoded) || encoded.length % 4 === 1) throw new ImgRelayError(\"image_decode_error\", \"Base64 图片无效或超过 32 MiB 限制\", 3);\n\tconst bytes = Buffer.from(encoded, \"base64\");\n\tif (bytes.length > 33554432 || bytes.toString(\"base64\").replace(/=+$/, \"\") !== encoded.replace(/=+$/, \"\")) throw new ImgRelayError(\"image_decode_error\", \"Base64 图片解码失败\", 3);\n\treturn bytes;\n}\nasync function download(urlString, signal) {\n\tlet current = urlString;\n\ttry {\n\t\tfor (let redirects = 0; redirects <= 3; redirects++) {\n\t\t\tconst url = new URL(current);\n\t\t\tif (![\"http:\", \"https:\"].includes(url.protocol) || url.username || url.password) throw new ImgRelayError(\"image_download_error\", \"图片地址必须为不含内嵌凭据的 HTTP(S) URL\", 3);\n\t\t\tconst timeout = AbortSignal.timeout(6e4);\n\t\t\tconst response = await fetch(url, {\n\t\t\t\tredirect: \"manual\",\n\t\t\t\tsignal: signal ? AbortSignal.any([signal, timeout]) : timeout\n\t\t\t});\n\t\t\tif (response.status >= 300 && response.status < 400) {\n\t\t\t\tconst location = response.headers.get(\"location\");\n\t\t\t\tawait response.body?.cancel();\n\t\t\t\tif (!location) throw new ImgRelayError(\"image_download_error\", \"图片重定向缺少目标地址\", 3);\n\t\t\t\tcurrent = new URL(location, url).toString();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!response.ok) {\n\t\t\t\tawait response.body?.cancel();\n\t\t\t\tthrow new ImgRelayError(\"image_download_error\", `图片下载返回 HTTP ${response.status}`, 3, response.status);\n\t\t\t}\n\t\t\treturn await readBounded(response, MAX_IMAGE_BYTES);\n\t\t}\n\t\tthrow new ImgRelayError(\"image_download_error\", \"图片下载重定向超过三次\", 3);\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new ImgRelayError(\"interrupted\", \"已停止本地保存;无法保证取消已提交的上游生成\", 130);\n\t\tif (error instanceof ImgRelayError) throw error;\n\t\tthrow new ImgRelayError(\"image_download_error\", \"图片下载超时或网络失败;不会重新生成图片\", 3);\n\t}\n}\nfunction usageNumbers(value, depth = 0) {\n\tif (depth > 4) return void 0;\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return void 0;\n\tconst entries = Object.entries(value).slice(0, 100).flatMap(([key, item]) => {\n\t\tif (!/^[a-z_][a-z0-9_]{0,63}$/i.test(key)) return [];\n\t\tconst result = usageNumbers(item, depth + 1);\n\t\treturn result === void 0 ? [] : [[key, result]];\n\t});\n\treturn entries.length ? Object.fromEntries(entries) : void 0;\n}\nasync function generate(store, options) {\n\tif (!options.prompt.trim()) throw new ImgRelayError(\"input_error\", \"提示词不能为空\");\n\tif (options.timeoutSeconds !== void 0 && (!Number.isFinite(options.timeoutSeconds) || options.timeoutSeconds <= 0 || options.timeoutSeconds > 2147483)) throw new ImgRelayError(\"input_error\", \"超时必须是有效的正数秒数\");\n\tif (options.filename && (basename(options.filename) !== options.filename || /[<>:\"/\\\\|?*]/.test(options.filename) || options.filename.split(\"\").some((character) => character.charCodeAt(0) < 32) || !parse(options.filename).name || [\".\", \"..\"].includes(options.filename))) throw new ImgRelayError(\"input_error\", \"--filename 必须是普通文件名,保存目录使用 --output-dir\");\n\tconst selected = await store.selected(options.provider);\n\tconst model = (options.model || selected.provider.defaultModel || \"\").trim();\n\tif (!model) throw new ImgRelayError(\"config_error\", \"未配置默认模型,请通过 --model 指定或运行 provider edit\");\n\tconst key = await store.key(selected.provider);\n\tconst outputDir = resolve(options.outputDir || \"output/imagegen\");\n\tconst requestId = randomUUID();\n\tconst recordPath = join(outputDir, `${requestId}-report.json`);\n\tconst supplied = {};\n\tfor (const name of [\n\t\t\"size\",\n\t\t\"n\",\n\t\t\"quality\",\n\t\t\"outputFormat\",\n\t\t\"responseFormat\"\n\t]) {\n\t\tconst value = options[name];\n\t\tif (value !== void 0) Object.assign(supplied, { [name]: value });\n\t}\n\tconst data = {\n\t\trequestId,\n\t\tprovider: selected.name,\n\t\trequestedModel: model,\n\t\trequestedCount: supplied.n || selected.provider.defaults.n || 1,\n\t\treturnedCount: 0,\n\t\tparameters: {\n\t\t\t...selected.provider.defaults,\n\t\t\t...supplied\n\t\t},\n\t\tendpoint: resolveEndpoint(selected.provider.baseUrl, selected.provider.endpoints.generate || \"/v1/images/generations\"),\n\t\tcapabilityEvidence: {\n\t\t\tknown: Object.hasOwn(KNOWN_MODEL_CAPABILITIES, model) ? KNOWN_MODEL_CAPABILITIES[model] || null : null,\n\t\t\tprovider: Object.hasOwn(selected.provider.modelOverrides, model) ? selected.provider.modelOverrides[model] || null : null\n\t\t},\n\t\timages: [],\n\t\tfailures: [],\n\t\trecordPath,\n\t\tsubmissionStatus: \"not_submitted\"\n\t};\n\tconst record = {\n\t\tschemaVersion: 1,\n\t\tcreatedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tprompt: options.prompt,\n\t\t...data\n\t};\n\ttry {\n\t\tawait mkdir(outputDir, { recursive: true });\n\t\tif (options.filename && !options.overwrite) try {\n\t\t\tawait access(join(outputDir, options.filename));\n\t\t\tthrow new ImgRelayError(\"save_error\", \"目标文件已存在,请使用其他文件名或显式 --overwrite\", 4);\n\t\t} catch (error) {\n\t\t\tif (!isNotFound(error)) throw error;\n\t\t}\n\t\tawait writeFile(recordPath, `${JSON.stringify(store.redactor.value({\n\t\t\t...record,\n\t\t\tstatus: \"prepared\"\n\t\t}), null, 2)}\\n`, {\n\t\t\tflag: \"wx\",\n\t\t\tmode: 384\n\t\t});\n\t} catch (error) {\n\t\tif (error instanceof ImgRelayError) throw error;\n\t\tthrow new ImgRelayError(\"save_error\", \"无法创建输出目录或请求记录;未提交生成请求\", 4);\n\t}\n\tlet outcome;\n\ttry {\n\t\tdata.parameters = resolveParameters(selected.provider, model, supplied);\n\t\tconst body = {\n\t\t\tmodel,\n\t\t\tprompt: options.prompt\n\t\t};\n\t\tfor (const [name, value] of Object.entries(data.parameters)) {\n\t\t\tconst wire = {\n\t\t\t\toutputFormat: \"output_format\",\n\t\t\t\tresponseFormat: \"response_format\"\n\t\t\t}[name] || name;\n\t\t\tbody[wire] = value;\n\t\t}\n\t\tif (options.signal?.aborted) throw new ImgRelayError(\"interrupted\", \"用户中断,未提交生成请求\", 130);\n\t\toptions.progress?.(\"正在等待生图接口,生成请求只提交一次…\");\n\t\tdata.submissionStatus = \"submitted\";\n\t\tconst response = await requestJson({\n\t\t\turl: data.endpoint,\n\t\t\tkey,\n\t\t\tredactor: store.redactor,\n\t\t\tmethod: \"POST\",\n\t\t\tbody,\n\t\t\ttimeoutSeconds: options.timeoutSeconds || selected.provider.timeoutSeconds,\n\t\t\t...options.signal ? { signal: options.signal } : {}\n\t\t});\n\t\tdata.submissionStatus = \"result_received\";\n\t\tif (!response || typeof response !== \"object\" || !(\"data\" in response) || !Array.isArray(response.data) || response.data.length === 0) throw new ImgRelayError(\"invalid_response\", \"上游响应没有有效的 data[] 图片结果\", 3);\n\t\tif (\"model\" in response && typeof response.model === \"string\") data.reportedModel = response.model;\n\t\tif (\"usage\" in response) {\n\t\t\tconst usage = usageNumbers(response.usage);\n\t\t\tif (usage !== void 0) data.usage = usage;\n\t\t}\n\t\tdata.returnedCount = response.data.length;\n\t\tfor (const [offset, item] of response.data.entries()) {\n\t\t\tconst index = offset + 1;\n\t\t\ttry {\n\t\t\t\tif (options.signal?.aborted) throw new ImgRelayError(\"interrupted\", \"用户中断保存,已保存的文件保持不变\", 130);\n\t\t\t\tif (!item || typeof item !== \"object\") throw new ImgRelayError(\"invalid_response\", \"图片条目不是对象\", 3);\n\t\t\t\tlet bytes;\n\t\t\t\tif (\"b64_json\" in item && typeof item.b64_json === \"string\" && item.b64_json) bytes = base64Bytes(item.b64_json);\n\t\t\t\telse if (\"url\" in item && typeof item.url === \"string\" && item.url) bytes = await download(item.url, options.signal);\n\t\t\t\telse throw new ImgRelayError(\"invalid_response\", \"图片条目缺少 b64_json 或 url\", 3);\n\t\t\t\tlet dimensions;\n\t\t\t\tlet format;\n\t\t\t\ttry {\n\t\t\t\t\tformat = await fileTypeFromBuffer(bytes);\n\t\t\t\t\tdimensions = imageSize(bytes);\n\t\t\t\t\tif (!format?.mime.startsWith(\"image/\") || !dimensions.width || !dimensions.height) throw new Error(\"Invalid image\");\n\t\t\t\t} catch {\n\t\t\t\t\tthrow new ImgRelayError(\"image_decode_error\", \"返回数据不是可识别的有效图片\", 3);\n\t\t\t\t}\n\t\t\t\tconst stem = options.filename ? parse(options.filename).name : requestId;\n\t\t\t\tconst sequence = !options.filename || response.data.length > 1 ? `-${String(index).padStart(2, \"0\")}` : \"\";\n\t\t\t\tconst path = join(outputDir, `${stem}${sequence}.${format.ext}`);\n\t\t\t\tconst handle = await open(path, options.overwrite ? \"w\" : \"wx\", 384).catch(() => {\n\t\t\t\t\tthrow new ImgRelayError(\"save_error\", \"无法保存图片;请检查文件重名和目录权限\", 4);\n\t\t\t\t});\n\t\t\t\ttry {\n\t\t\t\t\tawait handle.writeFile(bytes);\n\t\t\t\t\tawait handle.sync();\n\t\t\t\t} catch {\n\t\t\t\t\tawait handle.close().catch(() => {});\n\t\t\t\t\tawait unlink(path).catch(() => {});\n\t\t\t\t\tthrow new ImgRelayError(\"save_error\", \"图片写入失败;不会重新提交生成\", 4);\n\t\t\t\t} finally {\n\t\t\t\t\tawait handle.close().catch(() => {});\n\t\t\t\t}\n\t\t\t\tdata.images.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tpath,\n\t\t\t\t\tformat: format.ext,\n\t\t\t\t\twidth: dimensions.width,\n\t\t\t\t\theight: dimensions.height,\n\t\t\t\t\tbytes: bytes.length\n\t\t\t\t});\n\t\t\t\toptions.progress?.(`已保存 ${index}/${data.returnedCount} 张图片`);\n\t\t\t} catch (error) {\n\t\t\t\tdata.failures.push({\n\t\t\t\t\tindex,\n\t\t\t\t\terror: store.redactor.error(error)\n\t\t\t\t});\n\t\t\t\tif (error instanceof ImgRelayError && error.category === \"interrupted\") throw error;\n\t\t\t}\n\t\t}\n\t\tconst failed = data.failures.length > 0;\n\t\tconst error = data.failures[0]?.error;\n\t\toutcome = data.images.length ? {\n\t\t\tstatus: failed ? \"partial_success\" : \"success\",\n\t\t\texitCode: failed ? 5 : 0,\n\t\t\tdata\n\t\t} : {\n\t\t\tstatus: \"error\",\n\t\t\texitCode: data.failures.some((failure) => failure.error.category === \"save_error\") ? 4 : 3,\n\t\t\tdata,\n\t\t\t...error ? { error } : {}\n\t\t};\n\t} catch (error) {\n\t\tconst info = store.redactor.error(error);\n\t\tif (info.category === \"result_unknown\") data.submissionStatus = \"unknown\";\n\t\toutcome = {\n\t\t\tstatus: info.category === \"result_unknown\" ? \"unknown\" : info.category === \"interrupted\" ? \"interrupted\" : \"error\",\n\t\t\texitCode: error instanceof ImgRelayError ? error.exitCode : 1,\n\t\t\tdata,\n\t\t\terror: info\n\t\t};\n\t}\n\ttry {\n\t\tawait writeAtomic(recordPath, store.redactor.value({\n\t\t\t...record,\n\t\t\t...data,\n\t\t\tstatus: outcome.status,\n\t\t\terror: outcome.error || null,\n\t\t\tcompletedAt: (/* @__PURE__ */ new Date()).toISOString()\n\t\t}));\n\t} catch {\n\t\tdata.recordPath = null;\n\t\treturn {\n\t\t\tstatus: \"error\",\n\t\t\texitCode: 4,\n\t\t\tdata,\n\t\t\terror: {\n\t\t\t\tcategory: \"save_error\",\n\t\t\t\tmessage: \"生成记录保存失败;已保存的图片路径仍可使用,不会重新生成\"\n\t\t\t}\n\t\t};\n\t}\n\treturn outcome;\n}\n\n//#endregion\n//#region src/models.ts\nconst modelsResponse = z.object({ data: z.array(z.object({\n\tid: z.string().min(1),\n\ttype: z.string().optional()\n})) });\nconst cachedModels = z.object({\n\tfetchedAt: z.iso.datetime(),\n\tmodels: modelsResponse.shape.data,\n\turl: z.string(),\n\trevision: z.number()\n});\nasync function discoverModels(provider, key, redactor, signal) {\n\tconst url = resolveEndpoint(provider.baseUrl, provider.endpoints.models || \"/v1/models\");\n\tconst response = modelsResponse.safeParse(await requestJson({\n\t\turl,\n\t\tkey,\n\t\tredactor,\n\t\tretry: true,\n\t\t...signal ? { signal } : {}\n\t}));\n\tif (!response.success) throw new ImgRelayError(\"invalid_response\", \"模型接口未返回 data[].id;仍可手动配置模型后生成\", 3);\n\treturn response.data.data;\n}\nasync function models(store, options = {}) {\n\tconst selected = await store.selected(options.provider);\n\tconst key = await store.key(selected.provider);\n\tconst url = resolveEndpoint(selected.provider.baseUrl, selected.provider.endpoints.models || \"/v1/models\");\n\tconst cacheKey = createHash(\"sha256\").update(JSON.stringify([\n\t\tselected.name,\n\t\turl,\n\t\tselected.provider.revision,\n\t\tkey\n\t])).digest(\"hex\");\n\tif (!options.refresh) {\n\t\tconst cache = z.record(z.string(), z.unknown()).safeParse(await store.cache());\n\t\tconst cached = cachedModels.safeParse(cache.success ? cache.data[cacheKey] : void 0);\n\t\tif (cached.success && Date.now() - Date.parse(cached.data.fetchedAt) >= 0 && Date.now() - Date.parse(cached.data.fetchedAt) < 9e5) return {\n\t\t\t...cached.data,\n\t\t\tprovider: selected.name,\n\t\t\tcached: true\n\t\t};\n\t}\n\tconst discovered = await discoverModels(selected.provider, key, store.redactor, options.signal);\n\tconst result = {\n\t\tfetchedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tmodels: discovered,\n\t\turl,\n\t\trevision: selected.provider.revision\n\t};\n\tawait store.saveCache(cacheKey, result);\n\treturn {\n\t\t...result,\n\t\tprovider: selected.name,\n\t\tcached: false\n\t};\n}\nasync function doctor(store, options = {}) {\n\tlet selected;\n\ttry {\n\t\tselected = await store.selected(options.provider);\n\t} catch (error) {\n\t\tconst info = store.redactor.error(error);\n\t\treturn {\n\t\t\texitCode: error instanceof ImgRelayError ? error.exitCode : 1,\n\t\t\terror: info,\n\t\t\tdata: {\n\t\t\t\tprovider: options.provider || null,\n\t\t\t\tendpoints: null,\n\t\t\t\tconfiguration: \"invalid\",\n\t\t\t\tauthentication: \"not_checked\",\n\t\t\t\tmodelDiscovery: { status: \"not_checked\" },\n\t\t\t\tgeneration: \"not_verified\"\n\t\t\t}\n\t\t};\n\t}\n\tconst endpoints = {\n\t\tgenerate: resolveEndpoint(selected.provider.baseUrl, selected.provider.endpoints.generate || \"/v1/images/generations\"),\n\t\tmodels: resolveEndpoint(selected.provider.baseUrl, selected.provider.endpoints.models || \"/v1/models\")\n\t};\n\ttry {\n\t\tconst result = await models(store, {\n\t\t\t...options,\n\t\t\trefresh: true\n\t\t});\n\t\treturn {\n\t\t\texitCode: 0,\n\t\t\tdata: {\n\t\t\t\tprovider: selected.name,\n\t\t\t\tendpoints,\n\t\t\t\tconfiguration: \"valid\",\n\t\t\t\tauthentication: \"verified_for_models\",\n\t\t\t\tmodelDiscovery: result,\n\t\t\t\tgeneration: \"not_verified\",\n\t\t\t\tdefaultModelListed: selected.provider.defaultModel ? result.models.some((model) => model.id === selected.provider.defaultModel) : null\n\t\t\t}\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof ImgRelayError && error.category === \"interrupted\") throw error;\n\t\tconst info = store.redactor.error(error);\n\t\treturn {\n\t\t\texitCode: error instanceof ImgRelayError ? error.exitCode : 1,\n\t\t\terror: info,\n\t\t\tdata: {\n\t\t\t\tprovider: selected.name,\n\t\t\t\tendpoints,\n\t\t\t\tconfiguration: \"valid\",\n\t\t\t\tauthentication: info.category === \"auth_error\" ? \"failed\" : \"unknown\",\n\t\t\t\tmodelDiscovery: {\n\t\t\t\t\tstatus: \"unavailable\",\n\t\t\t\t\terror: info\n\t\t\t\t},\n\t\t\t\tgeneration: \"not_verified\",\n\t\t\t\tmessage: \"模型列表不可用时,仍可手动设置模型;生成能力尚未验证\"\n\t\t\t}\n\t\t};\n\t}\n}\n\n//#endregion\n//#region src/store.ts\nfunction defaultConfigDirectory() {\n\tif (process.env.IMGRELAY_CONFIG_DIR) return resolve(process.env.IMGRELAY_CONFIG_DIR);\n\treturn join(homedir(), \".imgrelay\");\n}\nvar Store = class {\n\tdirectory;\n\tredactor = new Redactor();\n\tinitialized = false;\n\tconstructor(directory = defaultConfigDirectory()) {\n\t\tthis.directory = resolve(directory);\n\t\tif (this.directory === parse(this.directory).root) throw new ImgRelayError(\"config_error\", \"配置目录不能是文件系统根目录\");\n\t}\n\tasync config() {\n\t\ttry {\n\t\t\tconst raw = await readJson(join(this.directory, \"config.json\"));\n\t\t\tif (raw && typeof raw === \"object\" && \"schemaVersion\" in raw && raw.schemaVersion !== 1) throw new ImgRelayError(\"config_error\", \"不支持此配置版本;当前仅支持 schemaVersion=1\");\n\t\t\tconst result = configSchema.safeParse(raw);\n\t\t\tif (!result.success) throw new ImgRelayError(\"config_error\", \"配置文件结构或版本无效;请检查 config.json\");\n\t\t\tfor (const provider of Object.values(result.data.providers)) if (provider.apiKey) this.redactor.add(provider.apiKey);\n\t\t\treturn result.data;\n\t\t} catch (error) {\n\t\t\tif (isNotFound(error)) return {\n\t\t\t\tschemaVersion: 1,\n\t\t\t\tproviders: {}\n\t\t\t};\n\t\t\tif (error instanceof ImgRelayError) throw error;\n\t\t\tthrow new ImgRelayError(\"config_error\", \"无法读取配置文件;请检查文件格式及访问权限\");\n\t\t}\n\t}\n\tasync selected(name) {\n\t\tconst config = await this.config();\n\t\tconst selected = name || config.defaultProvider;\n\t\tif (!selected) throw new ImgRelayError(\"config_error\", \"未设置默认供应商,请运行 imgrelay provider use <名称>\");\n\t\tconst provider = Object.hasOwn(config.providers, selected) ? config.providers[selected] : void 0;\n\t\tif (!provider) throw new ImgRelayError(\"config_error\", `供应商 ${selected} 不存在,请运行 imgrelay provider add ${selected}`);\n\t\treturn {\n\t\t\tname: selected,\n\t\t\tprovider\n\t\t};\n\t}\n\tasync initialize() {\n\t\tif (!this.initialized) {\n\t\t\tawait mkdir(this.directory, { recursive: true });\n\t\t\tthis.initialized = true;\n\t\t}\n\t}\n\tasync locked(operation) {\n\t\tawait this.initialize();\n\t\tconst lock = join(this.directory, \".write-lock\");\n\t\tconst owner = join(lock, \"owner.json\");\n\t\tconst deadline = Date.now() + 1e4;\n\t\tfor (;;) try {\n\t\t\tawait mkdir(lock);\n\t\t\tbreak;\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof Error && \"code\" in error && error.code === \"EEXIST\")) throw error;\n\t\t\ttry {\n\t\t\t\tconst data = z.object({ pid: z.number().int().positive() }).parse(await readJson(owner));\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(data.pid, 0);\n\t\t\t\t} catch (checkError) {\n\t\t\t\t\tif (checkError instanceof Error && \"code\" in checkError && checkError.code === \"ESRCH\") {\n\t\t\t\t\t\tawait unlink(owner);\n\t\t\t\t\t\tawait rmdir(lock);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\ttry {\n\t\t\t\t\tif (Date.now() - (await lstat(lock)).mtimeMs > 6e4) {\n\t\t\t\t\t\tawait unlink(owner).catch(() => {});\n\t\t\t\t\t\tawait rmdir(lock);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t\tif (Date.now() >= deadline) throw new ImgRelayError(\"config_busy\", \"配置正在被其他进程修改,请稍后重试\");\n\t\t\tawait setTimeout(50);\n\t\t}\n\t\ttry {\n\t\t\tawait writeFile(owner, JSON.stringify({ pid: process.pid }));\n\t\t\treturn await operation();\n\t\t} finally {\n\t\t\tawait unlink(owner).catch(() => {});\n\t\t\tawait rmdir(lock).catch(() => {});\n\t\t}\n\t}\n\tasync key(provider) {\n\t\tconst key = provider.apiKey;\n\t\tif (!key) throw new ImgRelayError(\"credential_error\", \"未配置 API 密钥,请运行 imgrelay provider edit <名称>\");\n\t\tif (/[\\r\\n\\0]/.test(key)) throw new ImgRelayError(\"credential_error\", \"密钥不能包含换行或空字符\");\n\t\tthis.redactor.add(key);\n\t\treturn key;\n\t}\n\tasync put(name, input, options = {}) {\n\t\tif (!providerNameSchema.safeParse(name).success) throw new ImgRelayError(\"input_error\", \"供应商名称只能包含字母、数字、下划线和连字符\");\n\t\tif (input.apiKey) this.redactor.add(input.apiKey);\n\t\tif (options.secret) this.redactor.add(options.secret);\n\t\tconst proposed = parseProvider({\n\t\t\t...input,\n\t\t\t...options.secret !== void 0 ? { apiKey: options.secret } : {}\n\t\t});\n\t\tif (proposed.apiKey) this.redactor.add(proposed.apiKey);\n\t\treturn this.locked(async () => {\n\t\t\tconst config = await this.config();\n\t\t\tconst previous = Object.hasOwn(config.providers, name) ? config.providers[name] : void 0;\n\t\t\tif (options.edit ? !previous : previous) throw new ImgRelayError(\"config_error\", options.edit ? \"供应商不存在\" : \"供应商已存在,请使用 provider edit\");\n\t\t\tif (options.expectedRevision !== void 0 && previous?.revision !== options.expectedRevision) throw new ImgRelayError(\"config_busy\", \"配置已被其他进程修改,请重新执行编辑\");\n\t\t\tproposed.revision = (previous?.revision || 0) + 1;\n\t\t\tconfig.providers[name] = proposed;\n\t\t\tif (options.makeDefault) config.defaultProvider = name;\n\t\t\tawait writeAtomic(join(this.directory, \"config.json\"), config);\n\t\t\treturn proposed;\n\t\t});\n\t}\n\tasync use(name) {\n\t\tawait this.locked(async () => {\n\t\t\tconst config = await this.config();\n\t\t\tif (!Object.hasOwn(config.providers, name)) throw new ImgRelayError(\"config_error\", \"供应商不存在\");\n\t\t\tconfig.defaultProvider = name;\n\t\t\tawait writeAtomic(join(this.directory, \"config.json\"), config);\n\t\t});\n\t}\n\tasync remove(name) {\n\t\tawait this.locked(async () => {\n\t\t\tconst config = await this.config();\n\t\t\tif (!Object.hasOwn(config.providers, name)) throw new ImgRelayError(\"config_error\", \"供应商不存在\");\n\t\t\tdelete config.providers[name];\n\t\t\tif (config.defaultProvider === name) delete config.defaultProvider;\n\t\t\tawait writeAtomic(join(this.directory, \"config.json\"), config);\n\t\t});\n\t}\n\tasync cache() {\n\t\ttry {\n\t\t\treturn await readJson(join(this.directory, \"models-cache.json\"));\n\t\t} catch {\n\t\t\treturn {};\n\t\t}\n\t}\n\tasync saveCache(key, value) {\n\t\tawait this.locked(async () => {\n\t\t\tconst parsed = z.record(z.string(), z.unknown()).safeParse(await this.cache());\n\t\t\tconst cache = parsed.success ? parsed.data : {};\n\t\t\tcache[key] = value;\n\t\t\tconst entries = Object.entries(cache).slice(-100);\n\t\t\tawait writeAtomic(join(this.directory, \"models-cache.json\"), Object.fromEntries(entries));\n\t\t});\n\t}\n};\n\n//#endregion\nexport { CUBENCE_PRESET, ImgRelayError, KNOWN_MODEL_CAPABILITIES, Redactor, Store, configSchema, defaultConfigDirectory, discoverModels, doctor, generate, modelCapabilitySchema, models, normalizeBaseUrl, parseProvider, providerNameSchema, providerSchema, resolveEndpoint };\n//# sourceMappingURL=index.mjs.map","","/* Interactive prompts must be shown one at a time. */\n/* eslint-disable no-await-in-loop */\nimport { readFile } from 'node:fs/promises'\nimport { resolve } from 'node:path'\n\nimport * as prompts from '@clack/prompts'\nimport { CUBENCE_PRESET, discoverModels, ImgRelayError, parseProvider } from '@imgrelay/core'\nimport type { Provider, ProviderInput, Store } from '@imgrelay/core'\nimport type { Command } from 'commander'\n\nexport interface ProviderFlags {\n baseUrl?: string\n protocol?: string\n preset?: string\n model?: string\n clearKey?: boolean\n size?: string\n n?: string\n quality?: string\n outputFormat?: string\n responseFormat?: string\n generationPath?: string\n modelsPath?: string\n capabilitiesFile?: string\n timeout?: string\n default?: boolean\n}\n\nfunction answer(value: string | symbol): string\nfunction answer(value: boolean | symbol): boolean\nfunction answer(value: string | boolean | symbol): string | boolean {\n if (typeof value === 'symbol')\n throw new ImgRelayError('interrupted', '用户取消配置,未保存修改', 130)\n return value\n}\n\nexport function providerOptions(command: Command): Command {\n return command\n .option('--base-url <URL>', 'API 基础地址,推荐包含 /v1')\n .option('--protocol <协议>', '首版支持 openai-images')\n .option('--preset <名称>', '使用已验证配置预设:cubence')\n .option('--model <ID>', '默认模型,允许手动填写')\n .option('--clear-key', '清除配置中保存的密钥')\n .option('--default', '保存后设为默认供应商')\n .option('--size <尺寸>', '默认尺寸')\n .option('--n <数量>', '默认生成数量')\n .option('--quality <质量>', '默认质量')\n .option('--output-format <格式>', '默认图片格式')\n .option('--response-format <格式>', '供应商要求的返回格式:url 或 b64_json')\n .option('--generation-path <路径>', '生成端点覆盖')\n .option('--models-path <路径>', '模型端点覆盖')\n .option('--capabilities-file <文件>', '按模型的能力覆盖 JSON 文件')\n .option('--timeout <秒数>', '默认生成超时')\n}\n\nexport async function configureProvider(\n store: Store,\n name: string,\n flags: ProviderFlags,\n interactive: boolean,\n signal: AbortSignal,\n existing?: Provider,\n): Promise<Provider> {\n if (flags.preset && flags.preset !== 'cubence')\n throw new ImgRelayError('input_error', '未知预设;当前提供 cubence')\n if (!existing && !interactive)\n throw new ImgRelayError(\n 'config_error',\n '新增供应商需要隐藏输入 API 密钥,请在交互终端不带 --json 运行 provider add',\n )\n const input: ProviderInput = {\n protocol: 'openai-images',\n baseUrl: '',\n ...(flags.preset ? CUBENCE_PRESET : {}),\n ...existing,\n }\n if (flags.protocol) {\n if (flags.protocol !== 'openai-images')\n throw new ImgRelayError('config_error', '首版仅支持 openai-images 协议')\n input.protocol = flags.protocol\n }\n if (flags.baseUrl !== undefined) input.baseUrl = flags.baseUrl\n if (flags.model !== undefined) input.defaultModel = flags.model\n input.defaults = { ...input.defaults }\n input.endpoints = { ...input.endpoints }\n if (flags.size !== undefined) input.defaults.size = flags.size\n if (flags.n !== undefined) input.defaults.n = Number(flags.n)\n if (flags.quality !== undefined) input.defaults.quality = flags.quality\n if (flags.outputFormat !== undefined) input.defaults.outputFormat = flags.outputFormat\n if (flags.responseFormat !== undefined) {\n if (flags.responseFormat !== 'url' && flags.responseFormat !== 'b64_json')\n throw new ImgRelayError('input_error', '返回格式只能是 url 或 b64_json')\n input.defaults.responseFormat = flags.responseFormat\n }\n if (flags.generationPath !== undefined) input.endpoints.generate = flags.generationPath\n if (flags.modelsPath !== undefined) input.endpoints.models = flags.modelsPath\n if (flags.timeout !== undefined) input.timeoutSeconds = Number(flags.timeout)\n if (flags.capabilitiesFile) {\n try {\n const modelOverrides: unknown = JSON.parse(\n await readFile(resolve(flags.capabilitiesFile), 'utf8'),\n )\n input.modelOverrides = parseProvider({ ...input, modelOverrides }).modelOverrides\n } catch {\n throw new ImgRelayError('input_error', '能力覆盖文件必须是可读的 UTF-8 JSON')\n }\n }\n let secret: string | undefined\n if (flags.clearKey) delete input.apiKey\n if (interactive) {\n prompts.intro(existing ? `编辑供应商 ${name}` : `添加供应商 ${name}`)\n if (flags.baseUrl === undefined)\n input.baseUrl = answer(\n await prompts.text({\n message: 'API 基础地址',\n initialValue: input.baseUrl,\n validate: (value) => (value?.trim() ? undefined : '请输入地址'),\n }),\n )\n if (!flags.clearKey) {\n secret =\n answer(\n await prompts.password({\n message: input.apiKey ? 'API 密钥(留空保留当前密钥)' : 'API 密钥',\n validate: (value) => (value?.trim() || input.apiKey ? undefined : '密钥不能为空'),\n }),\n ).trim() || undefined\n if (secret) store.redactor.add(secret)\n }\n }\n if (!existing && !secret) throw new ImgRelayError('config_error', '新增供应商需要非空 API 密钥')\n if (interactive && flags.model === undefined) {\n let ids: string[] = []\n try {\n const key = secret || (await store.key(input))\n ids = (await discoverModels(parseProvider(input), key, store.redactor, signal)).map(\n (model) => model.id,\n )\n } catch (error) {\n if (error instanceof ImgRelayError && error.category === 'interrupted') throw error\n prompts.log.warn('未能查询模型列表,可以手动填写模型 ID;生成能力尚未验证')\n }\n const choice = ids.length\n ? answer(\n await prompts.select({\n message: '默认模型',\n options: [\n ...ids.map((id) => ({ value: id, label: store.redactor.text(id) })),\n { value: '\\0manual', label: '手动填写模型 ID' },\n ],\n }),\n )\n : '\\0manual'\n input.defaultModel =\n choice === '\\0manual'\n ? answer(\n await prompts.text({\n message: '默认模型(留空可稍后设置)',\n initialValue: input.defaultModel || '',\n }),\n )\n : choice\n if (!input.defaultModel) delete input.defaultModel\n }\n if (\n interactive &&\n answer(\n await prompts.confirm({\n message: '设置尺寸、数量、质量和格式的默认值?',\n initialValue: false,\n }),\n )\n ) {\n for (const [field, label] of [\n ['size', '尺寸'],\n ['n', '数量'],\n ['quality', '质量'],\n ['outputFormat', '图片格式'],\n ] as const) {\n const value = answer(\n await prompts.text({\n message: `${label}(留空表示不设置)`,\n initialValue: String(input.defaults[field] || ''),\n }),\n )\n if (value) Object.assign(input.defaults, { [field]: field === 'n' ? Number(value) : value })\n else delete input.defaults[field]\n }\n }\n const makeDefault =\n flags.default ||\n (interactive\n ? answer(\n await prompts.confirm({\n message: '设为默认供应商?',\n initialValue: !(await store.config()).defaultProvider,\n }),\n )\n : false)\n const saved = await store.put(name, input, {\n ...(existing ? { edit: true, expectedRevision: existing.revision } : {}),\n ...(secret ? { secret } : {}),\n makeDefault,\n })\n if (interactive) prompts.outro('配置已保存;此流程没有生成图片')\n return saved\n}\n","#!/usr/bin/env node\nimport { doctor, generate, ImgRelayError, models, Store } from '@imgrelay/core'\nimport type { ErrorInfo } from '@imgrelay/core'\nimport { Command, CommanderError } from 'commander'\n\nimport packageJson from '../package.json' with { type: 'json' }\nimport { configureProvider, providerOptions } from './provider.js'\nimport type { ProviderFlags } from './provider.js'\n\nconst json = process.argv.includes('--json')\nconst controller = new AbortController()\nprocess.once('SIGINT', () => controller.abort())\nprocess.once('SIGTERM', () => controller.abort())\nlet commandName = 'imgrelay'\nlet outputWritten = false\nlet helpOutput = ''\nlet store: Store | undefined\n\nfunction output(\n data: unknown,\n options: { status?: string; exitCode?: number; error?: ErrorInfo } = {},\n): void {\n if (outputWritten) return\n outputWritten = true\n const envelope = {\n schemaVersion: 1,\n command: commandName,\n status: options.status || 'success',\n data,\n error: options.error || null,\n }\n const safe = store ? store.redactor.value(envelope) : envelope\n if (json) process.stdout.write(`${JSON.stringify(safe)}\\n`)\n else {\n if (options.error)\n process.stderr.write(\n `${store?.redactor.text(options.error.message) || options.error.message}\\n`,\n )\n if (data !== null)\n process.stdout.write(\n `${JSON.stringify(store ? store.redactor.value(data) : data, null, 2)}\\n`,\n )\n }\n process.exitCode = options.exitCode || 0\n}\n\nfunction active(name: string): Store {\n commandName = name\n store ||= new Store()\n return store\n}\n\nconst program = new Command()\n .name('imgrelay')\n .description('通过统一入口调用 OpenAI Images 兼容中转站')\n .version(packageJson.version)\n .option('--json', '输出一个最终 JSON 对象,禁用交互输入')\n .exitOverride()\n .configureOutput({\n writeOut: (value) => {\n if (json) helpOutput += value\n else process.stdout.write(value)\n },\n writeErr: (value) => {\n if (!json) process.stderr.write(value)\n },\n })\n\nconst provider = program.command('provider').description('管理供应商配置与凭据')\nproviderOptions(provider.command('add <名称>').description('添加供应商')).action(\n async (name: string, flags: ProviderFlags) => {\n const current = active('provider add')\n const result = await configureProvider(\n current,\n name,\n flags,\n !json && process.stdin.isTTY && process.stdout.isTTY,\n controller.signal,\n )\n output({ provider: name, configuration: result })\n },\n)\nproviderOptions(provider.command('edit <名称>').description('修改供应商')).action(\n async (name: string, flags: ProviderFlags) => {\n const current = active('provider edit')\n const existing = await current.selected(name)\n const result = await configureProvider(\n current,\n name,\n flags,\n !json && process.stdin.isTTY && process.stdout.isTTY,\n controller.signal,\n existing.provider,\n )\n output({ provider: name, configuration: result })\n },\n)\nprovider\n .command('list')\n .description('列出供应商摘要')\n .action(async () => {\n const current = active('provider list')\n const config = await current.config()\n output({\n defaultProvider: config.defaultProvider || null,\n providers: Object.entries(config.providers).map(([name, entry]) => ({\n name,\n protocol: entry.protocol,\n baseUrl: entry.baseUrl,\n defaultModel: entry.defaultModel || null,\n credentialSource: entry.apiKey ? 'config' : null,\n default: name === config.defaultProvider,\n })),\n })\n })\nprovider\n .command('show <名称>')\n .description('查看脱敏配置')\n .action(async (name: string) => {\n const current = active('provider show')\n const selected = await current.selected(name)\n output({ provider: name, configuration: selected.provider })\n })\nprovider\n .command('use <名称>')\n .description('设置默认供应商')\n .action(async (name: string) => {\n const current = active('provider use')\n await current.use(name)\n output({ defaultProvider: name })\n })\nprovider\n .command('remove <名称>')\n .description('移除供应商及其已保存的密钥')\n .action(async (name: string) => {\n const current = active('provider remove')\n await current.remove(name)\n output({ removed: name })\n })\nprogram\n .command('models')\n .description('查询模型列表或查看 15 分钟缓存')\n .option('--provider <名称>', '本次使用的供应商')\n .option('--refresh', '强制刷新模型列表')\n .action(async (flags: { provider?: string; refresh?: boolean }) => {\n const current = active('models')\n output(await models(current, { ...flags, signal: controller.signal }))\n })\nprogram\n .command('doctor')\n .description('检查配置与模型接口,不生成图片')\n .option('--provider <名称>', '检查指定供应商')\n .action(async (flags: { provider?: string }) => {\n const current = active('doctor')\n const result = await doctor(current, { ...flags, signal: controller.signal })\n output(result.data, {\n status: result.exitCode ? 'error' : 'success',\n exitCode: result.exitCode,\n ...(result.error ? { error: result.error } : {}),\n })\n })\nprogram\n .command('generate')\n .description('生成图片并保存原图和记录')\n .option('--prompt <文本>', '直接提供非空提示词(必填)')\n .option('--provider <名称>', '本次使用的供应商')\n .option('--model <ID>', '本次使用的模型')\n .option('--size <尺寸>', '图片尺寸,如 auto 或 1024x1024')\n .option('--n <数量>', '请求图片数量,不自动拆单')\n .option('--quality <质量>', '请求质量')\n .option('--output-format <格式>', '请求图片格式')\n .option('--output-dir <目录>', '保存目录,默认 output/imagegen')\n .option('--filename <名称>', '文件名;多图追加序号,扩展名按实际格式')\n .option('--overwrite', '允许覆盖图片文件')\n .option('--timeout <秒数>', '生成等待超时,默认 600 秒')\n .action(\n async (flags: {\n prompt?: string\n provider?: string\n model?: string\n size?: string\n n?: string\n quality?: string\n outputFormat?: string\n outputDir?: string\n filename?: string\n overwrite?: boolean\n timeout?: string\n }) => {\n const current = active('generate')\n if (flags.prompt === undefined)\n throw new ImgRelayError('input_error', '请通过 --prompt 提供非空提示词')\n const result = await generate(current, {\n prompt: flags.prompt,\n ...(flags.provider ? { provider: flags.provider } : {}),\n ...(flags.model ? { model: flags.model } : {}),\n ...(flags.size !== undefined ? { size: flags.size } : {}),\n ...(flags.n !== undefined ? { n: Number(flags.n) } : {}),\n ...(flags.quality !== undefined ? { quality: flags.quality } : {}),\n ...(flags.outputFormat !== undefined ? { outputFormat: flags.outputFormat } : {}),\n ...(flags.outputDir !== undefined ? { outputDir: flags.outputDir } : {}),\n ...(flags.filename !== undefined ? { filename: flags.filename } : {}),\n ...(flags.timeout !== undefined ? { timeoutSeconds: Number(flags.timeout) } : {}),\n overwrite: Boolean(flags.overwrite),\n signal: controller.signal,\n progress: (message) => process.stderr.write(`${message}\\n`),\n })\n output(result.data, {\n status: result.status,\n exitCode: result.exitCode,\n ...(result.error ? { error: result.error } : {}),\n })\n },\n )\nprogram.action(() => {\n if (json) output({ help: program.helpInformation() })\n else program.outputHelp()\n})\n\ntry {\n await program.parseAsync(process.argv)\n} catch (error) {\n if (error instanceof CommanderError && error.exitCode === 0) {\n if (json) output({ help: helpOutput.trim() })\n process.exitCode = 0\n } else {\n const failure =\n error instanceof CommanderError ? new ImgRelayError('input_error', error.message) : error\n const info: ErrorInfo = store\n ? store.redactor.error(failure)\n : {\n category: failure instanceof ImgRelayError ? failure.category : 'internal_error',\n message: failure instanceof Error ? failure.message : '发生未知错误',\n }\n output(null, {\n status: info.category === 'interrupted' ? 'interrupted' : 'error',\n exitCode: failure instanceof ImgRelayError ? failure.exitCode : 1,\n error: info,\n })\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["packageJson.version"],"sources":["../../core/dist/index.mjs","../package.json","../src/prompt.ts","../src/provider.ts","../src/index.ts"],"sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { access, lstat, mkdir, open, readFile, rename, rmdir, unlink, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join, parse, resolve } from \"node:path\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport { imageSize } from \"image-size\";\nimport { setTimeout } from \"node:timers/promises\";\nimport { z } from \"zod\";\nimport { homedir } from \"node:os\";\n\n//#region src/errors.ts\nvar ImgRelayError = class extends Error {\n\tcategory;\n\texitCode;\n\thttpStatus;\n\tconstructor(category, message, exitCode = 2, httpStatus) {\n\t\tsuper(message);\n\t\tthis.name = \"ImgRelayError\";\n\t\tthis.category = category;\n\t\tthis.exitCode = exitCode;\n\t\tthis.httpStatus = httpStatus;\n\t}\n};\n/** Redact before serialization; never retain an upstream response as a diagnostic. */\nvar Redactor = class {\n\tsecrets = /* @__PURE__ */ new Set();\n\tadd(secret) {\n\t\tif (secret) this.secrets.add(secret);\n\t}\n\ttext(value) {\n\t\tlet text = value;\n\t\tfor (const secret of [...this.secrets].toSorted((a, b) => b.length - a.length)) text = text.replaceAll(secret, \"[REDACTED]\");\n\t\treturn text.replace(/https?:\\/\\/[^\\s<>\"']+/gi, (raw) => {\n\t\t\ttry {\n\t\t\t\tconst url = new URL(raw);\n\t\t\t\tif (url.username || url.password) {\n\t\t\t\t\turl.username = \"REDACTED\";\n\t\t\t\t\turl.password = \"\";\n\t\t\t\t}\n\t\t\t\tif (url.search) url.search = \"?REDACTED\";\n\t\t\t\tif (url.hash) url.hash = \"#REDACTED\";\n\t\t\t\treturn url.toString();\n\t\t\t} catch {\n\t\t\t\treturn \"[REDACTED_URL]\";\n\t\t\t}\n\t\t});\n\t}\n\tvalue(value) {\n\t\tif (typeof value === \"string\") return this.text(value);\n\t\tif (Array.isArray(value)) return value.map((item) => this.value(item));\n\t\tif (value && typeof value === \"object\") return Object.fromEntries(Object.entries(value).map(([key, item]) => [this.text(key), key === \"promptSha256\" && typeof item === \"string\" && /^[a-f0-9]{64}$/.test(item) ? item : this.value(item)]));\n\t\treturn value;\n\t}\n\terror(error) {\n\t\tif (error instanceof ImgRelayError) return {\n\t\t\tcategory: error.category,\n\t\t\tmessage: this.text(error.message),\n\t\t\t...error.httpStatus === void 0 ? {} : { httpStatus: error.httpStatus }\n\t\t};\n\t\treturn {\n\t\t\tcategory: \"internal_error\",\n\t\t\tmessage: this.text(error instanceof Error ? error.message : \"发生未知错误\")\n\t\t};\n\t}\n};\n\n//#endregion\n//#region src/files.ts\nfunction isNotFound(error) {\n\treturn error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\nasync function assertRegular(path) {\n\tconst stat = await lstat(path);\n\tif (!stat.isFile() || stat.isSymbolicLink()) throw new ImgRelayError(\"credential_error\", \"配置或凭据文件必须是普通文件,不能使用符号链接\");\n}\nasync function writeAtomic(path, value) {\n\tconst temporary = join(dirname(path), `.${randomUUID()}.tmp`);\n\tconst handle = await open(temporary, \"wx\");\n\ttry {\n\t\tawait handle.writeFile(`${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n\t\tawait handle.sync();\n\t\tawait handle.close();\n\t\tawait rename(temporary, path);\n\t} finally {\n\t\tawait handle.close().catch(() => {});\n\t\tawait unlink(temporary).catch(() => {});\n\t}\n}\nasync function readJson(path) {\n\tawait assertRegular(path);\n\treturn JSON.parse(await readFile(path, \"utf8\"));\n}\n\n//#endregion\n//#region src/http.ts\nconst MAX_JSON_BYTES = 134217728;\nconst MAX_IMAGE_BYTES = 33554432;\nasync function readBounded(response, limit) {\n\tif (Number(response.headers.get(\"content-length\")) > limit) {\n\t\tawait response.body?.cancel();\n\t\tthrow new ImgRelayError(\"invalid_response\", \"上游响应超过大小限制\", 3);\n\t}\n\tif (!response.body) return Buffer.alloc(0);\n\tconst reader = response.body.getReader();\n\tconst chunks = [];\n\tlet size = 0;\n\ttry {\n\t\tfor (;;) {\n\t\t\tconst { value, done } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tsize += value.byteLength;\n\t\t\tif (size > limit) throw new ImgRelayError(\"invalid_response\", \"上游响应超过大小限制\", 3);\n\t\t\tchunks.push(value);\n\t\t}\n\t\treturn Buffer.concat(chunks, size);\n\t} finally {\n\t\tawait reader.cancel().catch(() => {});\n\t\treader.releaseLock();\n\t}\n}\nfunction httpError(status, text, redactor) {\n\tlet detail = \"\";\n\ttry {\n\t\tconst parsed = JSON.parse(text);\n\t\tif (parsed && typeof parsed === \"object\" && \"error\" in parsed) {\n\t\t\tconst error = parsed.error;\n\t\t\tif (typeof error === \"string\") detail = error;\n\t\t\telse if (error && typeof error === \"object\" && \"message\" in error && typeof error.message === \"string\") detail = error.message;\n\t\t}\n\t} catch {}\n\tlet category = \"upstream_error\";\n\tif (status === 401 || status === 403) category = \"auth_error\";\n\telse if (status === 429) category = \"rate_limit\";\n\telse if (status === 402 || /insufficient.*(quota|balance)|余额不足/i.test(detail)) category = \"quota_exceeded\";\n\telse if (/model.*(not found|not exist|unavailable|invalid)|模型.*(不存在|不可用)/i.test(detail)) category = \"model_unavailable\";\n\telse if (/unsupported.*(param|size|quality|format)|unknown parameter|参数.*(不支持|无效)/i.test(detail)) category = \"parameter_unsupported\";\n\treturn new ImgRelayError(category, redactor.text(`上游返回 HTTP ${status}${detail ? `:${detail.slice(0, 1e3)}` : \",请检查接口、权限和请求参数\"}`), 3, status);\n}\nasync function requestJson(options) {\n\tconst method = options.method || \"GET\";\n\tconst attempts = method === \"GET\" && options.retry ? 2 : 1;\n\tfor (let attempt = 0; attempt < attempts; attempt++) {\n\t\tconst timeout = AbortSignal.timeout(Math.ceil((options.timeoutSeconds || 15) * 1e3));\n\t\tconst signal = options.signal ? AbortSignal.any([timeout, options.signal]) : timeout;\n\t\ttry {\n\t\t\tconst response = await fetch(options.url, {\n\t\t\t\tmethod,\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${options.key}`,\n\t\t\t\t\t...method === \"POST\" ? { \"Content-Type\": \"application/json\" } : {}\n\t\t\t\t},\n\t\t\t\t...options.body === void 0 ? {} : { body: JSON.stringify(options.body) },\n\t\t\t\tredirect: \"manual\",\n\t\t\t\tsignal\n\t\t\t});\n\t\t\tconst text = (await readBounded(response, response.ok ? MAX_JSON_BYTES : 65536)).toString(\"utf8\");\n\t\t\tif (!response.ok) throw httpError(response.status, text, options.redactor);\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(text);\n\t\t\t} catch {\n\t\t\t\tthrow new ImgRelayError(\"invalid_response\", \"上游成功响应不是有效 JSON\", 3);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (options.signal?.aborted) throw new ImgRelayError(\"interrupted\", method === \"POST\" ? \"已停止本地等待,无法保证取消已提交的上游生成\" : \"用户中断请求\", 130);\n\t\t\tconst retryable = !(error instanceof ImgRelayError) || error.httpStatus === 429 || error.httpStatus !== void 0 && error.httpStatus >= 500;\n\t\t\tif (attempt + 1 < attempts && retryable) {\n\t\t\t\tawait setTimeout(150);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (error instanceof ImgRelayError) throw error;\n\t\t\tthrow new ImgRelayError(method === \"POST\" ? \"result_unknown\" : \"upstream_error\", method === \"POST\" ? \"生成请求超时或网络断开,结果未知;上游可能仍在生成,请勿直接重复提交\" : \"模型查询超时或网络失败,请检查地址和网络\", 3);\n\t\t}\n\t}\n\tthrow new ImgRelayError(\"internal_error\", \"请求执行状态无效\", 1);\n}\n\n//#endregion\n//#region src/urls.ts\nfunction parseApiUrl(value) {\n\tlet url;\n\ttry {\n\t\turl = new URL(value);\n\t} catch {\n\t\tthrow new ImgRelayError(\"config_error\", \"API 地址必须是完整的 HTTP 或 HTTPS URL\");\n\t}\n\tif (![\"http:\", \"https:\"].includes(url.protocol) || url.username || url.password || url.search || url.hash) throw new ImgRelayError(\"config_error\", \"API 地址只能使用 HTTP(S),不能包含凭据、查询参数或片段\");\n\treturn url;\n}\nfunction normalizeBaseUrl(value) {\n\treturn normalizeAddress(value).baseUrl;\n}\nfunction normalizeAddress(value) {\n\tconst url = parseApiUrl(value);\n\tconst path = url.pathname.replace(/\\/+$/, \"\");\n\tconst isGeneration = path.endsWith(\"/images/generations\");\n\turl.pathname = isGeneration ? path.slice(0, -19) : path;\n\treturn {\n\t\tbaseUrl: url.toString().replace(/\\/+$/, \"\"),\n\t\t...isGeneration ? { generationPath: \"/images/generations\" } : {}\n\t};\n}\nfunction validateEndpoint(path) {\n\ttry {\n\t\treturn path.startsWith(\"/\") && !/[?#\\\\]/.test(path) && !path.includes(\"//\") && !path.split(\"/\").some((part) => [\"..\", \".\"].includes(decodeURIComponent(part)));\n\t} catch {\n\t\treturn false;\n\t}\n}\nfunction resolveEndpoint(baseUrl, endpoint) {\n\tif (!validateEndpoint(endpoint)) throw new ImgRelayError(\"config_error\", \"端点必须是路径,不能包含主机、查询参数或上级目录\");\n\tconst url = parseApiUrl(baseUrl);\n\tconst basePath = url.pathname.replace(/\\/+$/, \"\");\n\turl.pathname = `${basePath}${basePath.endsWith(\"/v1\") && endpoint.startsWith(\"/v1/\") ? endpoint.slice(3) : endpoint}`;\n\treturn url.toString();\n}\n\n//#endregion\n//#region src/schema.ts\nconst shortText = z.string().trim().min(1).max(256);\nconst providerNameSchema = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/);\nconst parameterSchema = z.strictObject({\n\tsize: shortText.optional(),\n\tn: z.number().int().positive().optional(),\n\tquality: shortText.optional(),\n\toutputFormat: shortText.optional(),\n\tresponseFormat: z.enum([\"url\", \"b64_json\"]).optional()\n});\nconst parameterCapabilitySchema = z.strictObject({\n\tsupported: z.boolean().optional(),\n\tvalues: z.array(shortText).min(1).optional(),\n\tmin: z.number().optional(),\n\tmax: z.number().optional()\n});\nconst modelCapabilitySchema = z.strictObject({\n\tsource: z.enum([\n\t\t\"official_documentation\",\n\t\t\"provider_override\",\n\t\t\"call_verification\"\n\t]).default(\"provider_override\"),\n\tsourceUrl: z.url().optional(),\n\tverifiedAt: z.iso.datetime().optional(),\n\tparameters: z.strictObject({\n\t\tsize: parameterCapabilitySchema.optional(),\n\t\tn: parameterCapabilitySchema.optional(),\n\t\tquality: parameterCapabilitySchema.optional(),\n\t\toutputFormat: parameterCapabilitySchema.optional(),\n\t\tresponseFormat: parameterCapabilitySchema.optional()\n\t})\n});\nconst endpointSchema = z.string().max(1024).refine((value) => {\n\ttry {\n\t\treturn validateEndpoint(value);\n\t} catch {\n\t\treturn false;\n\t}\n}, \"端点必须是有效路径\");\nconst providerSchema = z.strictObject({\n\tprotocol: z.literal(\"openai-images\"),\n\tbaseUrl: z.string(),\n\tapiKey: z.string().trim().min(1).refine((key) => !/[\\r\\n\\0]/.test(key), \"密钥不能包含换行或空字符\").optional(),\n\tdefaultModel: shortText.optional(),\n\tdefaults: parameterSchema.default({}),\n\tendpoints: z.strictObject({\n\t\tgenerate: endpointSchema.optional(),\n\t\tmodels: endpointSchema.optional()\n\t}).default({}),\n\tmodelOverrides: z.record(shortText, modelCapabilitySchema).default({}),\n\ttimeoutSeconds: z.number().positive().max(2147483).finite().default(600),\n\trevision: z.number().int().positive().default(1)\n}).transform((provider) => {\n\tconst address = normalizeAddress(provider.baseUrl);\n\treturn {\n\t\t...provider,\n\t\tbaseUrl: address.baseUrl,\n\t\tendpoints: address.generationPath && !provider.endpoints.generate ? {\n\t\t\t...provider.endpoints,\n\t\t\tgenerate: address.generationPath\n\t\t} : provider.endpoints\n\t};\n});\nconst configSchema = z.strictObject({\n\tschemaVersion: z.literal(1),\n\tdefaultProvider: providerNameSchema.optional(),\n\tproviders: z.record(providerNameSchema, providerSchema)\n});\nfunction parseProvider(input) {\n\tconst result = providerSchema.safeParse(input);\n\tif (!result.success) throw new ImgRelayError(\"config_error\", `供应商配置无效:${result.error.issues.map((issue) => `${issue.path.join(\".\")} ${issue.message}`).join(\";\")}`);\n\treturn result.data;\n}\nconst CUBENCE_PRESET = {\n\tprotocol: \"openai-images\",\n\tbaseUrl: \"https://api-lb.cubence.ai/v1\",\n\tdefaultModel: \"gpt-image-2.5-flare\",\n\tdefaults: {\n\t\tsize: \"auto\",\n\t\tn: 1,\n\t\tquality: \"high\",\n\t\toutputFormat: \"png\"\n\t}\n};\n\n//#endregion\n//#region src/capabilities.ts\nconst GPT_IMAGE_CAPABILITY = {\n\tsource: \"official_documentation\",\n\tsourceUrl: \"https://developers.openai.com/api/reference/python/resources/images/methods/generate\",\n\tverifiedAt: \"2026-10-10T10:03:00.000Z\",\n\tparameters: {\n\t\tn: {\n\t\t\tmin: 1,\n\t\t\tmax: 10\n\t\t},\n\t\tsize: { values: [\n\t\t\t\"auto\",\n\t\t\t\"1024x1024\",\n\t\t\t\"1536x1024\",\n\t\t\t\"1024x1536\"\n\t\t] },\n\t\tquality: { values: [\n\t\t\t\"auto\",\n\t\t\t\"low\",\n\t\t\t\"medium\",\n\t\t\t\"high\"\n\t\t] },\n\t\toutputFormat: { values: [\n\t\t\t\"png\",\n\t\t\t\"jpeg\",\n\t\t\t\"webp\"\n\t\t] },\n\t\tresponseFormat: { supported: false }\n\t}\n};\nconst KNOWN_MODEL_CAPABILITIES = {\n\t\"gpt-image-1\": GPT_IMAGE_CAPABILITY,\n\t\"gpt-image-1-mini\": GPT_IMAGE_CAPABILITY\n};\nfunction resolveParameters(provider, model, supplied) {\n\tconst parsed = parameterSchema.safeParse({\n\t\tn: 1,\n\t\t...provider.defaults,\n\t\t...supplied\n\t});\n\tif (!parsed.success) throw new ImgRelayError(\"input_error\", \"生成参数无效:数量必须是正整数,各参数必须是非空字符串\");\n\tconst result = parsed.data;\n\tconst known = Object.hasOwn(KNOWN_MODEL_CAPABILITIES, model) ? KNOWN_MODEL_CAPABILITIES[model] : void 0;\n\tconst override = Object.hasOwn(provider.modelOverrides, model) ? provider.modelOverrides[model] : void 0;\n\tconst limits = {\n\t\t...known?.parameters,\n\t\t...override?.parameters\n\t};\n\tfor (const name of [\n\t\t\"size\",\n\t\t\"n\",\n\t\t\"quality\",\n\t\t\"outputFormat\",\n\t\t\"responseFormat\"\n\t]) {\n\t\tconst value = result[name];\n\t\tconst limit = limits[name];\n\t\tif (value === void 0 || !limit) continue;\n\t\tif (limit.supported === false && name === \"n\" && supplied.n === void 0 && provider.defaults.n === void 0) {\n\t\t\tdelete result.n;\n\t\t\tcontinue;\n\t\t}\n\t\tif (limit.supported === false || limit.values && !limit.values.includes(String(value)) || typeof value === \"number\" && (limit.min !== void 0 && value < limit.min || limit.max !== void 0 && value > limit.max)) throw new ImgRelayError(\"parameter_unsupported\", `模型 ${model} 不支持参数 ${name}=${value};请检查模型能力或供应商覆盖`, 2);\n\t}\n\treturn result;\n}\n\n//#endregion\n//#region src/request.ts\nconst parameterNames = [\n\t\"size\",\n\t\"n\",\n\t\"quality\",\n\t\"outputFormat\",\n\t\"responseFormat\"\n];\n/** Resolve local configuration without requiring credentials, network or filesystem writes. */\nasync function prepareRequest(store, options) {\n\tif (!options.prompt.trim()) throw new ImgRelayError(\"input_error\", \"提示词不能为空\");\n\tfor (const name of [\n\t\t\"provider\",\n\t\t\"model\",\n\t\t\"outputDir\"\n\t]) if (options[name] !== void 0 && !options[name].trim()) throw new ImgRelayError(\"input_error\", `${name} 不能为空`);\n\tif (options.timeoutSeconds !== void 0 && (!Number.isFinite(options.timeoutSeconds) || options.timeoutSeconds <= 0 || options.timeoutSeconds > 2147483)) throw new ImgRelayError(\"input_error\", \"超时必须是有效的正数秒数\");\n\tif (options.filename !== void 0 && (!options.filename || basename(options.filename) !== options.filename || /[<>:\"/\\\\|?*]/.test(options.filename) || options.filename.split(\"\").some((character) => character.charCodeAt(0) < 32) || !parse(options.filename).name || [\".\", \"..\"].includes(options.filename))) throw new ImgRelayError(\"input_error\", \"--filename 必须是普通文件名,保存目录使用 --output-dir\");\n\tconst selected = await store.selected(options.provider);\n\tconst model = (options.model ?? selected.provider.defaultModel ?? \"\").trim();\n\tif (!model) throw new ImgRelayError(\"config_error\", \"未配置默认模型,请通过 --model 指定或运行 provider edit\");\n\tconst supplied = {};\n\tconst parameterSources = {};\n\tfor (const name of parameterNames) {\n\t\tconst value = options[name];\n\t\tif (value !== void 0) Object.assign(supplied, { [name]: value });\n\t\tif (value !== void 0) parameterSources[name] = \"explicit\";\n\t\telse if (selected.provider.defaults[name] !== void 0) parameterSources[name] = \"provider_default\";\n\t\telse if (name === \"n\") parameterSources.n = \"tool_default\";\n\t}\n\treturn {\n\t\tdetails: {\n\t\t\tpromptSource: options.promptSource ?? { type: \"api\" },\n\t\t\tpromptSha256: createHash(\"sha256\").update(options.prompt, \"utf8\").digest(\"hex\"),\n\t\t\tpromptCharacters: options.prompt.length,\n\t\t\tpromptUtf8Bytes: Buffer.byteLength(options.prompt, \"utf8\"),\n\t\t\tprovider: selected.name,\n\t\t\trequestedModel: model,\n\t\t\tparameters: {\n\t\t\t\tn: 1,\n\t\t\t\t...selected.provider.defaults,\n\t\t\t\t...supplied\n\t\t\t},\n\t\t\tendpoint: resolveEndpoint(selected.provider.baseUrl, selected.provider.endpoints.generate || \"/v1/images/generations\"),\n\t\t\tcapabilityEvidence: {\n\t\t\t\tknown: Object.hasOwn(KNOWN_MODEL_CAPABILITIES, model) ? KNOWN_MODEL_CAPABILITIES[model] || null : null,\n\t\t\t\tprovider: Object.hasOwn(selected.provider.modelOverrides, model) ? selected.provider.modelOverrides[model] || null : null\n\t\t\t},\n\t\t\toutputDir: resolve(options.outputDir ?? \"output/imagegen\"),\n\t\t\tfilename: options.filename ?? null,\n\t\t\toverwrite: Boolean(options.overwrite),\n\t\t\ttimeoutSeconds: options.timeoutSeconds ?? selected.provider.timeoutSeconds,\n\t\t\tsources: {\n\t\t\t\tprovider: options.provider !== void 0 ? \"explicit\" : \"default\",\n\t\t\t\tmodel: options.model !== void 0 ? \"explicit\" : \"provider_default\",\n\t\t\t\tparameters: parameterSources,\n\t\t\t\toutputDir: options.outputDir !== void 0 ? \"explicit\" : \"tool_default\",\n\t\t\t\tfilename: options.filename !== void 0 ? \"explicit\" : \"tool_default\",\n\t\t\t\toverwrite: options.overwrite ? \"explicit\" : \"tool_default\",\n\t\t\t\ttimeoutSeconds: options.timeoutSeconds !== void 0 ? \"explicit\" : \"provider_default\"\n\t\t\t}\n\t\t},\n\t\tprovider: selected.provider,\n\t\tsupplied\n\t};\n}\nfunction validateRequest(prepared) {\n\tprepared.details.parameters = resolveParameters(prepared.provider, prepared.details.requestedModel, prepared.supplied);\n\tfor (const name of parameterNames) if (prepared.details.parameters[name] === void 0) delete prepared.details.sources.parameters[name];\n}\nasync function previewGenerate(store, options) {\n\tconst prepared = await prepareRequest(store, options);\n\tvalidateRequest(prepared);\n\tif (options.signal?.aborted) throw new ImgRelayError(\"interrupted\", \"用户中断,未提交生成请求\", 130);\n\treturn {\n\t\t...prepared.details,\n\t\tdryRun: true,\n\t\tcredentialConfigured: Boolean(prepared.provider.apiKey),\n\t\tsubmissionStatus: \"not_submitted\",\n\t\twillSubmitNetworkRequest: false\n\t};\n}\n\n//#endregion\n//#region src/generate.ts\nfunction base64Bytes(value) {\n\tconst encoded = value.replace(/^data:image\\/[^;,]+;base64,/, \"\").replace(/\\s/g, \"\");\n\tif (encoded.length > Math.ceil(33554432 / 3) * 4 || !/^[A-Za-z0-9+/]+={0,2}$/.test(encoded) || encoded.length % 4 === 1) throw new ImgRelayError(\"image_decode_error\", \"Base64 图片无效或超过 32 MiB 限制\", 3);\n\tconst bytes = Buffer.from(encoded, \"base64\");\n\tif (bytes.length > 33554432 || bytes.toString(\"base64\").replace(/=+$/, \"\") !== encoded.replace(/=+$/, \"\")) throw new ImgRelayError(\"image_decode_error\", \"Base64 图片解码失败\", 3);\n\treturn bytes;\n}\nasync function download(urlString, signal) {\n\tlet current = urlString;\n\ttry {\n\t\tfor (let redirects = 0; redirects <= 3; redirects++) {\n\t\t\tconst url = new URL(current);\n\t\t\tif (![\"http:\", \"https:\"].includes(url.protocol) || url.username || url.password) throw new ImgRelayError(\"image_download_error\", \"图片地址必须为不含内嵌凭据的 HTTP(S) URL\", 3);\n\t\t\tconst timeout = AbortSignal.timeout(6e4);\n\t\t\tconst response = await fetch(url, {\n\t\t\t\tredirect: \"manual\",\n\t\t\t\tsignal: signal ? AbortSignal.any([signal, timeout]) : timeout\n\t\t\t});\n\t\t\tif (response.status >= 300 && response.status < 400) {\n\t\t\t\tconst location = response.headers.get(\"location\");\n\t\t\t\tawait response.body?.cancel();\n\t\t\t\tif (!location) throw new ImgRelayError(\"image_download_error\", \"图片重定向缺少目标地址\", 3);\n\t\t\t\tcurrent = new URL(location, url).toString();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!response.ok) {\n\t\t\t\tawait response.body?.cancel();\n\t\t\t\tthrow new ImgRelayError(\"image_download_error\", `图片下载返回 HTTP ${response.status}`, 3, response.status);\n\t\t\t}\n\t\t\treturn await readBounded(response, MAX_IMAGE_BYTES);\n\t\t}\n\t\tthrow new ImgRelayError(\"image_download_error\", \"图片下载重定向超过三次\", 3);\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new ImgRelayError(\"interrupted\", \"已停止本地保存;无法保证取消已提交的上游生成\", 130);\n\t\tif (error instanceof ImgRelayError) throw error;\n\t\tthrow new ImgRelayError(\"image_download_error\", \"图片下载超时或网络失败;不会重新生成图片\", 3);\n\t}\n}\nfunction usageNumbers(value, depth = 0) {\n\tif (depth > 4) return void 0;\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return void 0;\n\tconst entries = Object.entries(value).slice(0, 100).flatMap(([key, item]) => {\n\t\tif (!/^[a-z_][a-z0-9_]{0,63}$/i.test(key)) return [];\n\t\tconst result = usageNumbers(item, depth + 1);\n\t\treturn result === void 0 ? [] : [[key, result]];\n\t});\n\treturn entries.length ? Object.fromEntries(entries) : void 0;\n}\nasync function generate(store, options) {\n\tconst prepared = await prepareRequest(store, options);\n\tconst { outputDir, requestedModel: model } = prepared.details;\n\tconst key = await store.key(prepared.provider);\n\tconst requestId = randomUUID();\n\tconst recordPath = join(outputDir, `${requestId}-report.json`);\n\tconst data = {\n\t\t...prepared.details,\n\t\trequestId,\n\t\trequestedCount: prepared.details.parameters.n || 1,\n\t\treturnedCount: 0,\n\t\timages: [],\n\t\tfailures: [],\n\t\trecordPath,\n\t\tsubmissionStatus: \"not_submitted\"\n\t};\n\tconst record = {\n\t\tschemaVersion: 1,\n\t\tcreatedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tprompt: options.prompt,\n\t\t...data\n\t};\n\ttry {\n\t\tawait mkdir(outputDir, { recursive: true });\n\t\tif (options.filename && !options.overwrite) try {\n\t\t\tawait access(join(outputDir, options.filename));\n\t\t\tthrow new ImgRelayError(\"save_error\", \"目标文件已存在,请使用其他文件名或显式 --overwrite\", 4);\n\t\t} catch (error) {\n\t\t\tif (!isNotFound(error)) throw error;\n\t\t}\n\t\tawait writeFile(recordPath, `${JSON.stringify(store.redactor.value({\n\t\t\t...record,\n\t\t\tstatus: \"prepared\"\n\t\t}), null, 2)}\\n`, {\n\t\t\tflag: \"wx\",\n\t\t\tmode: 384\n\t\t});\n\t} catch (error) {\n\t\tif (error instanceof ImgRelayError) throw error;\n\t\tthrow new ImgRelayError(\"save_error\", \"无法创建输出目录或请求记录;未提交生成请求\", 4);\n\t}\n\tlet outcome;\n\ttry {\n\t\tvalidateRequest(prepared);\n\t\tdata.parameters = prepared.details.parameters;\n\t\tconst body = {\n\t\t\tmodel,\n\t\t\tprompt: options.prompt\n\t\t};\n\t\tfor (const [name, value] of Object.entries(data.parameters)) {\n\t\t\tconst wire = {\n\t\t\t\toutputFormat: \"output_format\",\n\t\t\t\tresponseFormat: \"response_format\"\n\t\t\t}[name] || name;\n\t\t\tbody[wire] = value;\n\t\t}\n\t\tif (options.signal?.aborted) throw new ImgRelayError(\"interrupted\", \"用户中断,未提交生成请求\", 130);\n\t\toptions.progress?.(\"正在等待生图接口,生成请求只提交一次…\");\n\t\tdata.submissionStatus = \"submitted\";\n\t\tconst response = await requestJson({\n\t\t\turl: data.endpoint,\n\t\t\tkey,\n\t\t\tredactor: store.redactor,\n\t\t\tmethod: \"POST\",\n\t\t\tbody,\n\t\t\ttimeoutSeconds: data.timeoutSeconds,\n\t\t\t...options.signal ? { signal: options.signal } : {}\n\t\t});\n\t\tdata.submissionStatus = \"result_received\";\n\t\tif (!response || typeof response !== \"object\" || !(\"data\" in response) || !Array.isArray(response.data) || response.data.length === 0) throw new ImgRelayError(\"invalid_response\", \"上游响应没有有效的 data[] 图片结果\", 3);\n\t\tif (\"model\" in response && typeof response.model === \"string\") data.reportedModel = response.model;\n\t\tif (\"usage\" in response) {\n\t\t\tconst usage = usageNumbers(response.usage);\n\t\t\tif (usage !== void 0) data.usage = usage;\n\t\t}\n\t\tdata.returnedCount = response.data.length;\n\t\tfor (const [offset, item] of response.data.entries()) {\n\t\t\tconst index = offset + 1;\n\t\t\ttry {\n\t\t\t\tif (options.signal?.aborted) throw new ImgRelayError(\"interrupted\", \"用户中断保存,已保存的文件保持不变\", 130);\n\t\t\t\tif (!item || typeof item !== \"object\") throw new ImgRelayError(\"invalid_response\", \"图片条目不是对象\", 3);\n\t\t\t\tlet bytes;\n\t\t\t\tif (\"b64_json\" in item && typeof item.b64_json === \"string\" && item.b64_json) bytes = base64Bytes(item.b64_json);\n\t\t\t\telse if (\"url\" in item && typeof item.url === \"string\" && item.url) bytes = await download(item.url, options.signal);\n\t\t\t\telse throw new ImgRelayError(\"invalid_response\", \"图片条目缺少 b64_json 或 url\", 3);\n\t\t\t\tlet dimensions;\n\t\t\t\tlet format;\n\t\t\t\ttry {\n\t\t\t\t\tformat = await fileTypeFromBuffer(bytes);\n\t\t\t\t\tdimensions = imageSize(bytes);\n\t\t\t\t\tif (!format?.mime.startsWith(\"image/\") || !dimensions.width || !dimensions.height) throw new Error(\"Invalid image\");\n\t\t\t\t} catch {\n\t\t\t\t\tthrow new ImgRelayError(\"image_decode_error\", \"返回数据不是可识别的有效图片\", 3);\n\t\t\t\t}\n\t\t\t\tconst stem = options.filename ? parse(options.filename).name : requestId;\n\t\t\t\tconst sequence = !options.filename || response.data.length > 1 ? `-${String(index).padStart(2, \"0\")}` : \"\";\n\t\t\t\tconst path = join(outputDir, `${stem}${sequence}.${format.ext}`);\n\t\t\t\tconst handle = await open(path, options.overwrite ? \"w\" : \"wx\", 384).catch(() => {\n\t\t\t\t\tthrow new ImgRelayError(\"save_error\", \"无法保存图片;请检查文件重名和目录权限\", 4);\n\t\t\t\t});\n\t\t\t\ttry {\n\t\t\t\t\tawait handle.writeFile(bytes);\n\t\t\t\t\tawait handle.sync();\n\t\t\t\t} catch {\n\t\t\t\t\tawait handle.close().catch(() => {});\n\t\t\t\t\tawait unlink(path).catch(() => {});\n\t\t\t\t\tthrow new ImgRelayError(\"save_error\", \"图片写入失败;不会重新提交生成\", 4);\n\t\t\t\t} finally {\n\t\t\t\t\tawait handle.close().catch(() => {});\n\t\t\t\t}\n\t\t\t\tdata.images.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tpath,\n\t\t\t\t\tformat: format.ext,\n\t\t\t\t\twidth: dimensions.width,\n\t\t\t\t\theight: dimensions.height,\n\t\t\t\t\tbytes: bytes.length\n\t\t\t\t});\n\t\t\t\toptions.progress?.(`已保存 ${index}/${data.returnedCount} 张图片`);\n\t\t\t} catch (error) {\n\t\t\t\tdata.failures.push({\n\t\t\t\t\tindex,\n\t\t\t\t\terror: store.redactor.error(error)\n\t\t\t\t});\n\t\t\t\tif (error instanceof ImgRelayError && error.category === \"interrupted\") throw error;\n\t\t\t}\n\t\t}\n\t\tconst failed = data.failures.length > 0;\n\t\tconst error = data.failures[0]?.error;\n\t\toutcome = data.images.length ? {\n\t\t\tstatus: failed ? \"partial_success\" : \"success\",\n\t\t\texitCode: failed ? 5 : 0,\n\t\t\tdata\n\t\t} : {\n\t\t\tstatus: \"error\",\n\t\t\texitCode: data.failures.some((failure) => failure.error.category === \"save_error\") ? 4 : 3,\n\t\t\tdata,\n\t\t\t...error ? { error } : {}\n\t\t};\n\t} catch (error) {\n\t\tconst info = store.redactor.error(error);\n\t\tif (info.category === \"result_unknown\") data.submissionStatus = \"unknown\";\n\t\toutcome = {\n\t\t\tstatus: info.category === \"result_unknown\" ? \"unknown\" : info.category === \"interrupted\" ? \"interrupted\" : \"error\",\n\t\t\texitCode: error instanceof ImgRelayError ? error.exitCode : 1,\n\t\t\tdata,\n\t\t\terror: info\n\t\t};\n\t}\n\ttry {\n\t\tawait writeAtomic(recordPath, store.redactor.value({\n\t\t\t...record,\n\t\t\t...data,\n\t\t\tstatus: outcome.status,\n\t\t\terror: outcome.error || null,\n\t\t\tcompletedAt: (/* @__PURE__ */ new Date()).toISOString()\n\t\t}));\n\t} catch {\n\t\tdata.recordPath = null;\n\t\treturn {\n\t\t\tstatus: \"error\",\n\t\t\texitCode: 4,\n\t\t\tdata,\n\t\t\terror: {\n\t\t\t\tcategory: \"save_error\",\n\t\t\t\tmessage: \"生成记录保存失败;已保存的图片路径仍可使用,不会重新生成\"\n\t\t\t}\n\t\t};\n\t}\n\treturn outcome;\n}\n\n//#endregion\n//#region src/models.ts\nconst modelsResponse = z.object({ data: z.array(z.object({\n\tid: z.string().min(1),\n\ttype: z.string().optional()\n})) });\nconst cachedModels = z.object({\n\tfetchedAt: z.iso.datetime(),\n\tmodels: modelsResponse.shape.data,\n\turl: z.string(),\n\trevision: z.number()\n});\nasync function discoverModels(provider, key, redactor, signal) {\n\tconst url = resolveEndpoint(provider.baseUrl, provider.endpoints.models || \"/v1/models\");\n\tconst response = modelsResponse.safeParse(await requestJson({\n\t\turl,\n\t\tkey,\n\t\tredactor,\n\t\tretry: true,\n\t\t...signal ? { signal } : {}\n\t}));\n\tif (!response.success) throw new ImgRelayError(\"invalid_response\", \"模型接口未返回 data[].id;仍可手动配置模型后生成\", 3);\n\treturn response.data.data;\n}\nasync function models(store, options = {}) {\n\tconst selected = await store.selected(options.provider);\n\tconst key = await store.key(selected.provider);\n\tconst url = resolveEndpoint(selected.provider.baseUrl, selected.provider.endpoints.models || \"/v1/models\");\n\tconst cacheKey = createHash(\"sha256\").update(JSON.stringify([\n\t\tselected.name,\n\t\turl,\n\t\tselected.provider.revision,\n\t\tkey\n\t])).digest(\"hex\");\n\tif (!options.refresh) {\n\t\tconst cache = z.record(z.string(), z.unknown()).safeParse(await store.cache());\n\t\tconst cached = cachedModels.safeParse(cache.success ? cache.data[cacheKey] : void 0);\n\t\tif (cached.success && Date.now() - Date.parse(cached.data.fetchedAt) >= 0 && Date.now() - Date.parse(cached.data.fetchedAt) < 9e5) return {\n\t\t\t...cached.data,\n\t\t\tprovider: selected.name,\n\t\t\tcached: true\n\t\t};\n\t}\n\tconst discovered = await discoverModels(selected.provider, key, store.redactor, options.signal);\n\tconst result = {\n\t\tfetchedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tmodels: discovered,\n\t\turl,\n\t\trevision: selected.provider.revision\n\t};\n\tawait store.saveCache(cacheKey, result);\n\treturn {\n\t\t...result,\n\t\tprovider: selected.name,\n\t\tcached: false\n\t};\n}\nasync function doctor(store, options = {}) {\n\tlet selected;\n\ttry {\n\t\tselected = await store.selected(options.provider);\n\t} catch (error) {\n\t\tconst info = store.redactor.error(error);\n\t\treturn {\n\t\t\texitCode: error instanceof ImgRelayError ? error.exitCode : 1,\n\t\t\terror: info,\n\t\t\tdata: {\n\t\t\t\tprovider: options.provider || null,\n\t\t\t\tendpoints: null,\n\t\t\t\tconfiguration: \"invalid\",\n\t\t\t\tauthentication: \"not_checked\",\n\t\t\t\tmodelDiscovery: { status: \"not_checked\" },\n\t\t\t\tgeneration: \"not_verified\"\n\t\t\t}\n\t\t};\n\t}\n\tconst endpoints = {\n\t\tgenerate: resolveEndpoint(selected.provider.baseUrl, selected.provider.endpoints.generate || \"/v1/images/generations\"),\n\t\tmodels: resolveEndpoint(selected.provider.baseUrl, selected.provider.endpoints.models || \"/v1/models\")\n\t};\n\ttry {\n\t\tconst result = await models(store, {\n\t\t\t...options,\n\t\t\trefresh: true\n\t\t});\n\t\treturn {\n\t\t\texitCode: 0,\n\t\t\tdata: {\n\t\t\t\tprovider: selected.name,\n\t\t\t\tendpoints,\n\t\t\t\tconfiguration: \"valid\",\n\t\t\t\tauthentication: \"verified_for_models\",\n\t\t\t\tmodelDiscovery: result,\n\t\t\t\tgeneration: \"not_verified\",\n\t\t\t\tdefaultModelListed: selected.provider.defaultModel ? result.models.some((model) => model.id === selected.provider.defaultModel) : null\n\t\t\t}\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof ImgRelayError && error.category === \"interrupted\") throw error;\n\t\tconst info = store.redactor.error(error);\n\t\treturn {\n\t\t\texitCode: error instanceof ImgRelayError ? error.exitCode : 1,\n\t\t\terror: info,\n\t\t\tdata: {\n\t\t\t\tprovider: selected.name,\n\t\t\t\tendpoints,\n\t\t\t\tconfiguration: \"valid\",\n\t\t\t\tauthentication: info.category === \"auth_error\" ? \"failed\" : \"unknown\",\n\t\t\t\tmodelDiscovery: {\n\t\t\t\t\tstatus: \"unavailable\",\n\t\t\t\t\terror: info\n\t\t\t\t},\n\t\t\t\tgeneration: \"not_verified\",\n\t\t\t\tmessage: \"模型列表不可用时,仍可手动设置模型;生成能力尚未验证\"\n\t\t\t}\n\t\t};\n\t}\n}\n\n//#endregion\n//#region src/store.ts\nfunction defaultConfigDirectory() {\n\tif (process.env.IMGRELAY_CONFIG_DIR) return resolve(process.env.IMGRELAY_CONFIG_DIR);\n\treturn join(homedir(), \".imgrelay\");\n}\nvar Store = class {\n\tdirectory;\n\tredactor = new Redactor();\n\tinitialized = false;\n\tconstructor(directory = defaultConfigDirectory()) {\n\t\tthis.directory = resolve(directory);\n\t\tif (this.directory === parse(this.directory).root) throw new ImgRelayError(\"config_error\", \"配置目录不能是文件系统根目录\");\n\t}\n\tasync config() {\n\t\ttry {\n\t\t\tconst raw = await readJson(join(this.directory, \"config.json\"));\n\t\t\tif (raw && typeof raw === \"object\" && \"schemaVersion\" in raw && raw.schemaVersion !== 1) throw new ImgRelayError(\"config_error\", \"不支持此配置版本;当前仅支持 schemaVersion=1\");\n\t\t\tconst result = configSchema.safeParse(raw);\n\t\t\tif (!result.success) throw new ImgRelayError(\"config_error\", \"配置文件结构或版本无效;请检查 config.json\");\n\t\t\tfor (const provider of Object.values(result.data.providers)) if (provider.apiKey) this.redactor.add(provider.apiKey);\n\t\t\treturn result.data;\n\t\t} catch (error) {\n\t\t\tif (isNotFound(error)) return {\n\t\t\t\tschemaVersion: 1,\n\t\t\t\tproviders: {}\n\t\t\t};\n\t\t\tif (error instanceof ImgRelayError) throw error;\n\t\t\tthrow new ImgRelayError(\"config_error\", \"无法读取配置文件;请检查文件格式及访问权限\");\n\t\t}\n\t}\n\tasync selected(name) {\n\t\tconst config = await this.config();\n\t\tconst selected = name || config.defaultProvider;\n\t\tif (!selected) throw new ImgRelayError(\"config_error\", \"未设置默认供应商,请运行 imgrelay provider use <名称>\");\n\t\tconst provider = Object.hasOwn(config.providers, selected) ? config.providers[selected] : void 0;\n\t\tif (!provider) throw new ImgRelayError(\"config_error\", `供应商 ${selected} 不存在,请运行 imgrelay provider add ${selected}`);\n\t\treturn {\n\t\t\tname: selected,\n\t\t\tprovider\n\t\t};\n\t}\n\tasync initialize() {\n\t\tif (!this.initialized) {\n\t\t\tawait mkdir(this.directory, { recursive: true });\n\t\t\tthis.initialized = true;\n\t\t}\n\t}\n\tasync locked(operation) {\n\t\tawait this.initialize();\n\t\tconst lock = join(this.directory, \".write-lock\");\n\t\tconst owner = join(lock, \"owner.json\");\n\t\tconst deadline = Date.now() + 1e4;\n\t\tfor (;;) try {\n\t\t\tawait mkdir(lock);\n\t\t\tbreak;\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof Error && \"code\" in error && error.code === \"EEXIST\")) throw error;\n\t\t\ttry {\n\t\t\t\tconst data = z.object({ pid: z.number().int().positive() }).parse(await readJson(owner));\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(data.pid, 0);\n\t\t\t\t} catch (checkError) {\n\t\t\t\t\tif (checkError instanceof Error && \"code\" in checkError && checkError.code === \"ESRCH\") {\n\t\t\t\t\t\tawait unlink(owner);\n\t\t\t\t\t\tawait rmdir(lock);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\ttry {\n\t\t\t\t\tif (Date.now() - (await lstat(lock)).mtimeMs > 6e4) {\n\t\t\t\t\t\tawait unlink(owner).catch(() => {});\n\t\t\t\t\t\tawait rmdir(lock);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t\tif (Date.now() >= deadline) throw new ImgRelayError(\"config_busy\", \"配置正在被其他进程修改,请稍后重试\");\n\t\t\tawait setTimeout(50);\n\t\t}\n\t\ttry {\n\t\t\tawait writeFile(owner, JSON.stringify({ pid: process.pid }));\n\t\t\treturn await operation();\n\t\t} finally {\n\t\t\tawait unlink(owner).catch(() => {});\n\t\t\tawait rmdir(lock).catch(() => {});\n\t\t}\n\t}\n\tasync key(provider) {\n\t\tconst key = provider.apiKey;\n\t\tif (!key) throw new ImgRelayError(\"credential_error\", \"未配置 API 密钥,请运行 imgrelay provider edit <名称>\");\n\t\tif (/[\\r\\n\\0]/.test(key)) throw new ImgRelayError(\"credential_error\", \"密钥不能包含换行或空字符\");\n\t\tthis.redactor.add(key);\n\t\treturn key;\n\t}\n\tasync put(name, input, options = {}) {\n\t\tif (!providerNameSchema.safeParse(name).success) throw new ImgRelayError(\"input_error\", \"供应商名称只能包含字母、数字、下划线和连字符\");\n\t\tif (input.apiKey) this.redactor.add(input.apiKey);\n\t\tif (options.secret) this.redactor.add(options.secret);\n\t\tconst proposed = parseProvider({\n\t\t\t...input,\n\t\t\t...options.secret !== void 0 ? { apiKey: options.secret } : {}\n\t\t});\n\t\tif (proposed.apiKey) this.redactor.add(proposed.apiKey);\n\t\treturn this.locked(async () => {\n\t\t\tconst config = await this.config();\n\t\t\tconst previous = Object.hasOwn(config.providers, name) ? config.providers[name] : void 0;\n\t\t\tif (options.edit ? !previous : previous) throw new ImgRelayError(\"config_error\", options.edit ? \"供应商不存在\" : \"供应商已存在,请使用 provider edit\");\n\t\t\tif (options.expectedRevision !== void 0 && previous?.revision !== options.expectedRevision) throw new ImgRelayError(\"config_busy\", \"配置已被其他进程修改,请重新执行编辑\");\n\t\t\tproposed.revision = (previous?.revision || 0) + 1;\n\t\t\tconfig.providers[name] = proposed;\n\t\t\tif (options.makeDefault) config.defaultProvider = name;\n\t\t\tawait writeAtomic(join(this.directory, \"config.json\"), config);\n\t\t\treturn proposed;\n\t\t});\n\t}\n\tasync use(name) {\n\t\tawait this.locked(async () => {\n\t\t\tconst config = await this.config();\n\t\t\tif (!Object.hasOwn(config.providers, name)) throw new ImgRelayError(\"config_error\", \"供应商不存在\");\n\t\t\tconfig.defaultProvider = name;\n\t\t\tawait writeAtomic(join(this.directory, \"config.json\"), config);\n\t\t});\n\t}\n\tasync remove(name) {\n\t\tawait this.locked(async () => {\n\t\t\tconst config = await this.config();\n\t\t\tif (!Object.hasOwn(config.providers, name)) throw new ImgRelayError(\"config_error\", \"供应商不存在\");\n\t\t\tdelete config.providers[name];\n\t\t\tif (config.defaultProvider === name) delete config.defaultProvider;\n\t\t\tawait writeAtomic(join(this.directory, \"config.json\"), config);\n\t\t});\n\t}\n\tasync cache() {\n\t\ttry {\n\t\t\treturn await readJson(join(this.directory, \"models-cache.json\"));\n\t\t} catch {\n\t\t\treturn {};\n\t\t}\n\t}\n\tasync saveCache(key, value) {\n\t\tawait this.locked(async () => {\n\t\t\tconst parsed = z.record(z.string(), z.unknown()).safeParse(await this.cache());\n\t\t\tconst cache = parsed.success ? parsed.data : {};\n\t\t\tcache[key] = value;\n\t\t\tconst entries = Object.entries(cache).slice(-100);\n\t\t\tawait writeAtomic(join(this.directory, \"models-cache.json\"), Object.fromEntries(entries));\n\t\t});\n\t}\n};\n\n//#endregion\nexport { CUBENCE_PRESET, ImgRelayError, KNOWN_MODEL_CAPABILITIES, Redactor, Store, configSchema, defaultConfigDirectory, discoverModels, doctor, generate, modelCapabilitySchema, models, normalizeBaseUrl, parseProvider, previewGenerate, providerNameSchema, providerSchema, resolveEndpoint };\n//# sourceMappingURL=index.mjs.map","","import { readFile } from 'node:fs/promises'\nimport { resolve } from 'node:path'\nimport type { Readable } from 'node:stream'\n\nimport { ImgRelayError } from '@imgrelay/core'\nimport type { PromptSource } from '@imgrelay/core'\n\nexport interface PromptFlags {\n promptFile?: string\n promptStdin?: boolean\n}\n\nfunction interrupted(): ImgRelayError {\n return new ImgRelayError('interrupted', '用户中断读取提示词,未提交生成请求', 130)\n}\n\nexport async function readPrompt(\n flags: PromptFlags,\n signal?: AbortSignal,\n stdin: Readable & { isTTY?: boolean } = process.stdin,\n): Promise<{ prompt: string; promptSource: PromptSource }> {\n if (Number(flags.promptFile !== undefined) + Number(Boolean(flags.promptStdin)) !== 1)\n throw new ImgRelayError('input_error', '必须且只能指定 --prompt-file 或 --prompt-stdin')\n if (signal?.aborted) throw interrupted()\n let bytes: Buffer\n let promptSource: PromptSource\n if (flags.promptFile !== undefined) {\n if (!flags.promptFile.trim())\n throw new ImgRelayError('input_error', '--prompt-file 路径不能为空')\n const path = resolve(flags.promptFile)\n try {\n bytes = await readFile(path, signal ? { signal } : {})\n } catch {\n if (signal?.aborted) throw interrupted()\n throw new ImgRelayError('input_error', '无法读取 --prompt-file;请检查文件路径及访问权限')\n }\n promptSource = { type: 'file', path }\n } else {\n if (stdin.isTTY)\n throw new ImgRelayError(\n 'input_error',\n '--prompt-stdin 需要管道或重定向输入;也可使用 --prompt-file',\n )\n const abort = () => stdin.destroy(interrupted())\n signal?.addEventListener('abort', abort, { once: true })\n const chunks: Buffer[] = []\n try {\n for await (const chunk of stdin) chunks.push(Buffer.from(chunk))\n bytes = Buffer.concat(chunks)\n } catch {\n if (signal?.aborted) throw interrupted()\n throw new ImgRelayError('input_error', '无法读取 stdin 提示词')\n } finally {\n signal?.removeEventListener('abort', abort)\n }\n promptSource = { type: 'stdin' }\n }\n if (signal?.aborted) throw interrupted()\n let prompt: string\n try {\n prompt = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes)\n } catch {\n throw new ImgRelayError('input_error', '提示词必须是有效 UTF-8 文本')\n }\n if (prompt.startsWith('\\uFEFF')) prompt = prompt.slice(1)\n if (!prompt.trim()) throw new ImgRelayError('input_error', '提示词不能为空或全空白')\n return { prompt, promptSource }\n}\n","/* Interactive prompts must be shown one at a time. */\n/* eslint-disable no-await-in-loop */\nimport { readFile } from 'node:fs/promises'\nimport { resolve } from 'node:path'\n\nimport * as prompts from '@clack/prompts'\nimport { CUBENCE_PRESET, discoverModels, ImgRelayError, parseProvider } from '@imgrelay/core'\nimport type { Provider, ProviderInput, Store } from '@imgrelay/core'\nimport type { Command } from 'commander'\n\nexport interface ProviderFlags {\n baseUrl?: string\n protocol?: string\n preset?: string\n model?: string\n clearKey?: boolean\n size?: string\n n?: string\n quality?: string\n outputFormat?: string\n responseFormat?: string\n generationPath?: string\n modelsPath?: string\n capabilitiesFile?: string\n timeout?: string\n default?: boolean\n}\n\nfunction answer(value: string | symbol): string\nfunction answer(value: boolean | symbol): boolean\nfunction answer(value: string | boolean | symbol): string | boolean {\n if (typeof value === 'symbol')\n throw new ImgRelayError('interrupted', '用户取消配置,未保存修改', 130)\n return value\n}\n\nexport function providerOptions(command: Command): Command {\n return command\n .option('--base-url <URL>', 'API 基础地址,推荐包含 /v1')\n .option('--protocol <协议>', '首版支持 openai-images')\n .option('--preset <名称>', '使用已验证配置预设:cubence')\n .option('--model <ID>', '默认模型,允许手动填写')\n .option('--clear-key', '清除配置中保存的密钥')\n .option('--default', '保存后设为默认供应商')\n .option('--size <尺寸>', '默认尺寸')\n .option('--n <数量>', '默认生成数量')\n .option('--quality <质量>', '默认质量')\n .option('--output-format <格式>', '默认图片格式')\n .option('--response-format <格式>', '供应商要求的返回格式:url 或 b64_json')\n .option('--generation-path <路径>', '生成端点覆盖')\n .option('--models-path <路径>', '模型端点覆盖')\n .option('--capabilities-file <文件>', '按模型的能力覆盖 JSON 文件')\n .option('--timeout <秒数>', '默认生成超时')\n}\n\nexport async function configureProvider(\n store: Store,\n name: string,\n flags: ProviderFlags,\n interactive: boolean,\n signal: AbortSignal,\n existing?: Provider,\n): Promise<Provider> {\n if (flags.preset && flags.preset !== 'cubence')\n throw new ImgRelayError('input_error', '未知预设;当前提供 cubence')\n if (!existing && !interactive)\n throw new ImgRelayError(\n 'config_error',\n '新增供应商需要隐藏输入 API 密钥,请在交互终端不带 --json 运行 provider add',\n )\n const input: ProviderInput = {\n protocol: 'openai-images',\n baseUrl: '',\n ...(flags.preset ? CUBENCE_PRESET : {}),\n ...existing,\n }\n if (flags.protocol) {\n if (flags.protocol !== 'openai-images')\n throw new ImgRelayError('config_error', '首版仅支持 openai-images 协议')\n input.protocol = flags.protocol\n }\n if (flags.baseUrl !== undefined) input.baseUrl = flags.baseUrl\n if (flags.model !== undefined) input.defaultModel = flags.model\n input.defaults = { ...input.defaults }\n input.endpoints = { ...input.endpoints }\n if (flags.size !== undefined) input.defaults.size = flags.size\n if (flags.n !== undefined) input.defaults.n = Number(flags.n)\n if (flags.quality !== undefined) input.defaults.quality = flags.quality\n if (flags.outputFormat !== undefined) input.defaults.outputFormat = flags.outputFormat\n if (flags.responseFormat !== undefined) {\n if (flags.responseFormat !== 'url' && flags.responseFormat !== 'b64_json')\n throw new ImgRelayError('input_error', '返回格式只能是 url 或 b64_json')\n input.defaults.responseFormat = flags.responseFormat\n }\n if (flags.generationPath !== undefined) input.endpoints.generate = flags.generationPath\n if (flags.modelsPath !== undefined) input.endpoints.models = flags.modelsPath\n if (flags.timeout !== undefined) input.timeoutSeconds = Number(flags.timeout)\n if (flags.capabilitiesFile) {\n try {\n const modelOverrides: unknown = JSON.parse(\n await readFile(resolve(flags.capabilitiesFile), 'utf8'),\n )\n input.modelOverrides = parseProvider({ ...input, modelOverrides }).modelOverrides\n } catch {\n throw new ImgRelayError('input_error', '能力覆盖文件必须是可读的 UTF-8 JSON')\n }\n }\n let secret: string | undefined\n if (flags.clearKey) delete input.apiKey\n if (interactive) {\n prompts.intro(existing ? `编辑供应商 ${name}` : `添加供应商 ${name}`)\n if (flags.baseUrl === undefined)\n input.baseUrl = answer(\n await prompts.text({\n message: 'API 基础地址',\n initialValue: input.baseUrl,\n validate: (value) => (value?.trim() ? undefined : '请输入地址'),\n }),\n )\n if (!flags.clearKey) {\n secret =\n answer(\n await prompts.password({\n message: input.apiKey ? 'API 密钥(留空保留当前密钥)' : 'API 密钥',\n validate: (value) => (value?.trim() || input.apiKey ? undefined : '密钥不能为空'),\n }),\n ).trim() || undefined\n if (secret) store.redactor.add(secret)\n }\n }\n if (!existing && !secret) throw new ImgRelayError('config_error', '新增供应商需要非空 API 密钥')\n if (interactive && flags.model === undefined) {\n let ids: string[] = []\n try {\n const key = secret || (await store.key(input))\n ids = (await discoverModels(parseProvider(input), key, store.redactor, signal)).map(\n (model) => model.id,\n )\n } catch (error) {\n if (error instanceof ImgRelayError && error.category === 'interrupted') throw error\n prompts.log.warn('未能查询模型列表,可以手动填写模型 ID;生成能力尚未验证')\n }\n const choice = ids.length\n ? answer(\n await prompts.select({\n message: '默认模型',\n options: [\n ...ids.map((id) => ({ value: id, label: store.redactor.text(id) })),\n { value: '\\0manual', label: '手动填写模型 ID' },\n ],\n }),\n )\n : '\\0manual'\n input.defaultModel =\n choice === '\\0manual'\n ? answer(\n await prompts.text({\n message: '默认模型(留空可稍后设置)',\n initialValue: input.defaultModel || '',\n }),\n )\n : choice\n if (!input.defaultModel) delete input.defaultModel\n }\n if (\n interactive &&\n answer(\n await prompts.confirm({\n message: '设置尺寸、数量、质量和格式的默认值?',\n initialValue: false,\n }),\n )\n ) {\n for (const [field, label] of [\n ['size', '尺寸'],\n ['n', '数量'],\n ['quality', '质量'],\n ['outputFormat', '图片格式'],\n ] as const) {\n const value = answer(\n await prompts.text({\n message: `${label}(留空表示不设置)`,\n initialValue: String(input.defaults[field] || ''),\n }),\n )\n if (value) Object.assign(input.defaults, { [field]: field === 'n' ? Number(value) : value })\n else delete input.defaults[field]\n }\n }\n const makeDefault =\n flags.default ||\n (interactive\n ? answer(\n await prompts.confirm({\n message: '设为默认供应商?',\n initialValue: !(await store.config()).defaultProvider,\n }),\n )\n : false)\n const saved = await store.put(name, input, {\n ...(existing ? { edit: true, expectedRevision: existing.revision } : {}),\n ...(secret ? { secret } : {}),\n makeDefault,\n })\n if (interactive) prompts.outro('配置已保存;此流程没有生成图片')\n return saved\n}\n","#!/usr/bin/env node\nimport { doctor, generate, ImgRelayError, models, previewGenerate, Store } from '@imgrelay/core'\nimport type { ErrorInfo } from '@imgrelay/core'\nimport { Command, CommanderError } from 'commander'\n\nimport packageJson from '../package.json' with { type: 'json' }\nimport { readPrompt } from './prompt.js'\nimport { configureProvider, providerOptions } from './provider.js'\nimport type { ProviderFlags } from './provider.js'\n\nconst json = process.argv.includes('--json')\nconst controller = new AbortController()\nprocess.once('SIGINT', () => controller.abort())\nprocess.once('SIGTERM', () => controller.abort())\nlet commandName = 'imgrelay'\nlet outputWritten = false\nlet helpOutput = ''\nlet store: Store | undefined\n\nfunction output(\n data: unknown,\n options: { status?: string; exitCode?: number; error?: ErrorInfo } = {},\n): void {\n if (outputWritten) return\n outputWritten = true\n const envelope = {\n schemaVersion: 1,\n command: commandName,\n status: options.status || 'success',\n data,\n error: options.error || null,\n }\n const safe = store ? store.redactor.value(envelope) : envelope\n if (json) process.stdout.write(`${JSON.stringify(safe)}\\n`)\n else {\n if (options.error)\n process.stderr.write(\n `${store?.redactor.text(options.error.message) || options.error.message}\\n`,\n )\n if (data !== null)\n process.stdout.write(\n `${JSON.stringify(store ? store.redactor.value(data) : data, null, 2)}\\n`,\n )\n }\n process.exitCode = options.exitCode || 0\n}\n\nfunction active(name: string): Store {\n commandName = name\n store ||= new Store()\n return store\n}\n\nconst program = new Command()\n .name('imgrelay')\n .description('通过统一入口调用 OpenAI Images 兼容中转站')\n .version(packageJson.version)\n .option('--json', '输出一个最终 JSON 对象,禁用交互输入')\n .exitOverride()\n .configureOutput({\n writeOut: (value) => {\n if (json) helpOutput += value\n else process.stdout.write(value)\n },\n writeErr: (value) => {\n if (!json) process.stderr.write(value)\n },\n })\n\nconst provider = program.command('provider').description('管理供应商配置与凭据')\nproviderOptions(provider.command('add <名称>').description('添加供应商')).action(\n async (name: string, flags: ProviderFlags) => {\n const current = active('provider add')\n const result = await configureProvider(\n current,\n name,\n flags,\n !json && process.stdin.isTTY && process.stdout.isTTY,\n controller.signal,\n )\n output({ provider: name, configuration: result })\n },\n)\nproviderOptions(provider.command('edit <名称>').description('修改供应商')).action(\n async (name: string, flags: ProviderFlags) => {\n const current = active('provider edit')\n const existing = await current.selected(name)\n const result = await configureProvider(\n current,\n name,\n flags,\n !json && process.stdin.isTTY && process.stdout.isTTY,\n controller.signal,\n existing.provider,\n )\n output({ provider: name, configuration: result })\n },\n)\nprovider\n .command('list')\n .description('列出供应商摘要')\n .action(async () => {\n const current = active('provider list')\n const config = await current.config()\n output({\n defaultProvider: config.defaultProvider || null,\n providers: Object.entries(config.providers).map(([name, entry]) => ({\n name,\n protocol: entry.protocol,\n baseUrl: entry.baseUrl,\n defaultModel: entry.defaultModel || null,\n credentialSource: entry.apiKey ? 'config' : null,\n default: name === config.defaultProvider,\n })),\n })\n })\nprovider\n .command('show <名称>')\n .description('查看脱敏配置')\n .action(async (name: string) => {\n const current = active('provider show')\n const selected = await current.selected(name)\n output({ provider: name, configuration: selected.provider })\n })\nprovider\n .command('use <名称>')\n .description('设置默认供应商')\n .action(async (name: string) => {\n const current = active('provider use')\n await current.use(name)\n output({ defaultProvider: name })\n })\nprovider\n .command('remove <名称>')\n .description('移除供应商及其已保存的密钥')\n .action(async (name: string) => {\n const current = active('provider remove')\n await current.remove(name)\n output({ removed: name })\n })\nprogram\n .command('models')\n .description('查询模型列表或查看 15 分钟缓存')\n .option('--provider <名称>', '本次使用的供应商')\n .option('--refresh', '强制刷新模型列表')\n .action(async (flags: { provider?: string; refresh?: boolean }) => {\n const current = active('models')\n output(await models(current, { ...flags, signal: controller.signal }))\n })\nprogram\n .command('doctor')\n .description('检查配置与模型接口,不生成图片')\n .option('--provider <名称>', '检查指定供应商')\n .action(async (flags: { provider?: string }) => {\n const current = active('doctor')\n const result = await doctor(current, { ...flags, signal: controller.signal })\n output(result.data, {\n status: result.exitCode ? 'error' : 'success',\n exitCode: result.exitCode,\n ...(result.error ? { error: result.error } : {}),\n })\n })\nprogram\n .command('generate')\n .description('生成图片并保存原图和记录')\n .allowExcessArguments(false)\n .option('--prompt-file <路径>', '读取 UTF-8 提示词文件,与 --prompt-stdin 互斥')\n .option('--prompt-stdin', '从管道或重定向读取 UTF-8 提示词,与 --prompt-file 互斥')\n .option('--dry-run', '离线预览有效请求,不联网、不写文件,无需密钥')\n .option('--provider <名称>', '本次使用的供应商')\n .option('--model <ID>', '本次使用的模型')\n .option('--size <尺寸>', '图片尺寸,如 auto 或 1024x1024')\n .option('--n <数量>', '请求图片数量,不自动拆单')\n .option('--quality <质量>', '请求质量')\n .option('--output-format <格式>', '请求图片格式')\n .option('--output-dir <目录>', '保存目录,默认 output/imagegen')\n .option('--filename <名称>', '文件名;多图追加序号,扩展名按实际格式')\n .option('--overwrite', '允许覆盖图片文件')\n .option('--timeout <秒数>', '生成等待超时,默认 600 秒')\n .action(\n async (flags: {\n promptFile?: string\n promptStdin?: boolean\n dryRun?: boolean\n provider?: string\n model?: string\n size?: string\n n?: string\n quality?: string\n outputFormat?: string\n outputDir?: string\n filename?: string\n overwrite?: boolean\n timeout?: string\n }) => {\n const current = active('generate')\n const prompt = await readPrompt(flags, controller.signal)\n const options = {\n ...prompt,\n ...(flags.provider !== undefined ? { provider: flags.provider } : {}),\n ...(flags.model !== undefined ? { model: flags.model } : {}),\n ...(flags.size !== undefined ? { size: flags.size } : {}),\n ...(flags.n !== undefined ? { n: Number(flags.n) } : {}),\n ...(flags.quality !== undefined ? { quality: flags.quality } : {}),\n ...(flags.outputFormat !== undefined ? { outputFormat: flags.outputFormat } : {}),\n ...(flags.outputDir !== undefined ? { outputDir: flags.outputDir } : {}),\n ...(flags.filename !== undefined ? { filename: flags.filename } : {}),\n ...(flags.timeout !== undefined ? { timeoutSeconds: Number(flags.timeout) } : {}),\n overwrite: Boolean(flags.overwrite),\n signal: controller.signal,\n progress: (message: string) => process.stderr.write(`${message}\\n`),\n }\n if (flags.dryRun) {\n output(await previewGenerate(current, options))\n return\n }\n const result = await generate(current, options)\n output(result.data, {\n status: result.status,\n exitCode: result.exitCode,\n ...(result.error ? { error: result.error } : {}),\n })\n },\n )\nprogram.action(() => {\n if (json) output({ help: program.helpInformation() })\n else program.outputHelp()\n})\n\ntry {\n await program.parseAsync(process.argv)\n} catch (error) {\n if (error instanceof CommanderError && error.exitCode === 0) {\n if (json) output({ help: helpOutput.trim() })\n process.exitCode = 0\n } else {\n const removedPrompt =\n error instanceof CommanderError &&\n error.code === 'commander.unknownOption' &&\n (error.message.includes(\"'--prompt'\") || error.message.includes(\"'--prompt=\"))\n if (removedPrompt) commandName = 'generate'\n const failure =\n error instanceof CommanderError\n ? new ImgRelayError(\n 'input_error',\n removedPrompt\n ? '--prompt 已移除,请改用 --prompt-file <路径> 或 --prompt-stdin'\n : error.message,\n )\n : error\n const info: ErrorInfo = store\n ? store.redactor.error(failure)\n : {\n category: failure instanceof ImgRelayError ? failure.category : 'internal_error',\n message: failure instanceof Error ? failure.message : '发生未知错误',\n }\n output(null, {\n status: info.category === 'interrupted' ? 'interrupted' : 'error',\n exitCode: failure instanceof ImgRelayError ? failure.exitCode : 1,\n error: info,\n })\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imgrelay",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "通过统一 CLI 调用多家 OpenAI Images 兼容中转站",
5
5
  "homepage": "https://github.com/bingwu-devkit/imgrelay#readme",
6
6
  "bugs": "https://github.com/bingwu-devkit/imgrelay/issues",