ai-zero-token 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +262 -0
  3. package/dist/api.js +6 -0
  4. package/dist/api.js.map +1 -0
  5. package/dist/cli/commands/ask.js +15 -0
  6. package/dist/cli/commands/ask.js.map +1 -0
  7. package/dist/cli/commands/clear.js +11 -0
  8. package/dist/cli/commands/clear.js.map +1 -0
  9. package/dist/cli/commands/help.js +26 -0
  10. package/dist/cli/commands/help.js.map +1 -0
  11. package/dist/cli/commands/login.js +21 -0
  12. package/dist/cli/commands/login.js.map +1 -0
  13. package/dist/cli/commands/models.js +14 -0
  14. package/dist/cli/commands/models.js.map +1 -0
  15. package/dist/cli/commands/serve.js +18 -0
  16. package/dist/cli/commands/serve.js.map +1 -0
  17. package/dist/cli/commands/status.js +32 -0
  18. package/dist/cli/commands/status.js.map +1 -0
  19. package/dist/cli/index.js +43 -0
  20. package/dist/cli/index.js.map +1 -0
  21. package/dist/cli/shared.js +50 -0
  22. package/dist/cli/shared.js.map +1 -0
  23. package/dist/cli.js +8 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/core/context.js +24 -0
  26. package/dist/core/context.js.map +1 -0
  27. package/dist/core/models/openai-codex-models.js +34 -0
  28. package/dist/core/models/openai-codex-models.js.map +1 -0
  29. package/dist/core/providers/http-client.js +84 -0
  30. package/dist/core/providers/http-client.js.map +1 -0
  31. package/dist/core/providers/openai-codex/chat.js +102 -0
  32. package/dist/core/providers/openai-codex/chat.js.map +1 -0
  33. package/dist/core/providers/openai-codex/oauth.js +284 -0
  34. package/dist/core/providers/openai-codex/oauth.js.map +1 -0
  35. package/dist/core/providers/openai-codex/pkce.js +21 -0
  36. package/dist/core/providers/openai-codex/pkce.js.map +1 -0
  37. package/dist/core/services/auth-service.js +73 -0
  38. package/dist/core/services/auth-service.js.map +1 -0
  39. package/dist/core/services/chat-service.js +28 -0
  40. package/dist/core/services/chat-service.js.map +1 -0
  41. package/dist/core/services/config-service.js +69 -0
  42. package/dist/core/services/config-service.js.map +1 -0
  43. package/dist/core/services/model-service.js +42 -0
  44. package/dist/core/services/model-service.js.map +1 -0
  45. package/dist/core/store/profile-store.js +74 -0
  46. package/dist/core/store/profile-store.js.map +1 -0
  47. package/dist/core/store/settings-store.js +51 -0
  48. package/dist/core/store/settings-store.js.map +1 -0
  49. package/dist/core/types.js +2 -0
  50. package/dist/core/types.js.map +1 -0
  51. package/dist/http.js +6 -0
  52. package/dist/http.js.map +1 -0
  53. package/dist/models.js +14 -0
  54. package/dist/models.js.map +1 -0
  55. package/dist/oauth.js +10 -0
  56. package/dist/oauth.js.map +1 -0
  57. package/dist/pkce.js +6 -0
  58. package/dist/pkce.js.map +1 -0
  59. package/dist/server/app.js +115 -0
  60. package/dist/server/app.js.map +1 -0
  61. package/dist/server/index.js +23 -0
  62. package/dist/server/index.js.map +1 -0
  63. package/dist/store.js +20 -0
  64. package/dist/store.js.map +1 -0
  65. package/package.json +55 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AI Zero Token contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,262 @@
