@getrouter/getrouter-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/.github/workflows/ci.yml +19 -0
  2. package/AGENTS.md +78 -0
  3. package/README.ja.md +116 -0
  4. package/README.md +116 -0
  5. package/README.zh-cn.md +116 -0
  6. package/biome.json +10 -0
  7. package/bun.lock +397 -0
  8. package/dist/bin.mjs +1422 -0
  9. package/docs/plans/2026-01-01-getrouter-cli-config-command-plan.md +231 -0
  10. package/docs/plans/2026-01-01-getrouter-cli-config-core-plan.md +307 -0
  11. package/docs/plans/2026-01-01-getrouter-cli-design.md +106 -0
  12. package/docs/plans/2026-01-01-getrouter-cli-scaffold-plan.md +327 -0
  13. package/docs/plans/2026-01-02-getrouter-cli-auth-design.md +68 -0
  14. package/docs/plans/2026-01-02-getrouter-cli-auth-device-design.md +73 -0
  15. package/docs/plans/2026-01-02-getrouter-cli-auth-device-plan.md +411 -0
  16. package/docs/plans/2026-01-02-getrouter-cli-auth-plan.md +435 -0
  17. package/docs/plans/2026-01-02-getrouter-cli-http-client-plan.md +235 -0
  18. package/docs/plans/2026-01-02-getrouter-cli-keys-create-update-output-design.md +24 -0
  19. package/docs/plans/2026-01-02-getrouter-cli-keys-create-update-output-plan.md +141 -0
  20. package/docs/plans/2026-01-02-getrouter-cli-keys-delete-output-design.md +22 -0
  21. package/docs/plans/2026-01-02-getrouter-cli-keys-delete-output-plan.md +122 -0
  22. package/docs/plans/2026-01-02-getrouter-cli-keys-get-output-design.md +23 -0
  23. package/docs/plans/2026-01-02-getrouter-cli-keys-get-output-plan.md +141 -0
  24. package/docs/plans/2026-01-02-getrouter-cli-keys-interactive-design.md +28 -0
  25. package/docs/plans/2026-01-02-getrouter-cli-keys-interactive-plan.md +247 -0
  26. package/docs/plans/2026-01-02-getrouter-cli-keys-output-design.md +31 -0
  27. package/docs/plans/2026-01-02-getrouter-cli-keys-output-plan.md +187 -0
  28. package/docs/plans/2026-01-02-getrouter-cli-keys-subscription-design.md +52 -0
  29. package/docs/plans/2026-01-02-getrouter-cli-keys-subscription-plan.md +306 -0
  30. package/docs/plans/2026-01-02-getrouter-cli-setup-env-design.md +67 -0
  31. package/docs/plans/2026-01-02-getrouter-cli-setup-env-plan.md +441 -0
  32. package/docs/plans/2026-01-02-getrouter-cli-subscription-output-design.md +34 -0
  33. package/docs/plans/2026-01-02-getrouter-cli-subscription-output-plan.md +157 -0
  34. package/docs/plans/2026-01-03-bun-migration-plan.md +103 -0
  35. package/docs/plans/2026-01-03-cli-emoji-output.md +45 -0
  36. package/docs/plans/2026-01-03-cli-english-output.md +123 -0
  37. package/docs/plans/2026-01-03-cli-simplify-design.md +62 -0
  38. package/docs/plans/2026-01-03-cli-simplify-implementation.md +468 -0
  39. package/docs/plans/2026-01-03-readme-command-descriptions.md +116 -0
  40. package/docs/plans/2026-01-03-tsdown-migration-plan.md +75 -0
  41. package/docs/plans/2026-01-04-cli-docs-cleanup-design.md +49 -0
  42. package/docs/plans/2026-01-04-cli-docs-cleanup-plan.md +126 -0
  43. package/docs/plans/2026-01-04-codex-multistep-design.md +76 -0
  44. package/docs/plans/2026-01-04-codex-multistep-plan.md +240 -0
  45. package/docs/plans/2026-01-04-env-hook-design.md +48 -0
  46. package/docs/plans/2026-01-04-env-hook-plan.md +173 -0
  47. package/docs/plans/2026-01-04-models-keys-fuzzy-design.md +75 -0
  48. package/docs/plans/2026-01-04-models-keys-fuzzy-implementation.md +704 -0
  49. package/package.json +37 -0
  50. package/src/.gitkeep +0 -0
  51. package/src/bin.ts +4 -0
  52. package/src/cli.ts +12 -0
  53. package/src/cmd/auth.ts +44 -0
  54. package/src/cmd/claude.ts +10 -0
  55. package/src/cmd/codex.ts +119 -0
  56. package/src/cmd/config-helpers.ts +16 -0
  57. package/src/cmd/config.ts +31 -0
  58. package/src/cmd/env.ts +103 -0
  59. package/src/cmd/index.ts +20 -0
  60. package/src/cmd/keys.ts +207 -0
  61. package/src/cmd/models.ts +48 -0
  62. package/src/cmd/status.ts +106 -0
  63. package/src/cmd/usages.ts +29 -0
  64. package/src/core/api/client.ts +79 -0
  65. package/src/core/auth/device.ts +105 -0
  66. package/src/core/auth/index.ts +37 -0
  67. package/src/core/config/fs.ts +13 -0
  68. package/src/core/config/index.ts +37 -0
  69. package/src/core/config/paths.ts +5 -0
  70. package/src/core/config/redact.ts +18 -0
  71. package/src/core/config/types.ts +23 -0
  72. package/src/core/http/errors.ts +32 -0
  73. package/src/core/http/request.ts +41 -0
  74. package/src/core/http/url.ts +12 -0
  75. package/src/core/interactive/clipboard.ts +61 -0
  76. package/src/core/interactive/codex.ts +75 -0
  77. package/src/core/interactive/fuzzy.ts +64 -0
  78. package/src/core/interactive/keys.ts +164 -0
  79. package/src/core/output/table.ts +34 -0
  80. package/src/core/output/usages.ts +75 -0
  81. package/src/core/paths.ts +4 -0
  82. package/src/core/setup/codex.ts +129 -0
  83. package/src/core/setup/env.ts +220 -0
  84. package/src/core/usages/aggregate.ts +69 -0
  85. package/src/generated/router/dashboard/v1/index.ts +1104 -0
  86. package/src/index.ts +1 -0
  87. package/tests/.gitkeep +0 -0
  88. package/tests/auth/device.test.ts +75 -0
  89. package/tests/auth/status.test.ts +64 -0
  90. package/tests/cli.test.ts +31 -0
  91. package/tests/cmd/auth.test.ts +90 -0
  92. package/tests/cmd/claude.test.ts +132 -0
  93. package/tests/cmd/codex.test.ts +147 -0
  94. package/tests/cmd/config-helpers.test.ts +18 -0
  95. package/tests/cmd/config.test.ts +56 -0
  96. package/tests/cmd/keys.test.ts +163 -0
  97. package/tests/cmd/models.test.ts +63 -0
  98. package/tests/cmd/status.test.ts +82 -0
  99. package/tests/cmd/usages.test.ts +42 -0
  100. package/tests/config/fs.test.ts +14 -0
  101. package/tests/config/index.test.ts +63 -0
  102. package/tests/config/paths.test.ts +10 -0
  103. package/tests/config/redact.test.ts +17 -0
  104. package/tests/config/types.test.ts +10 -0
  105. package/tests/core/api/client.test.ts +92 -0
  106. package/tests/core/interactive/clipboard.test.ts +44 -0
  107. package/tests/core/interactive/codex.test.ts +17 -0
  108. package/tests/core/interactive/fuzzy.test.ts +30 -0
  109. package/tests/core/setup/codex.test.ts +38 -0
  110. package/tests/core/setup/env.test.ts +84 -0
  111. package/tests/core/usages/aggregate.test.ts +55 -0
  112. package/tests/http/errors.test.ts +15 -0
  113. package/tests/http/request.test.ts +82 -0
  114. package/tests/http/url.test.ts +17 -0
  115. package/tests/output/table.test.ts +29 -0
  116. package/tests/output/usages.test.ts +71 -0
  117. package/tests/paths.test.ts +9 -0
  118. package/tsconfig.json +13 -0
  119. package/tsdown.config.ts +5 -0
  120. package/vitest.config.ts +7 -0
