@dreamor/atlas-cli 0.7.23 → 0.7.25

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 (46) hide show
  1. package/README.md +1 -59
  2. package/atlas.cjs +226 -0
  3. package/package.json +7 -9
  4. package/atlas.js +0 -5
  5. package/dist/adapters/atlas/auth/browser.js +0 -37
  6. package/dist/adapters/atlas/auth/index.js +0 -4
  7. package/dist/adapters/atlas/auth/login.js +0 -187
  8. package/dist/adapters/atlas/auth/portable.js +0 -193
  9. package/dist/adapters/atlas/auth/refresh.js +0 -138
  10. package/dist/adapters/atlas/auth/session.js +0 -167
  11. package/dist/adapters/atlas/cli.js +0 -561
  12. package/dist/adapters/atlas/commands/_output_schema.js +0 -379
  13. package/dist/adapters/atlas/commands/actual/_logic.js +0 -116
  14. package/dist/adapters/atlas/commands/actual/index.js +0 -138
  15. package/dist/adapters/atlas/commands/auth.js +0 -1
  16. package/dist/adapters/atlas/commands/baseline/index.js +0 -137
  17. package/dist/adapters/atlas/commands/compare/_logic.js +0 -39
  18. package/dist/adapters/atlas/commands/compare/index.js +0 -89
  19. package/dist/adapters/atlas/commands/exec.js +0 -81
  20. package/dist/adapters/atlas/commands/project/index.js +0 -218
  21. package/dist/adapters/atlas/commands/schema.js +0 -25
  22. package/dist/adapters/atlas/commands/suggest.js +0 -83
  23. package/dist/adapters/atlas/commands/update.js +0 -104
  24. package/dist/adapters/atlas/daemon/index.js +0 -145
  25. package/dist/adapters/atlas/dict/index.js +0 -41
  26. package/dist/adapters/atlas/http/client.js +0 -200
  27. package/dist/adapters/atlas/http/index.js +0 -1
  28. package/dist/adapters/atlas/schema/actual.js +0 -16
  29. package/dist/adapters/atlas/schema/baseline.js +0 -34
  30. package/dist/adapters/atlas/schema/department.js +0 -11
  31. package/dist/adapters/atlas/schema/index.js +0 -4
  32. package/dist/adapters/atlas/schema/project.js +0 -13
  33. package/dist/adapters/atlas/util/cidr.js +0 -114
  34. package/dist/adapters/atlas/util/constants.js +0 -4
  35. package/dist/adapters/atlas/util/env.js +0 -56
  36. package/dist/adapters/atlas/util/environment.js +0 -152
  37. package/dist/adapters/atlas/util/errors.js +0 -49
  38. package/dist/adapters/atlas/util/helpers.js +0 -17
  39. package/dist/adapters/atlas/util/months.js +0 -65
  40. package/dist/adapters/atlas/util/output-limit.js +0 -21
  41. package/dist/adapters/atlas/util/output.js +0 -70
  42. package/dist/adapters/atlas/util/paths.js +0 -40
  43. package/dist/adapters/atlas/util/portable-store.js +0 -153
  44. package/dist/adapters/atlas/util/secure-fs.js +0 -41
  45. package/dist/adapters/atlas/util/time.js +0 -17
  46. package/dist/adapters/atlas/util/version.js +0 -1
