@dreamor/atlas-cli 0.7.15 → 0.7.16
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/dist/adapters/atlas/cli.js +2 -8
- package/dist/adapters/atlas/commands/project/index.js +30 -0
- package/dist/adapters/atlas/http/client.js +25 -0
- package/dist/adapters/atlas/util/errors.js +0 -6
- package/dist/adapters/atlas/util/output.js +1 -4
- package/dist/adapters/atlas/util/version.js +1 -1
- package/package.json +3 -2
|
@@ -16,7 +16,7 @@ import { schemaCommandsCmd } from './commands/schema.js';
|
|
|
16
16
|
import { execCmd } from './commands/exec.js';
|
|
17
17
|
import { suggestCmd } from './commands/suggest.js';
|
|
18
18
|
import { updateCmd } from './commands/update.js';
|
|
19
|
-
import { BanmaApiError, ConfigError,
|
|
19
|
+
import { BanmaApiError, ConfigError, OutputTooLargeError, SessionExpiredError, isAtlasError, } from './util/errors.js';
|
|
20
20
|
import { isJsonMode, printError } from './util/output.js';
|
|
21
21
|
import { getOutputSchema } from './commands/_output_schema.js';
|
|
22
22
|
export function handleError(err) {
|
|
@@ -36,10 +36,6 @@ export function handleError(err) {
|
|
|
36
36
|
console.error(`Banma API error [${err.errCode}] ${err.errorMsg}`);
|
|
37
37
|
process.exit(3);
|
|
38
38
|
}
|
|
39
|
-
if (err instanceof NotImplementedError) {
|
|
40
|
-
console.error(err.message);
|
|
41
|
-
process.exit(64);
|
|
42
|
-
}
|
|
43
39
|
if (err instanceof OutputTooLargeError) {
|
|
44
40
|
const debug = process.env.DEBUG === '1';
|
|
45
41
|
console.error(debug ? err.stack ?? err.message : err.message);
|
|
@@ -56,8 +52,6 @@ export function exitCodeFor(err) {
|
|
|
56
52
|
return 3;
|
|
57
53
|
if (err instanceof OutputTooLargeError)
|
|
58
54
|
return 65;
|
|
59
|
-
if (err instanceof NotImplementedError)
|
|
60
|
-
return 64;
|
|
61
55
|
if (isAtlasError(err)) {
|
|
62
56
|
switch (err.code) {
|
|
63
57
|
case 'AMBIGUOUS_PROJECT': return 4;
|
|
@@ -476,7 +470,7 @@ export function buildProgram() {
|
|
|
476
470
|
6 API 限流(RateLimited)
|
|
477
471
|
7 网络错误(NetworkError)
|
|
478
472
|
8 版本更新异常(UpdateError)
|
|
479
|
-
64
|
|
473
|
+
64 配置错误(ConfigError)
|
|
480
474
|
65 输出超限(OutputTooLargeError)
|
|
481
475
|
`)
|
|
482
476
|
.showHelpAfterError()
|
|
@@ -71,6 +71,36 @@ export async function findCmd(kind, query, opts) {
|
|
|
71
71
|
results = projects
|
|
72
72
|
.filter((p) => getProjectId(p).includes(query) || getProjectName(p).includes(query))
|
|
73
73
|
.map((p) => ({ id: getProjectId(p), name: getProjectName(p), kind: 'project' }));
|
|
74
|
+
// B4 兜底:权限列表搜不到时尝试按 ID 或名称直接查项目
|
|
75
|
+
// 部分项目(如 status=2)不会出现在 selectHasPermisValidProject 中,
|
|
76
|
+
// 但 queryProjById / queryProjList 可返回完整信息
|
|
77
|
+
if (results.length === 0) {
|
|
78
|
+
// 兜底一:按 ID 查项目详情
|
|
79
|
+
try {
|
|
80
|
+
const detail = await client.get('/yuntu-service/projApi/queryProjById.json', { projId: query });
|
|
81
|
+
if (detail?.projInfo?.id && detail?.projInfo?.projName) {
|
|
82
|
+
results = [{ id: String(detail.projInfo.id), name: detail.projInfo.projName, kind: 'project' }];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// 静默忽略
|
|
87
|
+
}
|
|
88
|
+
// 兜底二:按名称模糊搜索项目列表
|
|
89
|
+
if (results.length === 0) {
|
|
90
|
+
try {
|
|
91
|
+
const list = await client.get('/yuntu-service/projApi/queryProjList.json', { projName: query, staffId: '' });
|
|
92
|
+
if (Array.isArray(list)) {
|
|
93
|
+
results = list
|
|
94
|
+
.filter((p) => p.id && p.projName)
|
|
95
|
+
.slice(0, parseInt(opts.limit ?? '20', 10))
|
|
96
|
+
.map((p) => ({ id: String(p.id), name: p.projName, kind: 'project' }));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// 静默忽略
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
74
104
|
}
|
|
75
105
|
else if (kind === 'department') {
|
|
76
106
|
const data = await client.post('/yuntu-service/department/tree/select.json', {});
|
|
@@ -63,6 +63,31 @@ export class HttpClient {
|
|
|
63
63
|
}
|
|
64
64
|
return headers;
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* GET 请求。
|
|
68
|
+
*
|
|
69
|
+
* query 参数以键值对形式传入,自动拼接到 URL 查询字符串。
|
|
70
|
+
* 可传可选 schema(ZodSchema),在 API 返回后对 json.data 做运行时校验。
|
|
71
|
+
*/
|
|
72
|
+
async get(path, query, schema) {
|
|
73
|
+
// A4: 校验 path 必须以 / 开头,防止 http://evil.example/x 绕过 baseUrl
|
|
74
|
+
if (!path.startsWith('/'))
|
|
75
|
+
throw new AtlasError('path must be relative (start with /)', 'CONFIG_ERROR');
|
|
76
|
+
const url = new URL(path, this.baseUrl + '/');
|
|
77
|
+
if (query) {
|
|
78
|
+
Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));
|
|
79
|
+
}
|
|
80
|
+
if (url.origin !== this.baseOrigin)
|
|
81
|
+
throw new AtlasError('origin mismatch — possible SSRF', 'CONFIG_ERROR');
|
|
82
|
+
const headers = await this.buildHeaders();
|
|
83
|
+
const response = await request(url.toString(), {
|
|
84
|
+
method: 'GET',
|
|
85
|
+
headers,
|
|
86
|
+
headersTimeout: this.timeout,
|
|
87
|
+
bodyTimeout: this.timeout,
|
|
88
|
+
});
|
|
89
|
+
return this.parseResponse(response, schema);
|
|
90
|
+
}
|
|
66
91
|
/**
|
|
67
92
|
* POST 请求。
|
|
68
93
|
*
|
|
@@ -23,12 +23,6 @@ export class SessionExpiredError extends Error {
|
|
|
23
23
|
this.name = 'SessionExpiredError';
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
export class NotImplementedError extends Error {
|
|
27
|
-
constructor(message = '该功能尚未实现') {
|
|
28
|
-
super(message);
|
|
29
|
-
this.name = 'NotImplementedError';
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
26
|
export class OutputTooLargeError extends Error {
|
|
33
27
|
bytes;
|
|
34
28
|
limit;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BanmaApiError, AtlasError, ConfigError,
|
|
1
|
+
import { BanmaApiError, AtlasError, ConfigError, OutputTooLargeError, SessionExpiredError } from './errors.js';
|
|
2
2
|
export function isJsonMode() {
|
|
3
3
|
return process.env.ATLAS_OUTPUT === 'json';
|
|
4
4
|
}
|
|
@@ -44,9 +44,6 @@ export function printError(err, opts) {
|
|
|
44
44
|
else if (err instanceof ConfigError) {
|
|
45
45
|
console.error(`Config error: ${err.message}`);
|
|
46
46
|
}
|
|
47
|
-
else if (err instanceof NotImplementedError) {
|
|
48
|
-
console.error(err.message);
|
|
49
|
-
}
|
|
50
47
|
else if (err instanceof OutputTooLargeError) {
|
|
51
48
|
console.error(err.message);
|
|
52
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const ATLAS_VERSION = '0.7.
|
|
1
|
+
export const ATLAS_VERSION = '0.7.16';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dreamor/atlas-cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.16",
|
|
4
4
|
"description": "Atlas CLI - 斑马云图人力基线管理工具",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
"test": "vitest run",
|
|
32
32
|
"test:watch": "vitest",
|
|
33
33
|
"verify": "node ./dist/adapters/atlas/cli.js --help",
|
|
34
|
-
"auth:login": "node --import tsx ./adapters/atlas/cli.ts auth login"
|
|
34
|
+
"auth:login": "node --import tsx ./adapters/atlas/cli.ts auth login",
|
|
35
|
+
"generate-skill-docs": "node scripts/generate-skill-docs.mjs"
|
|
35
36
|
},
|
|
36
37
|
"dependencies": {
|
|
37
38
|
"commander": "^14.0.3",
|