@ty_krystal/sei-ai 0.1.8 → 0.1.13
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 +34 -65
- package/dist/commands/api-docs.d.ts +1 -2
- package/dist/commands/api-docs.js +1 -1
- package/dist/commands/call.d.ts +1 -2
- package/dist/commands/call.js +1 -1
- package/dist/commands/dict/add-category.d.ts +1 -2
- package/dist/commands/dict/add-category.js +1 -1
- package/dist/commands/dict/add-item.d.ts +1 -2
- package/dist/commands/dict/add-item.js +1 -1
- package/dist/commands/dict/list.d.ts +1 -2
- package/dist/commands/dict/list.js +1 -1
- package/dist/commands/init/base-data.d.ts +1 -2
- package/dist/commands/init/base-data.js +1 -1
- package/dist/commands/query-sql.d.ts +1 -2
- package/dist/commands/query-sql.js +1 -1
- package/dist/commands/query.d.ts +1 -2
- package/dist/commands/query.js +1 -1
- package/dist/commands/relogin.d.ts +1 -2
- package/dist/commands/relogin.js +1 -1
- package/dist/commands/save.d.ts +1 -2
- package/dist/commands/save.js +1 -1
- package/dist/commands.d.ts +24 -0
- package/dist/commands.js +23 -0
- package/dist/core/cli-actions.d.ts +94 -0
- package/dist/core/cli-actions.js +155 -0
- package/dist/core/cli-helpers.d.ts +39 -0
- package/dist/core/cli-helpers.js +246 -0
- package/dist/core/command-base/context.d.ts +6 -0
- package/dist/core/command-base/context.js +10 -0
- package/dist/core/command-base/output.d.ts +2 -0
- package/dist/core/command-base/output.js +6 -0
- package/dist/core/command-base/payload.d.ts +7 -0
- package/dist/core/command-base/payload.js +33 -0
- package/dist/core/command-base/sei-command.d.ts +40 -0
- package/dist/core/command-base/sei-command.js +85 -0
- package/dist/core/config.d.ts +3 -0
- package/dist/core/config.js +80 -0
- package/dist/core/constants.d.ts +35 -0
- package/dist/core/constants.js +48 -0
- package/dist/core/env.d.ts +1 -0
- package/dist/core/env.js +55 -0
- package/dist/core/errors.d.ts +10 -0
- package/dist/core/errors.js +55 -0
- package/dist/core/index.d.ts +14 -0
- package/dist/core/index.js +14 -0
- package/dist/core/logger.d.ts +2 -0
- package/dist/core/logger.js +71 -0
- package/dist/core/openapi.d.ts +2 -0
- package/dist/core/openapi.js +261 -0
- package/dist/core/sei-client.d.ts +25 -0
- package/dist/core/sei-client.js +524 -0
- package/dist/core/types.d.ts +135 -0
- package/dist/core/types.js +1 -0
- package/dist/core/utils.d.ts +12 -0
- package/dist/core/utils.js +53 -0
- package/dist/hooks/command_not_found.d.ts +3 -0
- package/dist/hooks/command_not_found.js +36 -0
- package/oclif.manifest.json +361 -423
- package/package.json +18 -8
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export declare function runApiDocs(options: {
|
|
2
|
+
client: {
|
|
3
|
+
readApiDocs(): Promise<unknown>;
|
|
4
|
+
};
|
|
5
|
+
keyword?: string;
|
|
6
|
+
format?: 'json' | 'markdown';
|
|
7
|
+
outputPath?: string;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
export declare function runRelogin(options: {
|
|
10
|
+
client: {
|
|
11
|
+
relogin(): Promise<string>;
|
|
12
|
+
};
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
export declare function runCall(options: {
|
|
15
|
+
client: {
|
|
16
|
+
call(method: string, path: string, payload?: unknown, requestOptions?: Record<string, unknown>): Promise<unknown>;
|
|
17
|
+
};
|
|
18
|
+
method: string;
|
|
19
|
+
path: string;
|
|
20
|
+
payload?: unknown;
|
|
21
|
+
allowFailure?: boolean;
|
|
22
|
+
allowEmpty?: boolean;
|
|
23
|
+
skipAuth?: boolean;
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
export declare function runQuery(options: {
|
|
26
|
+
client: {
|
|
27
|
+
query(payload: unknown, requestOptions?: Record<string, unknown>): Promise<unknown>;
|
|
28
|
+
};
|
|
29
|
+
payload: unknown;
|
|
30
|
+
allowFailure?: boolean;
|
|
31
|
+
}): Promise<void>;
|
|
32
|
+
export declare function runSave(options: {
|
|
33
|
+
client: {
|
|
34
|
+
save(payload: unknown, requestOptions?: Record<string, unknown>): Promise<unknown>;
|
|
35
|
+
};
|
|
36
|
+
payload: unknown;
|
|
37
|
+
allowFailure?: boolean;
|
|
38
|
+
}): Promise<void>;
|
|
39
|
+
export declare function runQuerySql(options: {
|
|
40
|
+
client: {
|
|
41
|
+
querySql(sql: string, page?: number, size?: number, requestOptions?: Record<string, unknown>): Promise<unknown>;
|
|
42
|
+
};
|
|
43
|
+
sql: string;
|
|
44
|
+
page?: number;
|
|
45
|
+
size?: number;
|
|
46
|
+
allowFailure?: boolean;
|
|
47
|
+
}): Promise<void>;
|
|
48
|
+
export declare function runDictList(options: {
|
|
49
|
+
client: {
|
|
50
|
+
query(payload: unknown, requestOptions?: Record<string, unknown>): Promise<unknown>;
|
|
51
|
+
};
|
|
52
|
+
typeCode?: string;
|
|
53
|
+
keyword?: string;
|
|
54
|
+
size?: number;
|
|
55
|
+
flat?: boolean;
|
|
56
|
+
allowFailure?: boolean;
|
|
57
|
+
}): Promise<void>;
|
|
58
|
+
export declare function runDictAddCategory(options: {
|
|
59
|
+
client: {
|
|
60
|
+
save(payload: unknown, requestOptions?: Record<string, unknown>): Promise<unknown>;
|
|
61
|
+
};
|
|
62
|
+
typeCode: string;
|
|
63
|
+
name: string;
|
|
64
|
+
rowOptions?: Record<string, unknown>;
|
|
65
|
+
allowFailure?: boolean;
|
|
66
|
+
}): Promise<void>;
|
|
67
|
+
export declare function runDictAddItem(options: {
|
|
68
|
+
client: {
|
|
69
|
+
save(payload: unknown, requestOptions?: Record<string, unknown>): Promise<unknown>;
|
|
70
|
+
};
|
|
71
|
+
typeCode: string;
|
|
72
|
+
code: string;
|
|
73
|
+
name: string;
|
|
74
|
+
rowOptions?: Record<string, unknown>;
|
|
75
|
+
allowFailure?: boolean;
|
|
76
|
+
}): Promise<void>;
|
|
77
|
+
export declare function runInitBaseData(options: {
|
|
78
|
+
client: {
|
|
79
|
+
executeDdlStatements(statements: string[], requestOptions?: Record<string, unknown>): Promise<unknown>;
|
|
80
|
+
call(method: string, path: string, payload?: unknown, requestOptions?: Record<string, unknown>): Promise<unknown>;
|
|
81
|
+
};
|
|
82
|
+
sqlFile?: string;
|
|
83
|
+
sysid?: string;
|
|
84
|
+
adminUid?: string;
|
|
85
|
+
adminName?: string;
|
|
86
|
+
adminRole?: string;
|
|
87
|
+
adminRoleName?: string;
|
|
88
|
+
adminPassword?: string;
|
|
89
|
+
resetAdminPassword?: boolean;
|
|
90
|
+
allowFailure?: boolean;
|
|
91
|
+
}): Promise<void>;
|
|
92
|
+
export declare function writeOutput(path: string | undefined, text: string): Promise<void>;
|
|
93
|
+
export declare function resolveBaseSeedSqlPath(path: string | undefined): string;
|
|
94
|
+
export declare function formatActionError(error: unknown): string;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { BASE_SEED_DEFAULT_ADMIN_ROLE, BASE_SEED_DEFAULT_ADMIN_UID } from './constants.js';
|
|
4
|
+
import { formatCliError, SeiMcpError } from './errors.js';
|
|
5
|
+
import { buildBaseSeedSqlVars, buildDictCategoryRow, buildDictItemRow, buildDictQueryPayload, buildDictSavePayload, buildDictTree, removeSqlCommentLines, renderBaseSeedSql, splitSqlStatements, } from './cli-helpers.js';
|
|
6
|
+
import { printJson } from './command-base/output.js';
|
|
7
|
+
import { buildOpenApiDocSummary, renderOpenApiMarkdown } from './openapi.js';
|
|
8
|
+
export async function runApiDocs(options) {
|
|
9
|
+
const raw = await options.client.readApiDocs();
|
|
10
|
+
const summary = buildOpenApiDocSummary(raw, options.keyword);
|
|
11
|
+
const output = options.format === 'json' ? `${JSON.stringify(summary, null, 2)}\n` : renderOpenApiMarkdown(summary);
|
|
12
|
+
await writeOutput(options.outputPath, output);
|
|
13
|
+
}
|
|
14
|
+
export async function runRelogin(options) {
|
|
15
|
+
const token = await options.client.relogin();
|
|
16
|
+
printJson({
|
|
17
|
+
success: true,
|
|
18
|
+
code: 1,
|
|
19
|
+
message: '重新登录成功',
|
|
20
|
+
data: { token },
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export async function runCall(options) {
|
|
24
|
+
const response = await options.client.call(options.method, options.path, options.payload, {
|
|
25
|
+
allowFailure: options.allowFailure,
|
|
26
|
+
allowEmpty: options.allowEmpty,
|
|
27
|
+
skipAuth: options.skipAuth,
|
|
28
|
+
});
|
|
29
|
+
printJson(response);
|
|
30
|
+
}
|
|
31
|
+
export async function runQuery(options) {
|
|
32
|
+
const response = await options.client.query(options.payload, {
|
|
33
|
+
allowFailure: options.allowFailure,
|
|
34
|
+
});
|
|
35
|
+
printJson(response);
|
|
36
|
+
}
|
|
37
|
+
export async function runSave(options) {
|
|
38
|
+
const response = await options.client.save(options.payload, {
|
|
39
|
+
allowFailure: options.allowFailure,
|
|
40
|
+
});
|
|
41
|
+
printJson(response);
|
|
42
|
+
}
|
|
43
|
+
export async function runQuerySql(options) {
|
|
44
|
+
const response = await options.client.querySql(options.sql, options.page, options.size, {
|
|
45
|
+
allowFailure: options.allowFailure,
|
|
46
|
+
});
|
|
47
|
+
printJson(response);
|
|
48
|
+
}
|
|
49
|
+
export async function runDictList(options) {
|
|
50
|
+
const payload = buildDictQueryPayload(options.typeCode, options.keyword, options.size ?? 1000);
|
|
51
|
+
const response = await options.client.query(payload, {
|
|
52
|
+
allowFailure: options.allowFailure,
|
|
53
|
+
});
|
|
54
|
+
if (!options.flat && isObject(response) && isObject(response.data) && Array.isArray(response.data.rows)) {
|
|
55
|
+
response.data.tree = buildDictTree(response.data.rows);
|
|
56
|
+
}
|
|
57
|
+
printJson(response);
|
|
58
|
+
}
|
|
59
|
+
export async function runDictAddCategory(options) {
|
|
60
|
+
const payload = buildDictSavePayload(buildDictCategoryRow({
|
|
61
|
+
body: stringOrUndefined(options.rowOptions?.body),
|
|
62
|
+
code: stringOrUndefined(options.rowOptions?.code),
|
|
63
|
+
ctype: stringOrUndefined(options.rowOptions?.ctype),
|
|
64
|
+
dictFlag: numberOrUndefined(options.rowOptions?.dictFlag),
|
|
65
|
+
ename: stringOrUndefined(options.rowOptions?.ename),
|
|
66
|
+
memo: stringOrUndefined(options.rowOptions?.memo),
|
|
67
|
+
name: options.name,
|
|
68
|
+
sort: numberOrUndefined(options.rowOptions?.sort),
|
|
69
|
+
sysid: stringOrUndefined(options.rowOptions?.sysid),
|
|
70
|
+
typeCode: options.typeCode,
|
|
71
|
+
uuid: stringOrUndefined(options.rowOptions?.uuid),
|
|
72
|
+
}));
|
|
73
|
+
const response = await options.client.save(payload, {
|
|
74
|
+
allowFailure: options.allowFailure,
|
|
75
|
+
});
|
|
76
|
+
printJson(response);
|
|
77
|
+
}
|
|
78
|
+
export async function runDictAddItem(options) {
|
|
79
|
+
const payload = buildDictSavePayload(buildDictItemRow({
|
|
80
|
+
body: stringOrUndefined(options.rowOptions?.body),
|
|
81
|
+
code: options.code,
|
|
82
|
+
ctype: stringOrUndefined(options.rowOptions?.ctype),
|
|
83
|
+
dictFlag: numberOrUndefined(options.rowOptions?.dictFlag),
|
|
84
|
+
ename: stringOrUndefined(options.rowOptions?.ename),
|
|
85
|
+
memo: stringOrUndefined(options.rowOptions?.memo),
|
|
86
|
+
name: options.name,
|
|
87
|
+
parent: stringOrUndefined(options.rowOptions?.parent),
|
|
88
|
+
sort: numberOrUndefined(options.rowOptions?.sort),
|
|
89
|
+
sysid: stringOrUndefined(options.rowOptions?.sysid),
|
|
90
|
+
typeCode: options.typeCode,
|
|
91
|
+
uuid: stringOrUndefined(options.rowOptions?.uuid),
|
|
92
|
+
}));
|
|
93
|
+
const response = await options.client.save(payload, {
|
|
94
|
+
allowFailure: options.allowFailure,
|
|
95
|
+
});
|
|
96
|
+
printJson(response);
|
|
97
|
+
}
|
|
98
|
+
export async function runInitBaseData(options) {
|
|
99
|
+
const sqlFile = resolveBaseSeedSqlPath(options.sqlFile);
|
|
100
|
+
const template = await readFile(sqlFile, 'utf8');
|
|
101
|
+
const sql = renderBaseSeedSql(template, buildBaseSeedSqlVars({
|
|
102
|
+
adminName: options.adminName,
|
|
103
|
+
adminPassword: options.adminPassword,
|
|
104
|
+
adminRole: options.adminRole,
|
|
105
|
+
adminRoleName: options.adminRoleName,
|
|
106
|
+
adminUid: options.adminUid,
|
|
107
|
+
resetAdminPassword: options.resetAdminPassword,
|
|
108
|
+
sysid: options.sysid,
|
|
109
|
+
}));
|
|
110
|
+
const statements = splitSqlStatements(removeSqlCommentLines(sql));
|
|
111
|
+
if (statements.length === 0) {
|
|
112
|
+
throw new SeiMcpError('初始化 SQL 文件没有可执行语句', 'INVALID_PARAMS');
|
|
113
|
+
}
|
|
114
|
+
const executed = await options.client.executeDdlStatements(statements, {
|
|
115
|
+
allowFailure: options.allowFailure,
|
|
116
|
+
});
|
|
117
|
+
await options.client.call('POST', '/api/sei/data/removeAllCache', {}, { allowFailure: false }).catch(() => undefined);
|
|
118
|
+
printJson({
|
|
119
|
+
success: true,
|
|
120
|
+
code: 1,
|
|
121
|
+
message: '基础源数据初始化完成',
|
|
122
|
+
data: {
|
|
123
|
+
executed: Array.isArray(executed) ? executed.length : 0,
|
|
124
|
+
sqlFile,
|
|
125
|
+
admin: options.adminUid ?? BASE_SEED_DEFAULT_ADMIN_UID,
|
|
126
|
+
role: options.adminRole ?? BASE_SEED_DEFAULT_ADMIN_ROLE,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
export async function writeOutput(path, text) {
|
|
131
|
+
if (!path) {
|
|
132
|
+
process.stdout.write(text);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
await writeFile(path, text, 'utf8');
|
|
136
|
+
process.stdout.write(`已写入:${path}\n`);
|
|
137
|
+
}
|
|
138
|
+
export function resolveBaseSeedSqlPath(path) {
|
|
139
|
+
if (path) {
|
|
140
|
+
return resolve(path);
|
|
141
|
+
}
|
|
142
|
+
return resolve(process.cwd(), '.codex/skills/sei-ai/scripts/init-base-data.sql');
|
|
143
|
+
}
|
|
144
|
+
export function formatActionError(error) {
|
|
145
|
+
return formatCliError(error);
|
|
146
|
+
}
|
|
147
|
+
function stringOrUndefined(value) {
|
|
148
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
149
|
+
}
|
|
150
|
+
function numberOrUndefined(value) {
|
|
151
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
152
|
+
}
|
|
153
|
+
function isObject(value) {
|
|
154
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
155
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface DictRowInput {
|
|
2
|
+
body?: string;
|
|
3
|
+
ctype?: string;
|
|
4
|
+
dictFlag?: number;
|
|
5
|
+
ename?: string;
|
|
6
|
+
memo?: string;
|
|
7
|
+
sort?: number;
|
|
8
|
+
sysid?: string;
|
|
9
|
+
uuid?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface DictCategoryInput extends DictRowInput {
|
|
12
|
+
code?: string;
|
|
13
|
+
name: string;
|
|
14
|
+
typeCode: string;
|
|
15
|
+
}
|
|
16
|
+
export interface DictItemInput extends DictRowInput {
|
|
17
|
+
code: string;
|
|
18
|
+
name: string;
|
|
19
|
+
parent?: string;
|
|
20
|
+
typeCode: string;
|
|
21
|
+
}
|
|
22
|
+
export interface InitBaseDataInput {
|
|
23
|
+
adminName?: string;
|
|
24
|
+
adminPassword?: string;
|
|
25
|
+
adminRole?: string;
|
|
26
|
+
adminRoleName?: string;
|
|
27
|
+
adminUid?: string;
|
|
28
|
+
resetAdminPassword?: boolean;
|
|
29
|
+
sysid?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function buildDictQueryPayload(typeCode?: string, keyword?: string, size?: number): Record<string, unknown>;
|
|
32
|
+
export declare function buildDictSavePayload(row: Record<string, unknown>): Record<string, unknown>;
|
|
33
|
+
export declare function buildDictCategoryRow(input: DictCategoryInput): Record<string, unknown>;
|
|
34
|
+
export declare function buildDictItemRow(input: DictItemInput): Record<string, unknown>;
|
|
35
|
+
export declare function buildDictTree(rows: unknown): Array<Record<string, unknown>>;
|
|
36
|
+
export declare function buildBaseSeedSqlVars(input: InitBaseDataInput): Record<string, string>;
|
|
37
|
+
export declare function renderBaseSeedSql(template: string, values: Record<string, string>): string;
|
|
38
|
+
export declare function removeSqlCommentLines(sql: string): string;
|
|
39
|
+
export declare function splitSqlStatements(sql: string): string[];
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { BASE_SEED_DEFAULT_ADMIN_PASSWORD, BASE_SEED_DEFAULT_ADMIN_ROLE, BASE_SEED_DEFAULT_ADMIN_UID, BASE_SEED_DEFAULT_SYSID, DICT_DEFAULT_SYSID, DICT_FIELDS, DICT_MODULE, } from './constants.js';
|
|
3
|
+
import { SeiMcpError } from './errors.js';
|
|
4
|
+
export function buildDictQueryPayload(typeCode, keyword, size = 1000) {
|
|
5
|
+
return {
|
|
6
|
+
head: {
|
|
7
|
+
module: DICT_MODULE,
|
|
8
|
+
},
|
|
9
|
+
option: {
|
|
10
|
+
keyField: true,
|
|
11
|
+
privilege: true,
|
|
12
|
+
fields: DICT_FIELDS.join(','),
|
|
13
|
+
filter: buildDictQueryFilter(typeCode, keyword),
|
|
14
|
+
order: '_SORT ASC,_CODE ASC',
|
|
15
|
+
page: 1,
|
|
16
|
+
size,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function buildDictSavePayload(row) {
|
|
21
|
+
return {
|
|
22
|
+
head: {
|
|
23
|
+
module: DICT_MODULE,
|
|
24
|
+
},
|
|
25
|
+
data: [
|
|
26
|
+
{
|
|
27
|
+
action: 'add',
|
|
28
|
+
option: {
|
|
29
|
+
keyVal: true,
|
|
30
|
+
},
|
|
31
|
+
rows: [
|
|
32
|
+
{
|
|
33
|
+
row,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function buildDictCategoryRow(input) {
|
|
41
|
+
const typeCode = requiredText(input.typeCode, '字典类别');
|
|
42
|
+
const name = requiredText(input.name, '字典名称');
|
|
43
|
+
const uuid = requiredText(input.uuid || typeCode, '字典编号');
|
|
44
|
+
const code = requiredText(input.code || typeCode, '字典代码');
|
|
45
|
+
return {
|
|
46
|
+
_UUID: uuid,
|
|
47
|
+
_PID: '',
|
|
48
|
+
_SYSID: requiredText(input.sysid || DICT_DEFAULT_SYSID, '所属系统'),
|
|
49
|
+
_TYPE: typeCode,
|
|
50
|
+
_CTYPE: normalizeText(input.ctype),
|
|
51
|
+
_CODE: code,
|
|
52
|
+
_NAME: name,
|
|
53
|
+
_ENAME: normalizeText(input.ename),
|
|
54
|
+
_DICT: normalizeDictFlag(input.dictFlag),
|
|
55
|
+
_SORT: normalizeSort(input.sort),
|
|
56
|
+
_BODY: normalizeText(input.body),
|
|
57
|
+
_MEMO: normalizeText(input.memo),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function buildDictItemRow(input) {
|
|
61
|
+
const typeCode = requiredText(input.typeCode, '字典类别');
|
|
62
|
+
const code = requiredText(input.code, '字典代码');
|
|
63
|
+
const name = requiredText(input.name, '字典名称');
|
|
64
|
+
const parent = requiredText(input.parent || typeCode, '父级编号');
|
|
65
|
+
const uuid = requiredText(input.uuid || `${parent}_${code}`, '字典编号');
|
|
66
|
+
return {
|
|
67
|
+
_UUID: uuid,
|
|
68
|
+
_PID: parent,
|
|
69
|
+
_SYSID: requiredText(input.sysid || DICT_DEFAULT_SYSID, '所属系统'),
|
|
70
|
+
_TYPE: typeCode,
|
|
71
|
+
_CTYPE: normalizeText(input.ctype),
|
|
72
|
+
_CODE: code,
|
|
73
|
+
_NAME: name,
|
|
74
|
+
_ENAME: normalizeText(input.ename),
|
|
75
|
+
_DICT: normalizeDictFlag(input.dictFlag),
|
|
76
|
+
_SORT: normalizeSort(input.sort),
|
|
77
|
+
_BODY: normalizeText(input.body),
|
|
78
|
+
_MEMO: normalizeText(input.memo),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function buildDictTree(rows) {
|
|
82
|
+
if (!Array.isArray(rows)) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
const recordMap = new Map();
|
|
86
|
+
const childrenMap = new Map();
|
|
87
|
+
const roots = [];
|
|
88
|
+
for (const row of rows) {
|
|
89
|
+
if (!isObject(row)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const key = normalizeText(row._UUID);
|
|
93
|
+
if (!key) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
recordMap.set(key, { ...row });
|
|
97
|
+
}
|
|
98
|
+
for (const record of recordMap.values()) {
|
|
99
|
+
const parentId = normalizeText(record._PID);
|
|
100
|
+
if (!parentId || !recordMap.has(parentId)) {
|
|
101
|
+
roots.push(record);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const children = childrenMap.get(parentId) ?? [];
|
|
105
|
+
children.push(record);
|
|
106
|
+
childrenMap.set(parentId, children);
|
|
107
|
+
}
|
|
108
|
+
for (const [key, record] of recordMap.entries()) {
|
|
109
|
+
const children = childrenMap.get(key);
|
|
110
|
+
if (children && children.length > 0) {
|
|
111
|
+
record.children = children.sort(dictSortKey);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return roots.sort(dictSortKey);
|
|
115
|
+
}
|
|
116
|
+
export function buildBaseSeedSqlVars(input) {
|
|
117
|
+
const adminPassword = input.adminPassword || BASE_SEED_DEFAULT_ADMIN_PASSWORD;
|
|
118
|
+
const passwordHash = createHash('md5').update(adminPassword, 'utf8').digest('hex');
|
|
119
|
+
const adminUid = input.adminUid || BASE_SEED_DEFAULT_ADMIN_UID;
|
|
120
|
+
const adminRole = input.adminRole || BASE_SEED_DEFAULT_ADMIN_ROLE;
|
|
121
|
+
const resetSql = input.resetAdminPassword === true
|
|
122
|
+
? `UPDATE _SYS_USER\nSET _PWD = ${sqlLiteral(passwordHash)}\nWHERE _UID = ${sqlLiteral(adminUid)};`
|
|
123
|
+
: '';
|
|
124
|
+
return {
|
|
125
|
+
SYSID: sqlLiteral(input.sysid || BASE_SEED_DEFAULT_SYSID),
|
|
126
|
+
ADMIN_UID: sqlLiteral(adminUid),
|
|
127
|
+
ADMIN_NAME: sqlLiteral(input.adminName || '管理员'),
|
|
128
|
+
ADMIN_ROLE: sqlLiteral(adminRole),
|
|
129
|
+
ADMIN_ROLE_NAME: sqlLiteral(input.adminRoleName || '管理员'),
|
|
130
|
+
ADMIN_PASSWORD_MD5: sqlLiteral(passwordHash),
|
|
131
|
+
RESET_ADMIN_PASSWORD_SQL: resetSql,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
export function renderBaseSeedSql(template, values) {
|
|
135
|
+
let rendered = template;
|
|
136
|
+
for (const [key, value] of Object.entries(values)) {
|
|
137
|
+
rendered = rendered.replaceAll(`{{${key}}}`, value);
|
|
138
|
+
}
|
|
139
|
+
const missing = [...rendered.matchAll(/\{\{[A-Z0-9_]+\}\}/g)].map((item) => item[0]);
|
|
140
|
+
if (missing.length > 0) {
|
|
141
|
+
throw new SeiMcpError(`初始化 SQL 存在未替换变量:${[...new Set(missing)].join(', ')}`, 'INVALID_PARAMS');
|
|
142
|
+
}
|
|
143
|
+
return rendered;
|
|
144
|
+
}
|
|
145
|
+
export function removeSqlCommentLines(sql) {
|
|
146
|
+
return sql
|
|
147
|
+
.split('\n')
|
|
148
|
+
.filter((line) => !line.trimStart().startsWith('--'))
|
|
149
|
+
.join('\n');
|
|
150
|
+
}
|
|
151
|
+
export function splitSqlStatements(sql) {
|
|
152
|
+
const statements = [];
|
|
153
|
+
let current = '';
|
|
154
|
+
let quote = null;
|
|
155
|
+
let escaped = false;
|
|
156
|
+
for (const char of sql) {
|
|
157
|
+
if (escaped) {
|
|
158
|
+
current += char;
|
|
159
|
+
escaped = false;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (char === '\\' && quote !== null) {
|
|
163
|
+
current += char;
|
|
164
|
+
escaped = true;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (quote !== null) {
|
|
168
|
+
current += char;
|
|
169
|
+
if (char === quote) {
|
|
170
|
+
quote = null;
|
|
171
|
+
}
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (char === '\'' || char === '"' || char === '`') {
|
|
175
|
+
current += char;
|
|
176
|
+
quote = char;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (char === ';') {
|
|
180
|
+
const statement = current.trim();
|
|
181
|
+
if (statement) {
|
|
182
|
+
statements.push(statement);
|
|
183
|
+
}
|
|
184
|
+
current = '';
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
current += char;
|
|
188
|
+
}
|
|
189
|
+
const finalStatement = current.trim();
|
|
190
|
+
if (finalStatement) {
|
|
191
|
+
statements.push(finalStatement);
|
|
192
|
+
}
|
|
193
|
+
return statements;
|
|
194
|
+
}
|
|
195
|
+
function buildDictQueryFilter(typeCode, keyword) {
|
|
196
|
+
const filters = [];
|
|
197
|
+
const normalizedType = normalizeText(typeCode);
|
|
198
|
+
const normalizedKeyword = normalizeText(keyword);
|
|
199
|
+
if (normalizedType) {
|
|
200
|
+
filters.push({ _TYPE: { '=': normalizedType } });
|
|
201
|
+
}
|
|
202
|
+
if (normalizedKeyword) {
|
|
203
|
+
filters.push({
|
|
204
|
+
OR: [
|
|
205
|
+
{ _UUID: { '*LIKE*': normalizedKeyword } },
|
|
206
|
+
{ _TYPE: { '*LIKE*': normalizedKeyword } },
|
|
207
|
+
{ _CODE: { '*LIKE*': normalizedKeyword } },
|
|
208
|
+
{ _NAME: { '*LIKE*': normalizedKeyword } },
|
|
209
|
+
],
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return filters;
|
|
213
|
+
}
|
|
214
|
+
function dictSortKey(a, b) {
|
|
215
|
+
const sortA = normalizeSort(typeof a._SORT === 'number' ? a._SORT : Number(a._SORT ?? 0));
|
|
216
|
+
const sortB = normalizeSort(typeof b._SORT === 'number' ? b._SORT : Number(b._SORT ?? 0));
|
|
217
|
+
if (sortA !== sortB) {
|
|
218
|
+
return sortA - sortB;
|
|
219
|
+
}
|
|
220
|
+
return normalizeText(a._CODE).localeCompare(normalizeText(b._CODE), 'zh-CN');
|
|
221
|
+
}
|
|
222
|
+
function normalizeDictFlag(value) {
|
|
223
|
+
return value === 1 ? 1 : 0;
|
|
224
|
+
}
|
|
225
|
+
function normalizeSort(value) {
|
|
226
|
+
return Number.isInteger(value) && Number(value) >= 0 ? Number(value) : 100;
|
|
227
|
+
}
|
|
228
|
+
function requiredText(value, label) {
|
|
229
|
+
const normalized = normalizeText(value);
|
|
230
|
+
if (!normalized) {
|
|
231
|
+
throw new SeiMcpError(`${label} 不能为空`, 'INVALID_PARAMS');
|
|
232
|
+
}
|
|
233
|
+
return normalized;
|
|
234
|
+
}
|
|
235
|
+
function normalizeText(value) {
|
|
236
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
237
|
+
}
|
|
238
|
+
function sqlLiteral(value) {
|
|
239
|
+
if (value === null || value === undefined) {
|
|
240
|
+
return 'NULL';
|
|
241
|
+
}
|
|
242
|
+
return `'${String(value).replace(/'/g, "''")}'`;
|
|
243
|
+
}
|
|
244
|
+
function isObject(value) {
|
|
245
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
246
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { loadConfig } from '../config.js';
|
|
2
|
+
import { DEFAULT_LOG_LEVEL } from '../constants.js';
|
|
3
|
+
import { loadWorkingDirEnv } from '../env.js';
|
|
4
|
+
import { createLogger } from '../logger.js';
|
|
5
|
+
export async function loadCliContext(argv = process.argv.slice(2), env = process.env) {
|
|
6
|
+
await loadWorkingDirEnv();
|
|
7
|
+
const logger = createLogger(env.SEI_MCP_LOG_LEVEL ?? DEFAULT_LOG_LEVEL);
|
|
8
|
+
const config = await loadConfig(argv, env);
|
|
9
|
+
return { config, logger };
|
|
10
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { SeiMcpError } from '../errors.js';
|
|
3
|
+
export async function loadPayload(options) {
|
|
4
|
+
const sources = [options.stdin, options.jsonText !== undefined, options.filePath !== undefined].filter(Boolean).length;
|
|
5
|
+
if (sources > 1) {
|
|
6
|
+
throw new SeiMcpError('只能选择一种载荷来源:--json、--file 或 --stdin', 'INVALID_PARAMS');
|
|
7
|
+
}
|
|
8
|
+
if (options.jsonText !== undefined) {
|
|
9
|
+
return parseJson(options.jsonText);
|
|
10
|
+
}
|
|
11
|
+
if (options.filePath !== undefined) {
|
|
12
|
+
return parseJson(await readFile(options.filePath, 'utf8'));
|
|
13
|
+
}
|
|
14
|
+
if (options.stdin) {
|
|
15
|
+
return parseJson(await readStdin());
|
|
16
|
+
}
|
|
17
|
+
return options.fallback;
|
|
18
|
+
}
|
|
19
|
+
export function parseJson(text) {
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(text);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
throw new SeiMcpError(`载荷不是合法 JSON:${error instanceof Error ? error.message : String(error)}`, 'INVALID_PARAMS');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function readStdin() {
|
|
28
|
+
const chunks = [];
|
|
29
|
+
for await (const chunk of process.stdin) {
|
|
30
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
31
|
+
}
|
|
32
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
33
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import type { CliSeiClient } from '../sei-client.js';
|
|
3
|
+
import type { Logger, SeiMcpConfig } from '../types.js';
|
|
4
|
+
export declare abstract class SeiCommand extends Command {
|
|
5
|
+
static baseFlags: {
|
|
6
|
+
config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'ai-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
account: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'account-project': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
'account-checkcode': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
timeout: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
};
|
|
15
|
+
protected logger: Logger;
|
|
16
|
+
protected configData: SeiMcpConfig;
|
|
17
|
+
protected init(): Promise<void>;
|
|
18
|
+
protected resolveConfig(): Promise<SeiMcpConfig>;
|
|
19
|
+
protected createCliClient(options?: Partial<SeiAuthSettingsOptions>): Promise<CliSeiClient>;
|
|
20
|
+
protected loadPayload(input: {
|
|
21
|
+
fallback?: unknown;
|
|
22
|
+
filePath?: string;
|
|
23
|
+
jsonText?: string;
|
|
24
|
+
stdin?: boolean;
|
|
25
|
+
}): Promise<unknown>;
|
|
26
|
+
protected printJson(value: unknown): void;
|
|
27
|
+
protected writeText(text: string): void;
|
|
28
|
+
protected createAuthOptions(flags: Record<string, unknown>): SeiAuthSettingsOptions;
|
|
29
|
+
protected createClientFromFlags(flags: Record<string, unknown>): Promise<CliSeiClient>;
|
|
30
|
+
protected catch(error: unknown): Promise<unknown>;
|
|
31
|
+
}
|
|
32
|
+
export interface SeiAuthSettingsOptions {
|
|
33
|
+
baseUrl?: string;
|
|
34
|
+
token?: string;
|
|
35
|
+
aiKey?: string;
|
|
36
|
+
account?: string;
|
|
37
|
+
accountProject?: string;
|
|
38
|
+
accountCheckcode?: string;
|
|
39
|
+
timeoutMs?: number;
|
|
40
|
+
}
|