1
+ # AI Zero Token
2
+
3
+ AI Zero Token 是一个本地优先的单用户 AI CLI 和本地网关。
4
+
5
+ 它的核心目标是:
6
+
7
+ 让个人用户优先复用自己已经拥有的账号订阅和账号授权能力,在本地直接接入高质量 LLM,而不是再单独为优质 API 额度和接口调用链付费。
8
+
9
+ 很多用户已经有 ChatGPT、Claude、Gemini 之类产品的账号、订阅或可用授权能力,但缺少一个统一、可脚本化、可本地集成的入口。AI Zero Token 要做的,就是把这类已有授权能力整理成一个可直接使用的命令行工具和本地接口。
10
+
11
+ ## 为什么做这个项目
12
+
13
+ 如果你只是想在自己的电脑上更低门槛地接入主流 LLM,现实里通常会遇到这几个问题:
14
+
15
+ - 已经有产品订阅,但还没有开发者 API 方案
16
+ - 想把能力接入自己的脚本、前端、本地工作流,但不想每次都手工操作网页
17
+ - 想统一本地调用方式,而不是每家产品各写一套接入逻辑
18
+ - 想学习 OAuth、CLI、网关、npm CLI、桌面端这类真实工程能力
19
+
20
+ AI Zero Token 就是围绕这些问题设计的。
21
+
22
+ ## 当前能做什么
23
+
24
+ - 通过 OpenAI Codex OAuth 登录
25
+ - 在本地保存 `access_token` 和 `refresh_token`
26
+ - 在 token 过期时自动刷新
27
+ - 通过 CLI 发起真实模型请求
28
+ - 启动本地 HTTP 网关
29
+ - 暴露 OpenAI 风格接口:
30
+ - `GET /v1/models`
31
+ - `POST /v1/responses`
32
+
33
+
34
+ ## 适合谁用
35
+
36
+ - 想把账号授权能力包装成本地工具的人
37
+ - 想做自己的 AI 网关、AI CLI、AI 桌面端的人
38
+ - 想学习一条完整 OAuth -> token -> CLI -> HTTP API 链路的人
39
+ - 想把 AI 能力接入脚本、前端或自动化流程的人
40
+
41
+
42
+ ## 环境要求
43
+
44
+ - Node.js 22+ 推荐
45
+ - Bun 可用于开发和直接运行源码
46
+ - 终端网络需要可访问:
47
+ - `https://auth.openai.com`
48
+ - `https://chatgpt.com`
49
+
50
+ ## 安装与运行
51
+
52
+ ### 从源码运行
53
+
54
+ 克隆仓库并安装依赖:
55
+
56
+ ```bash
57
+ git clone https://github.com/fchangjun/AI-Zero-Token.git
58
+ cd AI-Zero-Token
59
+ npm install
60
+ ```
61
+
62
+ 直接运行源码:
63
+
64
+ ```bash
65
+ bun src/cli.ts help
66
+ ```
67
+
68
+ ### 从 npm 安装 CLI
69
+
70
+ 如果你只是想把它当作本地 CLI 和本地网关使用,可以直接全局安装:
71
+
72
+ ```bash
73
+ npm install -g ai-zero-token
74
+ ```
75
+
76
+ 安装后验证:
77
+
78
+ ```bash
79
+ azt help
80
+ ```
81
+
82
+ 如果你是为了开发、构建、`npm link`、`npm pack` 或准备发布,单独看:
83
+
84
+ - `BUILD_CLI.md`
85
+
86
+ ## 快速开始
87
+
88
+ 登录:
89
+ ```bash
90
+ azt login
91
+ ```
92
+
93
+ 查看当前状态:
94
+
95
+ ```bash
96
+ azt status
97
+ ```
98
+
99
+ 查看支持的模型:
100
+
101
+ ```bash
102
+ azt models
103
+ ```
104
+
105
+ 发起一次对话:
106
+
107
+ ```bash
108
+ azt ask "请只回复 OK"
109
+ ```
110
+
111
+ 指定模型发起对话:
112
+
113
+ ```bash
114
+ azt ask --model gpt-5.3-codex "请只回复 OK"
115
+ ```
116
+
117
+ 启动本地网关:
118
+
119
+ ```bash
120
+ azt serve
121
+ ```
122
+
123
+ 清空本地状态:
124
+
125
+ ```bash
126
+ azt clear
127
+ ```
128
+
129
+ 如果你当前还没有全局命令,也可以把上面的 `azt` 临时替换成:
130
+
131
+ ```bash
132
+ bun src/cli.ts
133
+ ```
134
+
135
+ 例如:
136
+
137
+ ```bash
138
+ bun src/cli.ts login
139
+ ```
140
+
141
+ ## 网关使用说明
142
+
143
+ 如果你主要把 AI Zero Token 当作本地网关来使用,建议按下面的顺序操作。
144
+
145
+ ### 1. 先完成登录
146
+
147
+ ```bash
148
+ azt login
149
+ ```
150
+
151
+ 这一步会打开浏览器,完成 OpenAI Codex OAuth 登录,并把可用 token 保存到本地。
152
+
153
+ ### 2. 启动本地网关
154
+
155
+ ```bash
156
+ azt serve
157
+ ```
158
+
159
+ CLI 一旦执行 `serve`,就会进入本地网关模式。
160
+
161
+ 默认监听地址:
162
+
163
+ ```text
164
+ http://127.0.0.1:8787
165
+ ```
166
+
167
+ ### 3. 先确认网关状态
168
+
169
+ 健康检查:
170
+
171
+ ```bash
172
+ curl http://127.0.0.1:8787/_gateway/health
173
+ ```
174
+
175
+ 查看当前网关状态:
176
+
177
+ ```bash
178
+ curl http://127.0.0.1:8787/_gateway/status
179
+ ```
180
+
181
+ ### 4. 查看模型列表
182
+
183
+ 内部模型接口:
184
+
185
+ ```bash
186
+ curl http://127.0.0.1:8787/_gateway/models
187
+ ```
188
+
189
+ OpenAI 风格模型接口:
190
+
191
+ ```bash
192
+ curl http://127.0.0.1:8787/v1/models
193
+ ```
194
+
195
+ ### 5. 调用对话接口
196
+
197
+ 最小请求示例:
198
+
199
+ ```bash
200
+ curl http://127.0.0.1:8787/v1/responses \
201
+ -H "content-type: application/json" \
202
+ -d '{"model":"gpt-5.4","input":"请只回复 OK"}'
203
+ ```
204
+
205
+ 带 `instructions` 的请求示例:
206
+
207
+ ```bash
208
+ curl http://127.0.0.1:8787/v1/responses \
209
+ -H "content-type: application/json" \
210
+ -d '{"model":"gpt-5.4","instructions":"你是一个简洁助手","input":"请只回复 OK"}'
211
+ ```
212
+
213
+ ### 6. 当前支持的接口
214
+
215
+ - `GET /_gateway/health`
216
+ - `GET /_gateway/status`
217
+ - `GET /_gateway/models`
218
+ - `GET /v1/models`
219
+ - `POST /v1/responses`
220
+
221
+ ### 7. 当前支持的主要参数
222
+
223
+ `POST /v1/responses` 当前主要支持:
224
+
225
+ - `model`
226
+ - `input`
227
+ - `instructions`
228
+ - `stream`
229
+
230
+ ### 8. 当前限制
231
+
232
+ - `stream=true` 目前只识别,不返回真实流式结果
233
+ - 还没有完整覆盖 OpenAI Responses API 的全部字段
234
+ - 还没有实现 `/v1/chat/completions`
235
+ - 网关当前默认面向本地单用户使用
236
+
237
+ ## 本地状态
238
+
239
+ 项目会在仓库目录下写入:
240
+
241
+ - `.state/store.json`
242
+ - `.state/settings.json`
243
+
244
+ 它们分别用于保存:
245
+
246
+ - OAuth 认证信息
247
+ - 默认模型和服务配置
248
+
249
+ ## 项目结构
250
+
251
+ - `src/cli/`
252
+ CLI 命令解析和命令分发
253
+ - `src/core/`
254
+ 核心业务逻辑
255
+ - `src/core/services/`
256
+ 认证、模型、聊天、配置服务
257
+ - `src/core/store/`
258
+ 本地状态读写
259
+ - `src/core/providers/openai-codex/`
260
+ OpenAI Codex provider 实现
261
+ - `src/server/`
262
+ 本地 HTTP 网关
package/dist/api.js ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import { askOpenAICodex } from "./core/providers/openai-codex/chat.js";
3
+ export {
4
+ askOpenAICodex
5
+ };
6
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api.ts"],"sourcesContent":["export { askOpenAICodex } from \"./core/providers/openai-codex/chat.js\";\n"],"mappings":";AAAA,SAAS,sBAAsB;","names":[]}
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import { createGatewayContext } from "../../core/context.js";
3
+ import { parseAskArgs } from "../shared.js";
4
+ async function runAskCommand(args) {
5
+ const { model, prompt } = parseAskArgs(args);
6
+ if (!prompt) {
7
+ throw new Error('ask \u9700\u8981\u4E00\u4E2A prompt\uFF0C\u4F8B\u5982 bun src/cli.js ask "\u4F60\u597D"');
8
+ }
9
+ const ctx = createGatewayContext();
10
+ console.log("model:", ctx);
11
+ }
12
+ export {
13
+ runAskCommand
14
+ };
15
+ //# sourceMappingURL=ask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/ask.ts"],"sourcesContent":["import { createGatewayContext } from \"../../core/context.js\";\nimport { parseAskArgs } from \"../shared.js\";\n\nexport async function runAskCommand(args: string[]): Promise<void> {\n const { model, prompt } = parseAskArgs(args);\n if (!prompt) {\n throw new Error('ask 需要一个 prompt,例如 bun src/cli.js ask \"你好\"');\n }\n\n const ctx = createGatewayContext();\n console.log('model:', ctx);\n// const result = await ctx.chatService.chat({\n// model,\n// input: prompt,\n// });\n\n// console.log(`provider: ${result.provider}`);\n// console.log(`model: ${result.model}`);\n// console.log(\"模型回复:\");\n// console.log(result.text || \"(返回成功,但没有解析出 output_text)\");\n}\n"],"mappings":";AAAA,SAAS,4BAA4B;AACrC,SAAS,oBAAoB;AAE7B,eAAsB,cAAc,MAA+B;AACjE,QAAM,EAAE,OAAO,OAAO,IAAI,aAAa,IAAI;AAC3C,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,yFAA4C;AAAA,EAC9D;AAEA,QAAM,MAAM,qBAAqB;AACjC,UAAQ,IAAI,UAAU,GAAG;AAU3B;","names":[]}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import { createGatewayContext } from "../../core/context.js";
3
+ async function runClearCommand() {
4
+ const ctx = createGatewayContext();
5
+ await ctx.authService.logoutAll();
6
+ console.log("\u5DF2\u6E05\u7A7A demo \u7684\u672C\u5730\u72B6\u6001\u3002");
7
+ }
8
+ export {
9
+ runClearCommand
10
+ };
11
+ //# sourceMappingURL=clear.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/clear.ts"],"sourcesContent":["import { createGatewayContext } from \"../../core/context.js\";\n\nexport async function runClearCommand(): Promise<void> {\n const ctx = createGatewayContext();\n await ctx.authService.logoutAll();\n console.log(\"已清空 demo 的本地状态。\");\n}\n"],"mappings":";AAAA,SAAS,4BAA4B;AAErC,eAAsB,kBAAiC;AACrD,QAAM,MAAM,qBAAqB;AACjC,QAAM,IAAI,YAAY,UAAU;AAChC,UAAQ,IAAI,8DAAiB;AAC/B;","names":[]}
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ function printHelp() {
3
+ console.log(`\u7528\u6CD5:
4
+
5
+ bun src/cli.js login
6
+ bun src/cli.js models
7
+ bun src/cli.js status
8
+ bun src/cli.js ask "\u4F60\u597D\uFF0C\u8BF7\u7B80\u5355\u4ECB\u7ECD\u4E00\u4E0B\u81EA\u5DF1"
9
+ bun src/cli.js ask --model gpt-5.3-codex "\u4F60\u597D"
10
+ bun src/cli.js serve
11
+ bun src/cli.js clear
12
+
13
+ \u8BF4\u660E:
14
+
15
+ login \u8D70\u771F\u5B9E OpenAI Codex OAuth\uFF0C\u4FDD\u5B58 access/refresh token
16
+ models \u67E5\u770B\u8FD9\u4E2A demo \u5F53\u524D\u5185\u7F6E\u652F\u6301\u7684\u6A21\u578B\u5217\u8868
17
+ status \u67E5\u770B\u5F53\u524D demo \u4FDD\u5B58\u7684\u8D26\u53F7\u548C\u8FC7\u671F\u65F6\u95F4
18
+ ask \u7528\u4FDD\u5B58\u7684 token \u8C03\u771F\u5B9E Codex Responses API
19
+ serve \u542F\u52A8\u672C\u5730 HTTP \u7F51\u5173
20
+ clear \u6E05\u7A7A demo \u7684\u672C\u5730\u72B6\u6001
21
+ `);
22
+ }
23
+ export {
24
+ printHelp
25
+ };
26
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/help.ts"],"sourcesContent":["export function printHelp(): void {\n console.log(`用法:\n\n bun src/cli.js login\n bun src/cli.js models\n bun src/cli.js status\n bun src/cli.js ask \"你好,请简单介绍一下自己\"\n bun src/cli.js ask --model gpt-5.3-codex \"你好\"\n bun src/cli.js serve\n bun src/cli.js clear\n\n说明:\n\n login 走真实 OpenAI Codex OAuth,保存 access/refresh token\n models 查看这个 demo 当前内置支持的模型列表\n status 查看当前 demo 保存的账号和过期时间\n ask 用保存的 token 调真实 Codex Responses API\n serve 启动本地 HTTP 网关\n clear 清空 demo 的本地状态\n`);\n}\n"],"mappings":";AAAO,SAAS,YAAkB;AAChC,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAkBb;AACD;","names":[]}
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import { createGatewayContext } from "../../core/context.js";
3
+ import { getStateDir, getStorePath } from "../../store.js";
4
+ import { formatExpiry } from "../shared.js";
5
+ async function runLoginCommand() {
6
+ const ctx = createGatewayContext();
7
+ const profile = await ctx.authService.login("openai-codex");
8
+ console.log("\u767B\u5F55\u6210\u529F\u3002");
9
+ console.log(`profileId: ${profile.profileId}`);
10
+ console.log(`accountId: ${profile.accountId}`);
11
+ if (profile.email) {
12
+ console.log(`email: ${profile.email}`);
13
+ }
14
+ console.log(`expires: ${formatExpiry(profile.expires)}`);
15
+ console.log(`stateDir: ${getStateDir()}`);
16
+ console.log(`store: ${getStorePath()}`);
17
+ }
18
+ export {
19
+ runLoginCommand
20
+ };
21
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/login.ts"],"sourcesContent":["import { createGatewayContext } from \"../../core/context.js\";\nimport { getStateDir, getStorePath } from \"../../store.js\";\nimport { formatExpiry } from \"../shared.js\";\n\nexport async function runLoginCommand(): Promise<void> {\n const ctx = createGatewayContext();\n const profile = await ctx.authService.login(\"openai-codex\");\n console.log(\"登录成功。\");\n console.log(`profileId: ${profile.profileId}`);\n console.log(`accountId: ${profile.accountId}`);\n if (profile.email) {\n console.log(`email: ${profile.email}`);\n }\n console.log(`expires: ${formatExpiry(profile.expires)}`);\n console.log(`stateDir: ${getStateDir()}`);\n console.log(`store: ${getStorePath()}`);\n}\n"],"mappings":";AAAA,SAAS,4BAA4B;AACrC,SAAS,aAAa,oBAAoB;AAC1C,SAAS,oBAAoB;AAE7B,eAAsB,kBAAiC;AACrD,QAAM,MAAM,qBAAqB;AACjC,QAAM,UAAU,MAAM,IAAI,YAAY,MAAM,cAAc;AAC1D,UAAQ,IAAI,gCAAO;AACnB,UAAQ,IAAI,cAAc,QAAQ,SAAS,EAAE;AAC7C,UAAQ,IAAI,cAAc,QAAQ,SAAS,EAAE;AAC7C,MAAI,QAAQ,OAAO;AACjB,YAAQ,IAAI,UAAU,QAAQ,KAAK,EAAE;AAAA,EACvC;AACA,UAAQ,IAAI,YAAY,aAAa,QAAQ,OAAO,CAAC,EAAE;AACvD,UAAQ,IAAI,aAAa,YAAY,CAAC,EAAE;AACxC,UAAQ,IAAI,UAAU,aAAa,CAAC,EAAE;AACxC;","names":[]}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import { createGatewayContext } from "../../core/context.js";
3
+ async function runModelsCommand() {
4
+ const ctx = createGatewayContext();
5
+ console.log("\u5F53\u524D demo \u5185\u7F6E\u652F\u6301\u7684\u6A21\u578B:");
6
+ for (const model of await ctx.modelService.listModels()) {
7
+ const suffix = model.isDefault ? " (\u9ED8\u8BA4)" : "";
8
+ console.log(`- ${model.id}${suffix}`);
9
+ }
10
+ }
11
+ export {
12
+ runModelsCommand
13
+ };
14
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/models.ts"],"sourcesContent":["import { createGatewayContext } from \"../../core/context.js\";\n\nexport async function runModelsCommand(): Promise<void> {\n const ctx = createGatewayContext();\n console.log(\"当前 demo 内置支持的模型:\");\n for (const model of await ctx.modelService.listModels()) {\n const suffix = model.isDefault ? \" (默认)\" : \"\";\n console.log(`- ${model.id}${suffix}`);\n }\n}\n"],"mappings":";AAAA,SAAS,4BAA4B;AAErC,eAAsB,mBAAkC;AACtD,QAAM,MAAM,qBAAqB;AACjC,UAAQ,IAAI,+DAAkB;AAC9B,aAAW,SAAS,MAAM,IAAI,aAAa,WAAW,GAAG;AACvD,UAAM,SAAS,MAAM,YAAY,oBAAU;AAC3C,YAAQ,IAAI,KAAK,MAAM,EAAE,GAAG,MAAM,EAAE;AAAA,EACtC;AACF;","names":[]}
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import { createGatewayContext } from "../../core/context.js";
3
+ import { startServer } from "../../server/index.js";
4
+ import { parseServeArgs } from "../shared.js";
5
+ async function runServeCommand(args) {
6
+ const { host, port } = parseServeArgs(args);
7
+ const ctx = createGatewayContext();
8
+ const status = await ctx.authService.getStatus();
9
+ const server = await startServer({ host, port });
10
+ console.log("\u672C\u5730\u7F51\u5173\u5DF2\u542F\u52A8\u3002");
11
+ console.log(`url: http://${server.host}:${server.port}`);
12
+ console.log(`activeProvider: ${status.activeProvider ?? "none"}`);
13
+ console.log(`defaultModel: ${status.defaultModel}`);
14
+ }
15
+ export {
16
+ runServeCommand
17
+ };
18
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/serve.ts"],"sourcesContent":["import { createGatewayContext } from \"../../core/context.js\";\nimport { startServer } from \"../../server/index.js\";\nimport { parseServeArgs } from \"../shared.js\";\n\nexport async function runServeCommand(args: string[]): Promise<void> {\n const { host, port } = parseServeArgs(args);\n const ctx = createGatewayContext();\n const status = await ctx.authService.getStatus();\n const server = await startServer({ host, port });\n console.log(\"本地网关已启动。\");\n console.log(`url: http://${server.host}:${server.port}`);\n console.log(`activeProvider: ${status.activeProvider ?? \"none\"}`);\n console.log(`defaultModel: ${status.defaultModel}`);\n}\n"],"mappings":";AAAA,SAAS,4BAA4B;AACrC,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;AAE/B,eAAsB,gBAAgB,MAA+B;AACnE,QAAM,EAAE,MAAM,KAAK,IAAI,eAAe,IAAI;AAC1C,QAAM,MAAM,qBAAqB;AACjC,QAAM,SAAS,MAAM,IAAI,YAAY,UAAU;AAC/C,QAAM,SAAS,MAAM,YAAY,EAAE,MAAM,KAAK,CAAC;AAC/C,UAAQ,IAAI,kDAAU;AACtB,UAAQ,IAAI,eAAe,OAAO,IAAI,IAAI,OAAO,IAAI,EAAE;AACvD,UAAQ,IAAI,mBAAmB,OAAO,kBAAkB,MAAM,EAAE;AAChE,UAAQ,IAAI,iBAAiB,OAAO,YAAY,EAAE;AACpD;","names":[]}
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ import { createGatewayContext } from "../../core/context.js";
3
+ import { getSettingsPath } from "../../core/store/settings-store.js";
4
+ import { getStateDir, getStorePath } from "../../store.js";
5
+ import { formatExpiry } from "../shared.js";
6
+ async function runStatusCommand() {
7
+ const ctx = createGatewayContext();
8
+ const status = await ctx.authService.getStatus();
9
+ if (!status.loggedIn) {
10
+ console.log("\u5F53\u524D\u6CA1\u6709\u5DF2\u4FDD\u5B58\u7684\u767B\u5F55\u72B6\u6001\u3002");
11
+ console.log(`stateDir: ${getStateDir()}`);
12
+ console.log(`store: ${getStorePath()}`);
13
+ return;
14
+ }
15
+ console.log("\u5F53\u524D\u767B\u5F55\u72B6\u6001:");
16
+ console.log(`provider: ${status.activeProvider}`);
17
+ console.log(`profileId: ${status.activeProfileId}`);
18
+ console.log(`defaultModel: ${status.defaultModel}`);
19
+ console.log(`serverHost: ${status.serverHost}`);
20
+ console.log(`serverPort: ${status.serverPort}`);
21
+ if (typeof status.expiresAt === "number") {
22
+ console.log(`expires: ${formatExpiry(status.expiresAt)}`);
23
+ console.log(`expired: ${Date.now() >= status.expiresAt ? "yes" : "no"}`);
24
+ }
25
+ console.log(`stateDir: ${getStateDir()}`);
26
+ console.log(`store: ${getStorePath()}`);
27
+ console.log(`settings: ${getSettingsPath()}`);
28
+ }
29
+ export {
30
+ runStatusCommand
31
+ };
32
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/status.ts"],"sourcesContent":["import { createGatewayContext } from \"../../core/context.js\";\nimport { getSettingsPath } from \"../../core/store/settings-store.js\";\nimport { getStateDir, getStorePath } from \"../../store.js\";\nimport { formatExpiry } from \"../shared.js\";\n\nexport async function runStatusCommand(): Promise<void> {\n const ctx = createGatewayContext();\n const status = await ctx.authService.getStatus();\n if (!status.loggedIn) {\n console.log(\"当前没有已保存的登录状态。\");\n console.log(`stateDir: ${getStateDir()}`);\n console.log(`store: ${getStorePath()}`);\n return;\n }\n\n console.log(\"当前登录状态:\");\n console.log(`provider: ${status.activeProvider}`);\n console.log(`profileId: ${status.activeProfileId}`);\n console.log(`defaultModel: ${status.defaultModel}`);\n console.log(`serverHost: ${status.serverHost}`);\n console.log(`serverPort: ${status.serverPort}`);\n if (typeof status.expiresAt === \"number\") {\n console.log(`expires: ${formatExpiry(status.expiresAt)}`);\n console.log(`expired: ${Date.now() >= status.expiresAt ? \"yes\" : \"no\"}`);\n }\n console.log(`stateDir: ${getStateDir()}`);\n console.log(`store: ${getStorePath()}`);\n console.log(`settings: ${getSettingsPath()}`);\n}\n"],"mappings":";AAAA,SAAS,4BAA4B;AACrC,SAAS,uBAAuB;AAChC,SAAS,aAAa,oBAAoB;AAC1C,SAAS,oBAAoB;AAE7B,eAAsB,mBAAkC;AACtD,QAAM,MAAM,qBAAqB;AACjC,QAAM,SAAS,MAAM,IAAI,YAAY,UAAU;AAC/C,MAAI,CAAC,OAAO,UAAU;AACpB,YAAQ,IAAI,gFAAe;AAC3B,YAAQ,IAAI,aAAa,YAAY,CAAC,EAAE;AACxC,YAAQ,IAAI,UAAU,aAAa,CAAC,EAAE;AACtC;AAAA,EACF;AAEA,UAAQ,IAAI,uCAAS;AACrB,UAAQ,IAAI,aAAa,OAAO,cAAc,EAAE;AAChD,UAAQ,IAAI,cAAc,OAAO,eAAe,EAAE;AAClD,UAAQ,IAAI,iBAAiB,OAAO,YAAY,EAAE;AAClD,UAAQ,IAAI,eAAe,OAAO,UAAU,EAAE;AAC9C,UAAQ,IAAI,eAAe,OAAO,UAAU,EAAE;AAC9C,MAAI,OAAO,OAAO,cAAc,UAAU;AACxC,YAAQ,IAAI,YAAY,aAAa,OAAO,SAAS,CAAC,EAAE;AACxD,YAAQ,IAAI,YAAY,KAAK,IAAI,KAAK,OAAO,YAAY,QAAQ,IAAI,EAAE;AAAA,EACzE;AACA,UAAQ,IAAI,aAAa,YAAY,CAAC,EAAE;AACxC,UAAQ,IAAI,UAAU,aAAa,CAAC,EAAE;AACtC,UAAQ,IAAI,aAAa,gBAAgB,CAAC,EAAE;AAC9C;","names":[]}
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ import { runAskCommand } from "./commands/ask.js";
3
+ import { runClearCommand } from "./commands/clear.js";
4
+ import { printHelp } from "./commands/help.js";
5
+ import { runLoginCommand } from "./commands/login.js";
6
+ import { runModelsCommand } from "./commands/models.js";
7
+ import { runServeCommand } from "./commands/serve.js";
8
+ import { runStatusCommand } from "./commands/status.js";
9
+ async function runCli(argv = process.argv.slice(2)) {
10
+ const [command, ...rest] = argv;
11
+ switch (command) {
12
+ case "login":
13
+ await runLoginCommand();
14
+ return;
15
+ case "status":
16
+ await runStatusCommand();
17
+ return;
18
+ case "models":
19
+ await runModelsCommand();
20
+ return;
21
+ case "ask":
22
+ await runAskCommand(rest);
23
+ return;
24
+ case "serve":
25
+ await runServeCommand(rest);
26
+ return;
27
+ case "clear":
28
+ await runClearCommand();
29
+ return;
30
+ case "help":
31
+ case "--help":
32
+ case "-h":
33
+ case void 0:
34
+ printHelp();
35
+ return;
36
+ default:
37
+ throw new Error(`\u672A\u77E5\u547D\u4EE4: ${command}`);
38
+ }
39
+ }
40
+ export {
41
+ runCli
42
+ };
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["import { runAskCommand } from \"./commands/ask.js\";\nimport { runClearCommand } from \"./commands/clear.js\";\nimport { printHelp } from \"./commands/help.js\";\nimport { runLoginCommand } from \"./commands/login.js\";\nimport { runModelsCommand } from \"./commands/models.js\";\nimport { runServeCommand } from \"./commands/serve.js\";\nimport { runStatusCommand } from \"./commands/status.js\";\n\nexport async function runCli(argv: string[] = process.argv.slice(2)): Promise<void> {\n const [command, ...rest] = argv;\n\n switch (command) {\n case \"login\":\n await runLoginCommand();\n return;\n case \"status\":\n await runStatusCommand();\n return;\n case \"models\":\n await runModelsCommand();\n return;\n case \"ask\":\n await runAskCommand(rest);\n return;\n case \"serve\":\n await runServeCommand(rest);\n return;\n case \"clear\":\n await runClearCommand();\n return;\n case \"help\":\n case \"--help\":\n case \"-h\":\n case undefined:\n printHelp();\n return;\n default:\n throw new Error(`未知命令: ${command}`);\n }\n}\n"],"mappings":";AAAA,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAChC,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AAEjC,eAAsB,OAAO,OAAiB,QAAQ,KAAK,MAAM,CAAC,GAAkB;AAClF,QAAM,CAAC,SAAS,GAAG,IAAI,IAAI;AAE3B,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,YAAM,gBAAgB;AACtB;AAAA,IACF,KAAK;AACH,YAAM,iBAAiB;AACvB;AAAA,IACF,KAAK;AACH,YAAM,iBAAiB;AACvB;AAAA,IACF,KAAK;AACH,YAAM,cAAc,IAAI;AACxB;AAAA,IACF,KAAK;AACH,YAAM,gBAAgB,IAAI;AAC1B;AAAA,IACF,KAAK;AACH,YAAM,gBAAgB;AACtB;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,gBAAU;AACV;AAAA,IACF;AACE,YAAM,IAAI,MAAM,6BAAS,OAAO,EAAE;AAAA,EACtC;AACF;","names":[]}
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ function formatExpiry(expires) {
3
+ return new Date(expires).toLocaleString("zh-CN", {
4
+ hour12: false
5
+ });
6
+ }
7
+ function parseAskArgs(args) {
8
+ const rest = [...args];
9
+ let model;
10
+ for (let index = 0; index < rest.length; index += 1) {
11
+ if (rest[index] !== "--model") {
12
+ continue;
13
+ }
14
+ model = rest[index + 1];
15
+ rest.splice(index, 2);
16
+ break;
17
+ }
18
+ return {
19
+ model,
20
+ prompt: rest.join(" ").trim()
21
+ };
22
+ }
23
+ function parseServeArgs(args) {
24
+ const rest = [...args];
25
+ let host;
26
+ let port;
27
+ for (let index = 0; index < rest.length; index += 1) {
28
+ if (rest[index] === "--host") {
29
+ host = rest[index + 1];
30
+ rest.splice(index, 2);
31
+ index -= 1;
32
+ continue;
33
+ }
34
+ if (rest[index] === "--port") {
35
+ const value = Number.parseInt(rest[index + 1] ?? "", 10);
36
+ if (Number.isFinite(value)) {
37
+ port = value;
38
+ }
39
+ rest.splice(index, 2);
40
+ index -= 1;
41
+ }
42
+ }
43
+ return { host, port };
44
+ }
45
+ export {
46
+ formatExpiry,
47
+ parseAskArgs,
48
+ parseServeArgs
49
+ };
50
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/shared.ts"],"sourcesContent":["export function formatExpiry(expires: number): string {\n return new Date(expires).toLocaleString(\"zh-CN\", {\n hour12: false,\n });\n}\n\nexport function parseAskArgs(args: string[]): { model?: string; prompt: string } {\n const rest = [...args];\n let model: string | undefined;\n for (let index = 0; index < rest.length; index += 1) {\n if (rest[index] !== \"--model\") {\n continue;\n }\n\n model = rest[index + 1];\n rest.splice(index, 2);\n break;\n }\n return {\n model,\n prompt: rest.join(\" \").trim(),\n };\n}\n\nexport function parseServeArgs(args: string[]): { host?: string; port?: number } {\n const rest = [...args];\n let host: string | undefined;\n let port: number | undefined;\n\n for (let index = 0; index < rest.length; index += 1) {\n if (rest[index] === \"--host\") {\n host = rest[index + 1];\n rest.splice(index, 2);\n index -= 1;\n continue;\n }\n\n if (rest[index] === \"--port\") {\n const value = Number.parseInt(rest[index + 1] ?? \"\", 10);\n if (Number.isFinite(value)) {\n port = value;\n }\n rest.splice(index, 2);\n index -= 1;\n }\n }\n\n return { host, port };\n}\n"],"mappings":";AAAO,SAAS,aAAa,SAAyB;AACpD,SAAO,IAAI,KAAK,OAAO,EAAE,eAAe,SAAS;AAAA,IAC/C,QAAQ;AAAA,EACV,CAAC;AACH;AAEO,SAAS,aAAa,MAAoD;AAC/E,QAAM,OAAO,CAAC,GAAG,IAAI;AACrB,MAAI;AACJ,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACnD,QAAI,KAAK,KAAK,MAAM,WAAW;AAC7B;AAAA,IACF;AAEA,YAAQ,KAAK,QAAQ,CAAC;AACtB,SAAK,OAAO,OAAO,CAAC;AACpB;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,KAAK,KAAK,GAAG,EAAE,KAAK;AAAA,EAC9B;AACF;AAEO,SAAS,eAAe,MAAkD;AAC/E,QAAM,OAAO,CAAC,GAAG,IAAI;AACrB,MAAI;AACJ,MAAI;AAEJ,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACnD,QAAI,KAAK,KAAK,MAAM,UAAU;AAC5B,aAAO,KAAK,QAAQ,CAAC;AACrB,WAAK,OAAO,OAAO,CAAC;AACpB,eAAS;AACT;AAAA,IACF;AAEA,QAAI,KAAK,KAAK,MAAM,UAAU;AAC5B,YAAM,QAAQ,OAAO,SAAS,KAAK,QAAQ,CAAC,KAAK,IAAI,EAAE;AACvD,UAAI,OAAO,SAAS,KAAK,GAAG;AAC1B,eAAO;AAAA,MACT;AACA,WAAK,OAAO,OAAO,CAAC;AACpB,eAAS;AAAA,IACX;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,KAAK;AACtB;","names":[]}
package/dist/cli.js ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from "./cli/index.js";
3
+ runCli().catch((error) => {
4
+ const message = error instanceof Error ? error.message : String(error);
5
+ console.error(`\u9519\u8BEF: ${message}`);
6
+ process.exitCode = 1;
7
+ });
8
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { runCli } from \"./cli/index.js\";\n\nrunCli().catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`错误: ${message}`);\n process.exitCode = 1;\n});\n"],"mappings":";AAAA,SAAS,cAAc;AAEvB,OAAO,EAAE,MAAM,CAAC,UAAU;AACxB,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAQ,MAAM,iBAAO,OAAO,EAAE;AAC9B,UAAQ,WAAW;AACrB,CAAC;","names":[]}
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ import { ConfigService } from "./services/config-service.js";
3
+ import { AuthService } from "./services/auth-service.js";
4
+ import { ChatService } from "./services/chat-service.js";
5
+ import { ModelService } from "./services/model-service.js";
6
+ function createGatewayContext() {
7
+ const configService = new ConfigService();
8
+ const authService = new AuthService(configService);
9
+ const modelService = new ModelService(configService);
10
+ const chatService = new ChatService({
11
+ authService,
12
+ modelService
13
+ });
14
+ return {
15
+ configService,
16
+ authService,
17
+ modelService,
18
+ chatService
19
+ };
20
+ }
21
+ export {
22
+ createGatewayContext
23
+ };
24
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/context.ts"],"sourcesContent":["import { ConfigService } from \"./services/config-service.js\";\nimport { AuthService } from \"./services/auth-service.js\";\nimport { ChatService } from \"./services/chat-service.js\";\nimport { ModelService } from \"./services/model-service.js\";\n\nexport function createGatewayContext() {\n const configService = new ConfigService();\n const authService = new AuthService(configService);\n const modelService = new ModelService(configService);\n const chatService = new ChatService({\n authService,\n modelService,\n });\n\n return {\n configService,\n authService,\n modelService,\n chatService,\n };\n}\n"],"mappings":";AAAA,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB;AAC5B,SAAS,oBAAoB;AAEtB,SAAS,uBAAuB;AACrC,QAAM,gBAAgB,IAAI,cAAc;AACxC,QAAM,cAAc,IAAI,YAAY,aAAa;AACjD,QAAM,eAAe,IAAI,aAAa,aAAa;AACnD,QAAM,cAAc,IAAI,YAAY;AAAA,IAClC;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ const DEFAULT_CODEX_MODEL = "gpt-5.4";
3
+ const CODEX_MODEL_INFOS = [
4
+ { provider: "openai-codex", id: "gpt-5.4", name: "GPT-5.4", input: ["text", "image"], source: "static" },
5
+ { provider: "openai-codex", id: "gpt-5.2", name: "GPT-5.2", input: ["text", "image"], source: "static" },
6
+ { provider: "openai-codex", id: "gpt-5.2-codex", name: "GPT-5.2 Codex", input: ["text", "image"], source: "static" },
7
+ { provider: "openai-codex", id: "gpt-5.3-codex", name: "GPT-5.3 Codex", input: ["text", "image"], source: "static" },
8
+ { provider: "openai-codex", id: "gpt-5.3-codex-spark", name: "GPT-5.3 Codex Spark", input: ["text"], source: "static" },
9
+ { provider: "openai-codex", id: "gpt-5.1", name: "GPT-5.1", input: ["text", "image"], source: "static" },
10
+ { provider: "openai-codex", id: "gpt-5.1-codex", name: "GPT-5.1 Codex", input: ["text", "image"], source: "static" },
11
+ { provider: "openai-codex", id: "gpt-5.1-codex-mini", name: "GPT-5.1 Codex Mini", input: ["text", "image"], source: "static" },
12
+ { provider: "openai-codex", id: "gpt-5.1-codex-max", name: "GPT-5.1 Codex Max", input: ["text", "image"], source: "static" }
13
+ ];
14
+ const SUPPORTED_CODEX_MODELS = [
15
+ "gpt-5.4",
16
+ "gpt-5.2",
17
+ "gpt-5.2-codex",
18
+ "gpt-5.3-codex",
19
+ "gpt-5.3-codex-spark",
20
+ "gpt-5.1",
21
+ "gpt-5.1-codex",
22
+ "gpt-5.1-codex-mini",
23
+ "gpt-5.1-codex-max"
24
+ ];
25
+ function isSupportedCodexModel(model) {
26
+ return SUPPORTED_CODEX_MODELS.includes(model);
27
+ }
28
+ export {
29
+ CODEX_MODEL_INFOS,
30
+ DEFAULT_CODEX_MODEL,
31
+ SUPPORTED_CODEX_MODELS,
32
+ isSupportedCodexModel
33
+ };
34
+ //# sourceMappingURL=openai-codex-models.js.map