@@ -0,0 +1,327 @@
1
+ # getrouter CLI Scaffold Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Set up a Node/TypeScript CLI scaffold for `getrouter` with build/test tooling, a minimal command tree, and initial core utilities.
6
+
7
+ **Architecture:** A thin CLI layer built on `commander` with an entrypoint in `src/bin.ts`, a program factory in `src/cli.ts`, placeholder command modules in `src/cmd/*`, and a small `core` utility for config paths. Build with `tsup` and test with `vitest`.
8
+
9
+ **Tech Stack:** Node.js 18+, TypeScript, commander, tsup, vitest.
10
+
11
+ ---
12
+
13
+ ### Task 1: Tooling & Project Bootstrap
14
+
15
+ **Files:**
16
+ - Create: `package.json`
17
+ - Create: `tsconfig.json`
18
+ - Create: `tsup.config.ts`
19
+ - Create: `vitest.config.ts`
20
+ - Create: `src/.gitkeep`
21
+ - Create: `tests/.gitkeep`
22
+
23
+ **Step 1: Create package.json**
24
+
25
+ ```json
26
+ {
27
+ "name": "getrouter",
28
+ "version": "0.1.0",
29
+ "description": "CLI for getrouter.dev",
30
+ "bin": {
31
+ "getrouter": "dist/bin.js"
32
+ },
33
+ "scripts": {
34
+ "build": "tsup",
35
+ "dev": "tsx src/bin.ts --help",
36
+ "test": "vitest run",
37
+ "typecheck": "tsc -p tsconfig.json --noEmit"
38
+ },
39
+ "engines": {
40
+ "node": ">=18"
41
+ },
42
+ "dependencies": {
43
+ "commander": "^12.1.0"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^20.12.12",
47
+ "tsup": "^8.3.5",
48
+ "tsx": "^4.19.2",
49
+ "typescript": "^5.7.3",
50
+ "vitest": "^2.1.8"
51
+ }
52
+ }
53
+ ```
54
+
55
+ **Step 2: Create tsconfig.json**
56
+
57
+ ```json
58
+ {
59
+ "compilerOptions": {
60
+ "target": "ES2020",
61
+ "module": "CommonJS",
62
+ "rootDir": "src",
63
+ "outDir": "dist",
64
+ "strict": true,
65
+ "esModuleInterop": true,
66
+ "moduleResolution": "node",
67
+ "skipLibCheck": true
68
+ },
69
+ "include": ["src", "tests"]
70
+ }
71
+ ```
72
+
73
+ **Step 3: Create tsup.config.ts**
74
+
75
+ ```ts
76
+ import { defineConfig } from "tsup";
77
+
78
+ export default defineConfig({
79
+ entry: ["src/bin.ts"],
80
+ format: ["cjs"],
81
+ sourcemap: true,
82
+ clean: true,
83
+ });
84
+ ```
85
+
86
+ **Step 4: Create vitest.config.ts**
87
+
88
+ ```ts
89
+ import { defineConfig } from "vitest/config";
90
+
91
+ export default defineConfig({
92
+ test: {
93
+ include: ["tests/**/*.test.ts"],
94
+ },
95
+ });
96
+ ```
97
+
98
+ **Step 5: Add placeholder directories**
99
+
100
+ Create empty files to ensure directories are tracked:
101
+
102
+ - `src/.gitkeep`
103
+ - `tests/.gitkeep`
104
+
105
+ **Step 6: Install deps**
106
+
107
+ Run: `npm install`
108
+ Expected: dependencies installed.
109
+
110
+ **Step 7: Sanity check tooling**
111
+
112
+ Run: `npm run typecheck`
113
+ Expected: PASS (no TS files yet).
114
+
115
+ **Step 8: Commit**
116
+
117
+ ```bash
118
+ git add package.json tsconfig.json tsup.config.ts vitest.config.ts src/.gitkeep tests/.gitkeep
119
+ git commit -m "chore: bootstrap cli tooling"
120
+ ```
121
+
122
+ ---
123
+
124
+ ### Task 2: Minimal CLI Program (TDD)
125
+
126
+ **Files:**
127
+ - Create: `src/cli.ts`
128
+ - Create: `src/bin.ts`
129
+ - Create: `tests/cli.test.ts`
130
+
131
+ **Step 1: Write the failing test**
132
+
133
+ ```ts
134
+ import { describe, it, expect } from "vitest";
135
+ import { createProgram } from "../src/cli";
136
+
137
+ describe("getrouter cli", () => {
138
+ it("exposes name and help", () => {
139
+ const program = createProgram();
140
+ expect(program.name()).toBe("getrouter");
141
+ expect(program.helpInformation()).toContain("getrouter");
142
+ });
143
+ });
144
+ ```
145
+
146
+ **Step 2: Run test to verify it fails**
147
+
148
+ Run: `npm test`
149
+ Expected: FAIL (module not found or createProgram missing).
150
+
151
+ **Step 3: Write minimal implementation**
152
+
153
+ `src/cli.ts`
154
+
155
+ ```ts
156
+ import { Command } from "commander";
157
+
158
+ export const createProgram = () => {
159
+ const program = new Command();
160
+ program
161
+ .name("getrouter")
162
+ .description("CLI for getrouter.dev")
163
+ .version("0.1.0");
164
+ return program;
165
+ };
166
+ ```
167
+
168
+ `src/bin.ts`
169
+
170
+ ```ts
171
+ #!/usr/bin/env node
172
+ import { createProgram } from "./cli";
173
+
174
+ createProgram().parse(process.argv);
175
+ ```
176
+
177
+ **Step 4: Run test to verify it passes**
178
+
179
+ Run: `npm test`
180
+ Expected: PASS.
181
+
182
+ **Step 5: Commit**
183
+
184
+ ```bash
185
+ git add src/cli.ts src/bin.ts tests/cli.test.ts
186
+ git commit -m "feat: add minimal cli entrypoint"
187
+ ```
188
+
189
+ ---
190
+
191
+ ### Task 3: Command Tree Skeleton
192
+
193
+ **Files:**
194
+ - Create: `src/cmd/index.ts`
195
+ - Create: `src/cmd/auth.ts`
196
+ - Create: `src/cmd/keys.ts`
197
+ - Create: `src/cmd/subscription.ts`
198
+ - Create: `src/cmd/plans.ts`
199
+ - Create: `src/cmd/models.ts`
200
+ - Create: `src/cmd/providers.ts`
201
+ - Create: `src/cmd/user.ts`
202
+ - Modify: `src/cli.ts`
203
+
204
+ **Step 1: Implement command modules**
205
+
206
+ Example (`src/cmd/auth.ts`):
207
+
208
+ ```ts
209
+ import { Command } from "commander";
210
+
211
+ export const registerAuthCommands = (program: Command) => {
212
+ const auth = program.command("auth").description("Authentication");
213
+ auth.command("login").description("Login with GitHub OAuth");
214
+ auth.command("logout").description("Clear local auth state");
215
+ auth.command("status").description("Show current auth status");
216
+ };
217
+ ```
218
+
219
+ Repeat similarly for:
220
+ - `keys` (list/create/update/delete/get)
221
+ - `subscription` (show)
222
+ - `plans` (list)
223
+ - `models` (list)
224
+ - `providers` (list)
225
+ - `user` (current)
226
+
227
+ `src/cmd/index.ts`:
228
+
229
+ ```ts
230
+ import { Command } from "commander";
231
+ import { registerAuthCommands } from "./auth";
232
+ import { registerKeysCommands } from "./keys";
233
+ import { registerSubscriptionCommands } from "./subscription";
234
+ import { registerPlansCommands } from "./plans";
235
+ import { registerModelsCommands } from "./models";
236
+ import { registerProvidersCommands } from "./providers";
237
+ import { registerUserCommands } from "./user";
238
+
239
+ export const registerCommands = (program: Command) => {
240
+ registerAuthCommands(program);
241
+ registerKeysCommands(program);
242
+ registerSubscriptionCommands(program);
243
+ registerPlansCommands(program);
244
+ registerModelsCommands(program);
245
+ registerProvidersCommands(program);
246
+ registerUserCommands(program);
247
+ };
248
+ ```
249
+
250
+ **Step 2: Wire command tree**
251
+
252
+ Modify `src/cli.ts`:
253
+
254
+ ```ts
255
+ import { Command } from "commander";
256
+ import { registerCommands } from "./cmd";
257
+
258
+ export const createProgram = () => {
259
+ const program = new Command();
260
+ program
261
+ .name("getrouter")
262
+ .description("CLI for getrouter.dev")
263
+ .version("0.1.0");
264
+ registerCommands(program);
265
+ return program;
266
+ };
267
+ ```
268
+
269
+ **Step 3: Run tests**
270
+
271
+ Run: `npm test`
272
+ Expected: PASS.
273
+
274
+ **Step 4: Commit**
275
+
276
+ ```bash
277
+ git add src/cmd src/cli.ts
278
+ git commit -m "feat: add command tree skeleton"
279
+ ```
280
+
281
+ ---
282
+
283
+ ### Task 4: Core Paths Utility (TDD)
284
+
285
+ **Files:**
286
+ - Create: `src/core/paths.ts`
287
+ - Create: `tests/paths.test.ts`
288
+
289
+ **Step 1: Write the failing test**
290
+
291
+ ```ts
292
+ import { describe, it, expect } from "vitest";
293
+ import { getConfigDir } from "../src/core/paths";
294
+
295
+ describe("paths", () => {
296
+ it("returns ~/.getrouter path", () => {
297
+ const dir = getConfigDir();
298
+ expect(dir).toContain(".getrouter");
299
+ });
300
+ });
301
+ ```
302
+
303
+ **Step 2: Run test to verify it fails**
304
+
305
+ Run: `npm test`
306
+ Expected: FAIL (module not found).
307
+
308
+ **Step 3: Write minimal implementation**
309
+
310
+ ```ts
311
+ import path from "node:path";
312
+ import os from "node:os";
313
+
314
+ export const getConfigDir = () => path.join(os.homedir(), ".getrouter");
315
+ ```
316
+
317
+ **Step 4: Run test to verify it passes**
318
+
319
+ Run: `npm test`
320
+ Expected: PASS.
321
+
322
+ **Step 5: Commit**
323
+
324
+ ```bash
325
+ git add src/core/paths.ts tests/paths.test.ts
326
+ git commit -m "feat: add config path helper"
327
+ ```
@@ -0,0 +1,68 @@
1
+ # getrouter CLI 认证设计(OAuth 未就绪占位)
2
+
3
+ 日期:2026-01-02
4
+ 状态:已确认
5
+
6
+ ## 背景
7
+ - getrouter OAuth/设备码流程仍在开发中,需要先提供 CLI 占位行为以保证体验一致与可预测。
8
+ - 当前阶段不写入虚假 token,避免误导用户或污染本地状态。
9
+
10
+ ## 目标与范围(当前阶段)
11
+ - `auth login` 提示“OAuth 未就绪”,不写入 `auth.json`。
12
+ - `auth logout` 清理本地认证文件。
13
+ - `auth status` 做本地判断,输出“远端验证待开放”。
14
+ - 输出支持 `--json`,默认人类可读。
15
+
16
+ ## 非目标(当前阶段)
17
+ - 不启动本地回调服务。
18
+ - 不与任何 OAuth/设备码接口通信。
19
+ - 不校验远端用户状态。
20
+
21
+ ## 命令与交互
22
+ - `getrouter auth login`
23
+ - 输出提示:OAuth 仍在开发中,暂不支持登录。
24
+ - 不写入或修改 `~/.getrouter/auth.json`。
25
+ - `getrouter auth logout`
26
+ - 删除或清空 `~/.getrouter/auth.json`。
27
+ - 输出“已清除本地认证信息”。
28
+ - `getrouter auth status`
29
+ - 读取 `auth.json`(如存在),检查字段完整性与过期时间。
30
+ - 若缺失或过期:显示“未登录”。
31
+ - 若完整且未过期:显示“已登录(仅本地验证,远端验证待开放)”。
32
+
33
+ ## 存储与字段
34
+ - 认证文件:`~/.getrouter/auth.json`
35
+ - 结构:
36
+ ```json
37
+ {
38
+ "accessToken": "...",
39
+ "refreshToken": "...",
40
+ "expiresAt": "2026-01-02T00:00:00Z",
41
+ "tokenType": "Bearer"
42
+ }
43
+ ```
44
+ - `tokenType` 默认 `Bearer`(后续真实 OAuth 可覆盖)。
45
+ - `expiresAt` 使用 ISO8601 字符串。
46
+ - *nix 系统写入时强制 `0600` 权限;Windows 保持默认 ACL。
47
+
48
+ ## 输出与脱敏
49
+ - 默认输出脱敏 token(仅显示前后 4 位)。
50
+ - 仅在 `--show-secret` 下展示完整 token。
51
+ - `--json` 输出结构化字段:`status`、`expiresAt`、`note`。
52
+
53
+ ## 错误处理
54
+ - JSON 解析失败、无权限写入等:提示路径与修复建议,返回非零退出码。
55
+ - 远端校验未实现时,`auth status` 明确标注“远端验证待开放”。
56
+
57
+ ## 测试策略
58
+ - 单测覆盖:
59
+ - 状态判定(未登录/已登录/过期)。
60
+ - `tokenType` 默认值与 `expiresAt` 解析。
61
+ - `auth login` 只提示不落盘。
62
+ - `auth logout` 清理文件。
63
+ - *nix 下断言 `0600`;Windows 仅断言写入成功。
64
+
65
+ ## 未来接入 OAuth 的扩展点
66
+ - 登录流程:本地回调 + 浏览器打开 + 回调接口换 token。
67
+ - `auth status` 增加“远端验证”调用。
68
+ - `core/http` 可扩展 401 触发 refresh 并重试。
@@ -0,0 +1,73 @@
1
+ # getrouter CLI 设备码式登录设计
2
+
3
+ 日期:2026-01-02
4
+
5
+ ## 背景与目标
6
+
7
+ 现有 CLI 的 `auth login` 仅提示 OAuth 未就绪。根据最新 auth 流程,CLI 需改为类似 tailscale 的设备码式登录:
8
+ - CLI 本地生成 `auth_code`(13 位小写 base32)
9
+ - 打开浏览器访问 `https://getrouter.dev/#/a/{auth_code}`
10
+ - CLI 轮询 `POST /v1/dashboard/auth/authorize`,body `{ code: auth_code }`
11
+ - 成功返回 `AuthToken` 后写入 `~/.getrouter/auth.json`
12
+
13
+ ## 关键流程
14
+
15
+ 1. `auth login` 生成 `auth_code`(13 位小写 base32)。
16
+ 2. 输出登录 URL,并尝试自动打开浏览器(macOS: `open`;Windows: `start`;Linux: `xdg-open`)。失败不阻断流程。
17
+ 3. CLI 进入轮询:
18
+ - 请求:`POST /v1/dashboard/auth/authorize`,body `{ code: auth_code }`
19
+ - 成功:HTTP 200 + `AuthToken`
20
+ - 未确认:HTTP 404(AUTH not found)→ 继续轮询
21
+ - 已兑换:HTTP 400(code already exchanged)→ 失败退出
22
+ - 过期:HTTP 403(token expired)→ 失败退出
23
+ - 其他 4xx/5xx:失败退出
24
+ 4. 轮询策略:指数退避 1s → 2s → 4s → 8s → 10s(封顶),总超时 5 分钟。
25
+ 5. 成功后写入 `auth.json`,并输出“登录成功”。
26
+ 6. Ctrl+C 中断轮询并提示“已取消登录”。
27
+
28
+ ## 数据与存储
29
+
30
+ - `AuthToken` 字段:`access_token`、`refresh_token`、`expires_at`。
31
+ - 写入位置:`~/.getrouter/auth.json` 或 `GETROUTER_CONFIG_DIR` 指定路径。
32
+ - 文件权限:`0600`(已有 `writeAuth` 逻辑覆盖)。
33
+
34
+ ## 错误处理
35
+
36
+ - 404:视为“未确认”,继续轮询。
37
+ - 400:视为“已兑换”,提示重新登录。
38
+ - 403:视为“已过期”,提示重新登录。
39
+ - 其他状态:直接失败,提示重试。
40
+
41
+ ## CLI 交互示例
42
+
43
+ ```
44
+ To authenticate, visit:
45
+ https://getrouter.dev/#/a/<auth_code>
46
+ Waiting for confirmation...
47
+ ```
48
+
49
+ 成功后:
50
+ ```
51
+ 登录成功
52
+ ```
53
+
54
+ ## 需要改动的模块
55
+
56
+ - `src/cmd/auth.ts`:实现设备码式登录流程。
57
+ - `src/core/auth/`:新增设备码登录辅助函数(生成 auth_code、打开浏览器、轮询)。
58
+ - `src/core/api/client.ts`:注入 `createAuthServiceClient`。
59
+ - `src/generated/router/dashboard/v1/index.ts`:确保包含 `AuthService.Authorize`(已生成)。
60
+ - 测试:新增/更新 `tests/cmd/auth.test.ts` 等。
61
+
62
+ ## 测试建议
63
+
64
+ 1. 轮询遇到 404 时继续,直到成功获取 token。
65
+ 2. 400/403 立即失败退出。
66
+ 3. 超时(5 分钟)后提示失败。
67
+ 4. 成功时写入 `auth.json` 且权限正确。
68
+ 5. 浏览器打开失败不影响轮询。
69
+
70
+ ## 不在范围内
71
+
72
+ - OAuth callback / 旧流程保留。
73
+ - 后端接口改动。