@@ -1,561 +0,0 @@
1
- #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- // Auth
4
- import { authLoginCmd, authStatusCmd, authRefreshCmd, authExportCmd, authImportCmd, authDoctorCmd } from './commands/auth.js';
5
- // Project commands (find, projects, link, unlink)
6
- import { findCmd, projectsCmd, linkCmd, linkStatusCmd, unlinkCmd, } from './commands/project/index.js';
7
- // Baseline commands (month, summary, export)
8
- import { monthCmd as baselineMonthCmd, summaryCmd as baselineSummaryCmd, exportCmd as baselineExportCmd, } from './commands/baseline/index.js';
9
- // Actual commands (list, show, month, summary, export)
10
- import { showCmd as actualShowCmd, monthCmd as actualMonthCmd, summaryCmd as actualSummaryCmd, exportCmd as actualExportCmd, } from './commands/actual/index.js';
11
- // Compare
12
- import { compareCmd } from './commands/compare/index.js';
13
- // Utility commands
14
- import { daemonCmd } from './daemon/index.js';
15
- import { schemaCommandsCmd } from './commands/schema.js';
16
- import { execCmd } from './commands/exec.js';
17
- import { suggestCmd } from './commands/suggest.js';
18
- import { updateCmd } from './commands/update.js';
19
- import { BanmaApiError, ConfigError, OutputTooLargeError, SessionExpiredError, isAtlasError, } from './util/errors.js';
20
- import { isJsonMode, printError } from './util/output.js';
21
- import { getOutputSchema } from './commands/_output_schema.js';
22
- export function handleError(err) {
23
- if (isJsonMode()) {
24
- printError(err, { json: true });
25
- process.exit(exitCodeFor(err));
26
- }
27
- if (err instanceof SessionExpiredError) {
28
- console.error(err.message);
29
- process.exit(2);
30
- }
31
- if (err instanceof ConfigError) {
32
- console.error(`Config error: ${err.message}`);
33
- process.exit(64);
34
- }
35
- if (err instanceof BanmaApiError) {
36
- console.error(`Banma API error [${err.errCode}] ${err.errorMsg}`);
37
- process.exit(3);
38
- }
39
- if (err instanceof OutputTooLargeError) {
40
- const debug = process.env.DEBUG === '1';
41
- console.error(debug ? err.stack ?? err.message : err.message);
42
- process.exit(65);
43
- }
44
- const debug = process.env.DEBUG === '1';
45
- console.error(err instanceof Error ? (debug ? err.stack ?? err.message : err.message) : String(err));
46
- process.exit(1);
47
- }
48
- export function exitCodeFor(err) {
49
- if (err instanceof SessionExpiredError)
50
- return 2;
51
- if (err instanceof BanmaApiError)
52
- return 3;
53
- if (err instanceof OutputTooLargeError)
54
- return 65;
55
- if (isAtlasError(err)) {
56
- switch (err.code) {
57
- case 'AMBIGUOUS_PROJECT': return 4;
58
- case 'PROJECT_NOT_FOUND': return 5;
59
- case 'RATE_LIMITED': return 6;
60
- case 'NETWORK_ERROR': return 7;
61
- case 'UPDATE_ERROR': return 8;
62
- case 'CONFIG_ERROR': return 64;
63
- case 'INTERACTIVE_REQUIRED': return 64;
64
- default: return 1;
65
- }
66
- }
67
- return 1;
68
- }
69
- export function emitDescribe(cmd) {
70
- const path = [];
71
- let cursor = cmd;
72
- while (cursor && cursor.name() !== 'atlas') {
73
- path.unshift(cursor.name());
74
- cursor = cursor.parent;
75
- }
76
- const commandPath = ['atlas', ...path].join(' ');
77
- const outSchema = getOutputSchema(commandPath);
78
- const payload = {
79
- command: commandPath,
80
- description: cmd.description() ?? '',
81
- options: cmd.options.map((o) => {
82
- const opt = o;
83
- return {
84
- flags: opt.flags,
85
- description: opt.description ?? '',
86
- required: opt.mandatory ?? false,
87
- ...(opt.defaultValue !== undefined ? { default: opt.defaultValue } : {}),
88
- };
89
- }),
90
- args: cmd.registeredArguments?.map((a) => ({
91
- name: a.name(),
92
- required: a.required,
93
- })) ?? [],
94
- subcommands: cmd.commands.map((c) => c.name()),
95
- outputSchema: outSchema.jsonSchema,
96
- };
97
- const envelope = { ok: true, data: payload };
98
- process.stdout.write(JSON.stringify(envelope) + '\n');
99
- }
100
- function addProjectOptions(cmd) {
101
- return cmd
102
- .option('--project-id <id>', '项目ID,精确名称或唯一子串(或使用 BANMA_PROJECT_ID 环境变量)')
103
- .option('--refresh-projects', '解析 --project-id 前重新获取项目目录缓存');
104
- }
105
- // ---------------------------------------------------------------------------
106
- // Registration functions
107
- // ---------------------------------------------------------------------------
108
- function registerAuthCommands(program) {
109
- const auth = program.command('auth').description('SSO 会话管理');
110
- auth
111
- .command('login')
112
- .description('打开浏览器完成 SSO 登录并持久化会话')
113
- .option('--json', '输出 JSON 信封')
114
- .action(async (opts) => {
115
- try {
116
- await authLoginCmd(opts);
117
- }
118
- catch (e) {
119
- handleError(e);
120
- }
121
- });
122
- auth
123
- .command('status')
124
- .description('显示当前会话信息')
125
- .option('--json', '输出 JSON')
126
- .action(async (opts) => {
127
- try {
128
- await authStatusCmd(opts);
129
- }
130
- catch (e) {
131
- handleError(e);
132
- }
133
- });
134
- auth
135
- .command('refresh')
136
- .description('无头模式静默刷新 access_token(依赖 SSO_REFRESH_TOKEN,失败降级到 atlas auth login)')
137
- .option('--json', '输出 JSON 信封')
138
- .action(async (opts) => {
139
- try {
140
- await authRefreshCmd(opts);
141
- }
142
- catch (e) {
143
- handleError(e);
144
- }
145
- });
146
- auth
147
- .command('export')
148
- .description('导出登录态为便携 bundle(默认 --refresh-only 剥离短命 token)')
149
- .option('-o, --out <path>', '输出文件路径(省略时 --base64 写 stdout)')
150
- .option('--base64', 'base64 文本格式(gzip+JSON),方便管道/env 传输')
151
- .option('--refresh-only', '仅长期凭证(默认开启)', true)
152
- .option('--include-access-token', '包含短命 access_token(默认剥离)')
153
- .option('--json', '输出 JSON 信封')
154
- .action(async (opts) => {
155
- try {
156
- await authExportCmd(opts);
157
- }
158
- catch (e) {
159
- handleError(e);
160
- }
161
- });
162
- auth
163
- .command('import')
164
- .description('从便携 bundle 导入登录态(覆盖本地 cookies)')
165
- .option('-i, --input <path>', '导入文件路径(省略 --base64 时从 stdin 读)')
166
- .option('--base64', '输入为 base64 文本格式')
167
- .option('--force', '本地已有登录态时强制覆盖')
168
- .option('--persist', '落盘到 ~/.atlas/cookies.json(默认开启)', true)
169
- .option('--json', '输出 JSON 信封')
170
- .action(async (opts) => {
171
- try {
172
- await authImportCmd(opts);
173
- }
174
- catch (e) {
175
- handleError(e);
176
- }
177
- });
178
- auth
179
- .command('doctor')
180
- .description('诊断当前环境的登录路径(沙盒 agent 自省用)')
181
- .option('--json', '输出 JSON 信封')
182
- .action(async (opts) => {
183
- try {
184
- await authDoctorCmd(opts);
185
- }
186
- catch (e) {
187
- handleError(e);
188
- }
189
- });
190
- }
191
- function registerProjectCommands(program) {
192
- // atlas find
193
- program
194
- .command('find <kind> <query>')
195
- .description('搜索项目/部门/字典值(kind: project|department|manpower-type|role|area)')
196
- .option('--json', '输出 JSON 信封')
197
- .option('--refresh', '刷新字典/部门/项目缓存')
198
- .option('--limit <n>', '最多返回 N 个候选(默认 20)')
199
- .addHelpText('after', `
200
- kind 说明:
201
-
202
- project 搜索有权限的项目列表(从 API 实时查询)
203
- department 搜索部门树中的部门名称(1500+ 部门节点)
204
- manpower-type 搜索人力类型(例: "斑马"、"智软",baseline --manpower-type 用)
205
- role 搜索人力基线角色(例: "开发"、"产品"、"测试"、"PM"、"设计" 等)
206
- area 搜索地域(例: "北上杭"、"合肥"、"武汉"、"西南")`)
207
- .action(async (kind, query, opts) => {
208
- try {
209
- await findCmd(kind, query, opts);
210
- }
211
- catch (e) {
212
- handleError(e);
213
- }
214
- });
215
- // atlas projects
216
- program
217
- .command('projects')
218
- .description('列出我有权限的所有项目')
219
- .option('--json', '输出 JSON 信封')
220
- .option('--refresh', '刷新项目缓存')
221
- .action(async (opts) => {
222
- try {
223
- await projectsCmd(opts);
224
- }
225
- catch (e) {
226
- handleError(e);
227
- }
228
- });
229
- // atlas link
230
- program
231
- .command('link [project]')
232
- .description('绑定当前项目(精确名称/子串/数字ID)。不带参数时显示当前绑定状态')
233
- .option('--json', '输出 JSON 信封')
234
- .option('--dry-run', '仅预览,不实际写入绑定')
235
- .option('--refresh-projects', '解析 project 前重新获取项目目录缓存')
236
- .action(async (project, opts) => {
237
- try {
238
- if (project === undefined) {
239
- await linkStatusCmd(opts);
240
- }
241
- else {
242
- await linkCmd(project, opts);
243
- }
244
- }
245
- catch (e) {
246
- handleError(e);
247
- }
248
- });
249
- // atlas unlink
250
- program
251
- .command('unlink')
252
- .description('清除当前项目绑定')
253
- .option('--json', '输出 JSON 信封')
254
- .option('--dry-run', '仅预览,不实际清除绑定')
255
- .action(async (opts) => {
256
- try {
257
- await unlinkCmd(opts);
258
- }
259
- catch (e) {
260
- handleError(e);
261
- }
262
- });
263
- }
264
- function registerBaselineCommands(program) {
265
- const base = program.command('baseline').description('基线(计划)人力数据');
266
- // atlas baseline month
267
- addProjectOptions(base
268
- .command('month')
269
- .description('人力基线汇总(按月显示人力投入)'))
270
- .option('--json', '输出 JSON')
271
- .option('--department <name>', '按部门名称/ID 筛选(子串,不区分大小写)')
272
- .option('--role <name>', '按角色/备注筛选(子串,不区分大小写)')
273
- .option('--area <code>', '按地域筛选(子串,不区分大小写)')
274
- .option('--manpower-type <type>', '按人力类型筛选(子串,不区分大小写)')
275
- .option('--month <yyyymm>', '查询月份(YYYY-MM,与 --from/--to 互斥)')
276
- .option('--from <yyyymm>', '起始月份(YYYY-MM,包含)')
277
- .option('--to <yyyymm>', '结束月份(YYYY-MM,包含)')
278
- .option('--all-months', '显示所有月份(默认:只显示有人力的月份)')
279
- .action(async (opts) => {
280
- try {
281
- await baselineMonthCmd(opts);
282
- }
283
- catch (e) {
284
- handleError(e);
285
- }
286
- });
287
- // atlas baseline summary
288
- addProjectOptions(base
289
- .command('summary')
290
- .description('按月/部门/角色汇总基线人力投入'))
291
- .option('--by <axis>', 'month | department | role', 'month')
292
- .option('--department <name>', '按部门名称/ID 筛选(子串,不区分大小写)')
293
- .option('--role <name>', '按角色/备注筛选(子串,不区分大小写)')
294
- .option('--area <code>', '按地域筛选(子串,不区分大小写)')
295
- .option('--manpower-type <type>', '按人力类型筛选(子串,不区分大小写)')
296
- .option('--from <yyyymm>', '起始月份(YYYY-MM,包含)')
297
- .option('--to <yyyymm>', '结束月份(YYYY-MM,包含)')
298
- .option('--json', '输出 JSON')
299
- .action(async (opts) => {
300
- try {
301
- await baselineSummaryCmd(opts);
302
- }
303
- catch (e) {
304
- handleError(e);
305
- }
306
- });
307
- // atlas baseline export
308
- addProjectOptions(base
309
- .command('export')
310
- .description('导出基线条目到 CSV/JSON'))
311
- .requiredOption('--format <fmt>', 'csv | json')
312
- .requiredOption('--out <path>', '输出文件路径')
313
- .option('--from <yyyymm>', '起始月份(YYYY-MM,包含)')
314
- .option('--to <yyyymm>', '结束月份(YYYY-MM,包含)')
315
- .option('--department <name>', '按部门名称/ID 筛选(子串,不区分大小写)')
316
- .option('--role <name>', '按角色/备注筛选(子串,不区分大小写)')
317
- .option('--since <iso>', '仅导出指定时间后修改的条目(ISO 时间戳)')
318
- .option('--json', '输出 JSON 信封(结果摘要)')
319
- .action(async (opts) => {
320
- try {
321
- if (!['csv', 'json'].includes(opts.format)) {
322
- throw new ConfigError(`--format must be csv|json, got "${opts.format}"`);
323
- }
324
- await baselineExportCmd(opts);
325
- }
326
- catch (e) {
327
- handleError(e);
328
- }
329
- });
330
- }
331
- function registerActualCommands(program) {
332
- const base = program.command('actual').description('实际人力数据');
333
- // atlas actual show <staffId>
334
- addProjectOptions(base
335
- .command('show <staffId>')
336
- .description('查看单个人员的实际工时明细'))
337
- .option('--month <yyyymm>', '查询月份(YYYY-MM,默认当前月)')
338
- .option('--status <status>', '筛选审批状态: approved | pending | all', 'approved')
339
- .option('--json', '输出 JSON 信封')
340
- .action(async (staffId, opts) => {
341
- try {
342
- await actualShowCmd(staffId, opts);
343
- }
344
- catch (e) {
345
- handleError(e);
346
- }
347
- });
348
- // atlas actual month
349
- addProjectOptions(base
350
- .command('month')
351
- .description('实际工时明细(人员×周透视表)。无参数时默认查当前自然年'))
352
- .option('--month <yyyymm>', '查询月份(YYYY-MM,与 --from/--to 互斥)')
353
- .option('--from <yyyymm>', '起始月份(YYYY-MM,包含,与 --month 互斥)')
354
- .option('--to <yyyymm>', '结束月份(YYYY-MM,包含,与 --month 互斥)')
355
- .option('--status <status>', '筛选审批状态: approved | pending | all', 'approved')
356
- .option('--department <name>', '按团队负责人/部门筛选(子串,不区分大小写)')
357
- .option('--role <name>', '按角色/备注筛选(子串,不区分大小写)')
358
- .option('--staff-name <name>', '按姓名/工号筛选(子串,不区分大小写)')
359
- .option('--json', '输出 JSON 信封')
360
- .action(async (opts) => {
361
- try {
362
- await actualMonthCmd(opts);
363
- }
364
- catch (e) {
365
- handleError(e);
366
- }
367
- });
368
- // atlas actual summary
369
- addProjectOptions(base
370
- .command('summary')
371
- .description('按月/部门/角色汇总实际工时'))
372
- .option('--by <axis>', 'month | department | role', 'month')
373
- .option('--month <yyyymm>', '查询月份')
374
- .option('--status <status>', 'approved | pending | all', 'approved')
375
- .option('--department <name>', '按部门筛选')
376
- .option('--role <name>', '按角色筛选')
377
- .option('--from <yyyymm>', '起始月份')
378
- .option('--to <yyyymm>', '结束月份')
379
- .option('--json', '输出 JSON 信封')
380
- .action(async (opts) => {
381
- try {
382
- await actualSummaryCmd(opts);
383
- }
384
- catch (e) {
385
- handleError(e);
386
- }
387
- });
388
- // atlas actual export
389
- addProjectOptions(base
390
- .command('export')
391
- .description('导出实际工时数据(CSV/JSON)'))
392
- .requiredOption('--format <fmt>', 'csv | json')
393
- .requiredOption('--out <path>', '输出文件路径')
394
- .option('--by <axis>', 'month | department | role', 'month')
395
- .option('--status <status>', 'approved | pending | all', 'approved')
396
- .option('--department <name>', '按部门筛选')
397
- .option('--role <name>', '按角色筛选')
398
- .option('--from <yyyymm>', '起始月份')
399
- .option('--to <yyyymm>', '结束月份')
400
- .option('--json', '输出 JSON 信封')
401
- .action(async (opts) => {
402
- try {
403
- await actualExportCmd(opts);
404
- }
405
- catch (e) {
406
- handleError(e);
407
- }
408
- });
409
- }
410
- function registerCompareCommands(program) {
411
- addProjectOptions(program
412
- .command('compare')
413
- .description('Compare baseline (计划) vs actual (实际) manpower'))
414
- .option('--by <axis>', 'month | department | role', 'month')
415
- .option('--from <yyyymm>', '起始月份(YYYY-MM,包含)')
416
- .option('--to <yyyymm>', '结束月份(YYYY-MM,包含)')
417
- .option('--month <yyyymm>', '查询月份(YYYY-MM,优先级高于 from/to 用于实际数据 API)')
418
- .option('--department <name>', '按部门名称/ID 筛选(子串,不区分大小写)')
419
- .option('--role <name>', '按角色/备注筛选(子串,不区分大小写)')
420
- .option('--status <status>', '筛选审批状态: approved | pending | all', 'approved')
421
- .option('--threshold <n>', '差异绝对值阈值(人月),低于此值不标记', '0')
422
- .option('--flag-overrun', '用 ⚠️ 标记实际 > 基线的情况')
423
- .option('--page <n>', '页码(从 1 开始)')
424
- .option('--page-size <n>', '每页条目数(大于 0 时启用分页)')
425
- .option('--json', '输出 JSON 信封')
426
- .action(async (opts) => {
427
- try {
428
- await compareCmd(opts);
429
- }
430
- catch (e) {
431
- handleError(e);
432
- }
433
- });
434
- }
435
- function registerUtilityCommands(program) {
436
- // daemon
437
- program
438
- .command('daemon')
439
- .description('启动本地守护进程(沙盒环境使用,保持浏览器会话)')
440
- .option('--port <n>', '监听端口(默认 8765,也可用 ATLAS_DAEMON_PORT 环境变量)')
441
- .option('--host <host>', '监听地址(默认 127.0.0.1;非 loopback 需配 --allow-ip 或 --insecure)')
442
- .option('--allow-ip <cidr>', 'IP 白名单(CIDR 或单 IP,可多次传)', (v, p) => [...p, v], [])
443
- .option('--tls-cert <path>', 'TLS 证书文件路径(需与 --tls-key 同时指定)')
444
- .option('--tls-key <path>', 'TLS 私钥文件路径')
445
- .option('--insecure', '显式允许明文监听非 loopback 接口(仅本机开发)')
446
- .option('--json', '输出 JSON 信封')
447
- .action(async (opts) => {
448
- try {
449
- await daemonCmd(opts);
450
- }
451
- catch (e) {
452
- handleError(e);
453
- }
454
- });
455
- // schema
456
- const schema = program.command('schema').description('CLI 自省 / 字段字典导出');
457
- schema
458
- .command('commands')
459
- .description('列出所有命令的参数 schema 及输出 schema 标注')
460
- .option('--json', '输出 JSON 信封')
461
- .option('--describe', '输出完整命令 schema 含 outputSchema(agent 自省用)')
462
- .action((opts) => {
463
- try {
464
- schemaCommandsCmd(program, opts);
465
- }
466
- catch (e) {
467
- handleError(e);
468
- }
469
- });
470
- // exec
471
- program
472
- .command('exec')
473
- .description('按 plan-file 顺序执行多条命令(agent 批处理用)')
474
- .requiredOption('--plan-file <path>', 'JSON 计划文件路径')
475
- .option('--json', '输出 JSON 信封')
476
- .action(async (opts) => {
477
- try {
478
- await execCmd(opts);
479
- }
480
- catch (e) {
481
- handleError(e);
482
- }
483
- });
484
- // update
485
- program
486
- .command('update')
487
- .description('检查并自动升级到最新版本(设置 ATLAS_DISABLE_UPDATE=1 禁用)')
488
- .option('--json', '输出 JSON 信封')
489
- .action(async (opts) => {
490
- try {
491
- await updateCmd(opts);
492
- }
493
- catch (e) {
494
- handleError(e);
495
- }
496
- });
497
- // suggest
498
- program
499
- .command('suggest <query...>')
500
- .description('将自然语言查询翻译为候选 atlas 命令(纯规则,不调 LLM)')
501
- .option('--json', '输出 JSON 信封')
502
- .action((tokens, opts) => {
503
- try {
504
- suggestCmd(tokens.join(' '), opts);
505
- }
506
- catch (e) {
507
- handleError(e);
508
- }
509
- });
510
- }
511
- // Version is generated from package.json by scripts/sync-version.mjs (run as
512
- // prebuild). Inlined as a string constant so both `tsc` and bun --compile
513
- // single-file binaries can read it without runtime fs access.
514
- import { ATLAS_VERSION } from './util/version.js';
515
- export function buildProgram() {
516
- const program = new Command();
517
- program
518
- .name('atlas')
519
- .description('Atlas CLI - 斑马云图人力基线管理工具')
520
- .version(ATLAS_VERSION, '-V, --version', '显示版本号')
521
- .option('--json', '以 JSON 信封输出(也可用环境变量 ATLAS_OUTPUT=json)')
522
- .option('--quiet', '静默模式:抑制非信封输出(设置 ATLAS_QUIET=1 也可)')
523
- .option('--describe', '不执行命令,仅输出该命令的参数 schema(agent 自省用)')
524
- .addHelpText('after', `
525
- 退出码:
526
- 0 成功
527
- 1 通用错误 / exec 中某 step 失败
528
- 2 会话过期(需重新登录)
529
- 3 API 返回错误(BanmaApiError)
530
- 4 项目匹配歧义(AmbiguousProject)
531
- 5 项目未找到(ProjectNotFound)
532
- 6 API 限流(RateLimited)
533
- 7 网络错误(NetworkError)
534
- 8 版本更新异常(UpdateError)
535
- 64 配置错误(ConfigError)
536
- 65 输出超限(OutputTooLargeError)
537
- `)
538
- .showHelpAfterError()
539
- .hook('preAction', (thisCommand, actionCommand) => {
540
- const opts = thisCommand.opts();
541
- if (opts.json === true && process.env.ATLAS_OUTPUT === undefined) {
542
- process.env.ATLAS_OUTPUT = 'json';
543
- }
544
- if (opts.quiet === true) {
545
- process.env.ATLAS_QUIET = '1';
546
- }
547
- if (opts.describe === true) {
548
- emitDescribe(actionCommand);
549
- process.exit(0);
550
- }
551
- });
552
- registerAuthCommands(program);
553
- registerProjectCommands(program);
554
- registerBaselineCommands(program);
555
- registerActualCommands(program);
556
- registerCompareCommands(program);
557
- registerUtilityCommands(program);
558
- return program;
559
- }
560
- // 注意:auto-run 入口已移至 bin/atlas.ts
561
- // 此模块仅 export buildProgram / handleError / emitDescribe