@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,85 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import { loadConfig } from '../config.js';
|
|
3
|
+
import { DEFAULT_LOG_LEVEL } from '../constants.js';
|
|
4
|
+
import { formatCliError, toErrorLogMeta } from '../errors.js';
|
|
5
|
+
import { loadWorkingDirEnv } from '../env.js';
|
|
6
|
+
import { createLogger } from '../logger.js';
|
|
7
|
+
import { createCliSeiClient, createSeiAuthSettings } from '../sei-client.js';
|
|
8
|
+
import { loadPayload } from './payload.js';
|
|
9
|
+
import { printJson, writeText } from './output.js';
|
|
10
|
+
export class SeiCommand extends Command {
|
|
11
|
+
static baseFlags = {
|
|
12
|
+
config: Flags.string({ description: '配置文件路径' }),
|
|
13
|
+
'base-url': Flags.string({ description: 'SEI 基础地址' }),
|
|
14
|
+
'ai-key': Flags.string({ description: 'AI 登录密钥' }),
|
|
15
|
+
account: Flags.string({ description: 'AI 登录账号' }),
|
|
16
|
+
'account-project': Flags.string({ description: 'AI 登录项目' }),
|
|
17
|
+
'account-checkcode': Flags.string({ description: 'AI 登录验证码' }),
|
|
18
|
+
token: Flags.string({ description: '固定 token' }),
|
|
19
|
+
timeout: Flags.integer({ description: '请求超时(毫秒)' }),
|
|
20
|
+
};
|
|
21
|
+
logger;
|
|
22
|
+
configData;
|
|
23
|
+
async init() {
|
|
24
|
+
await loadWorkingDirEnv();
|
|
25
|
+
this.logger = createLogger(process.env.SEI_MCP_LOG_LEVEL ?? DEFAULT_LOG_LEVEL);
|
|
26
|
+
this.configData = await loadConfig(this.argv, process.env);
|
|
27
|
+
await super.init();
|
|
28
|
+
}
|
|
29
|
+
async resolveConfig() {
|
|
30
|
+
return this.configData;
|
|
31
|
+
}
|
|
32
|
+
async createCliClient(options = {}) {
|
|
33
|
+
const config = await this.resolveConfig();
|
|
34
|
+
const settings = createSeiAuthSettings(config, {
|
|
35
|
+
baseUrl: options.baseUrl,
|
|
36
|
+
token: options.token,
|
|
37
|
+
aiKey: options.aiKey,
|
|
38
|
+
account: options.account,
|
|
39
|
+
accountProject: options.accountProject,
|
|
40
|
+
accountCheckcode: options.accountCheckcode,
|
|
41
|
+
timeoutMs: options.timeoutMs,
|
|
42
|
+
});
|
|
43
|
+
return createCliSeiClient(settings, this.logger, globalThis.fetch);
|
|
44
|
+
}
|
|
45
|
+
async loadPayload(input) {
|
|
46
|
+
return loadPayload(input);
|
|
47
|
+
}
|
|
48
|
+
printJson(value) {
|
|
49
|
+
printJson(value);
|
|
50
|
+
}
|
|
51
|
+
writeText(text) {
|
|
52
|
+
writeText(text);
|
|
53
|
+
}
|
|
54
|
+
createAuthOptions(flags) {
|
|
55
|
+
return {
|
|
56
|
+
baseUrl: stringFlag(flags, 'base-url'),
|
|
57
|
+
token: stringFlag(flags, 'token'),
|
|
58
|
+
aiKey: stringFlag(flags, 'ai-key'),
|
|
59
|
+
account: stringFlag(flags, 'account'),
|
|
60
|
+
accountProject: stringFlag(flags, 'account-project'),
|
|
61
|
+
accountCheckcode: stringFlag(flags, 'account-checkcode'),
|
|
62
|
+
timeoutMs: numberFlag(flags, 'timeout'),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async createClientFromFlags(flags) {
|
|
66
|
+
return this.createCliClient(this.createAuthOptions(flags));
|
|
67
|
+
}
|
|
68
|
+
async catch(error) {
|
|
69
|
+
this.logger?.error('CLI command failed', {
|
|
70
|
+
argv: this.argv,
|
|
71
|
+
error: toErrorLogMeta(error),
|
|
72
|
+
});
|
|
73
|
+
process.stderr.write(`${formatCliError(error)}\n`);
|
|
74
|
+
process.exitCode = 1;
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function stringFlag(flags, name) {
|
|
79
|
+
const value = flags[name];
|
|
80
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
81
|
+
}
|
|
82
|
+
function numberFlag(flags, name) {
|
|
83
|
+
const value = flags[name];
|
|
84
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
85
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { DEFAULT_BASE_URL } from './constants.js';
|
|
3
|
+
import { SeiMcpError } from './errors.js';
|
|
4
|
+
import { isObject, toTrimmedString } from './utils.js';
|
|
5
|
+
export async function loadConfig(argv = process.argv.slice(2), env = process.env) {
|
|
6
|
+
const configPath = resolveArg(argv, '--config') ?? (toTrimmedString(env.SEI_AI_MCP_CONFIG) || null);
|
|
7
|
+
const fileConfig = configPath ? await readConfigFile(configPath) : {};
|
|
8
|
+
return normalizeConfig(fileConfig, env);
|
|
9
|
+
}
|
|
10
|
+
export function normalizeConfig(input = {}, env = process.env) {
|
|
11
|
+
const config = isObject(input) ? input : {};
|
|
12
|
+
const auth = isObject(config.auth) ? config.auth : {};
|
|
13
|
+
const tools = isObject(config.tools) ? config.tools : {};
|
|
14
|
+
const targets = isObject(config.targets) ? config.targets : {};
|
|
15
|
+
return {
|
|
16
|
+
baseUrl: normalizeBaseUrl(config.baseUrl, env.SEI_BASE_URL),
|
|
17
|
+
auth: {
|
|
18
|
+
mode: normalizeMode(auth.mode, env.SEI_AI_MCP_AUTH_MODE),
|
|
19
|
+
token: stringOrEnv(auth.token, env.SEI_TOKEN),
|
|
20
|
+
tokenEnv: stringOrEnv(auth.tokenEnv, env.SEI_TOKEN ? 'SEI_TOKEN' : 'SEI_TOKEN'),
|
|
21
|
+
aiKey: stringOrEnv(auth.aiKey, env.SEI_AI_LOGIN_KEY),
|
|
22
|
+
aiKeyEnv: stringOrEnv(auth.aiKeyEnv, env.SEI_AI_LOGIN_KEY ? 'SEI_AI_LOGIN_KEY' : 'SEI_AI_LOGIN_KEY'),
|
|
23
|
+
account: stringOrEnv(auth.account, env.SEI_AI_LOGIN_ACCOUNT) || 'admin',
|
|
24
|
+
accountEnv: stringOrEnv(auth.accountEnv, env.SEI_AI_LOGIN_ACCOUNT ? 'SEI_AI_LOGIN_ACCOUNT' : 'SEI_AI_LOGIN_ACCOUNT'),
|
|
25
|
+
},
|
|
26
|
+
tools: {
|
|
27
|
+
query: tools.query !== false,
|
|
28
|
+
save: tools.save !== false,
|
|
29
|
+
schema: tools.schema !== false,
|
|
30
|
+
querySql: tools.querySql === true,
|
|
31
|
+
},
|
|
32
|
+
targets: {
|
|
33
|
+
modules: toTargetMap(targets.modules),
|
|
34
|
+
tables: toTargetMap(targets.tables),
|
|
35
|
+
sources: toTargetMap(targets.sources),
|
|
36
|
+
views: toTargetMap(targets.views),
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async function readConfigFile(path) {
|
|
41
|
+
try {
|
|
42
|
+
const text = await readFile(path, 'utf8');
|
|
43
|
+
return JSON.parse(text);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
throw new SeiMcpError(`无法读取配置文件: ${path}`, 'INVALID_REQUEST', {
|
|
47
|
+
path,
|
|
48
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function resolveArg(argv, name) {
|
|
53
|
+
const index = argv.indexOf(name);
|
|
54
|
+
if (index === -1) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const next = argv[index + 1];
|
|
58
|
+
return next && !next.startsWith('-') ? next : null;
|
|
59
|
+
}
|
|
60
|
+
function normalizeBaseUrl(configValue, envValue) {
|
|
61
|
+
const raw = stringOrEnv(configValue, envValue);
|
|
62
|
+
return raw || DEFAULT_BASE_URL;
|
|
63
|
+
}
|
|
64
|
+
function normalizeMode(configValue, envValue) {
|
|
65
|
+
const raw = stringOrEnv(configValue, envValue).toLowerCase();
|
|
66
|
+
return raw === 'token' ? 'token' : 'ai-login';
|
|
67
|
+
}
|
|
68
|
+
function stringOrEnv(value, envValue) {
|
|
69
|
+
const candidate = toTrimmedString(value);
|
|
70
|
+
if (candidate) {
|
|
71
|
+
return candidate;
|
|
72
|
+
}
|
|
73
|
+
return toTrimmedString(envValue);
|
|
74
|
+
}
|
|
75
|
+
function toTargetMap(value) {
|
|
76
|
+
if (!isObject(value)) {
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
return Object.fromEntries(Object.entries(value).filter(([, item]) => isObject(item)));
|
|
80
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export declare const PACKAGE_NAME = "sei-ai";
|
|
2
|
+
export declare const BIN_NAME = "sei-ai";
|
|
3
|
+
export declare const SERVER_NAME = "sei-ai-mcp-server";
|
|
4
|
+
export declare const SERVER_VERSION = "0.2.0";
|
|
5
|
+
export declare const DEFAULT_BASE_URL = "http://127.0.0.1:8081";
|
|
6
|
+
export declare const DEFAULT_AI_KEY = "dev-ai-secret";
|
|
7
|
+
export declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
8
|
+
export declare const DEFAULT_LOG_LEVEL = "info";
|
|
9
|
+
export declare const DEFAULT_QUERY_LIMIT = 20;
|
|
10
|
+
export declare const DEFAULT_QUERY_SQL_PAGE = 1;
|
|
11
|
+
export declare const DEFAULT_QUERY_SQL_SIZE = 20;
|
|
12
|
+
export declare const MAX_RESPONSE_TEXT = 20000;
|
|
13
|
+
export declare const MAX_LOG_TEXT = 2000;
|
|
14
|
+
export declare const LOGIN_PATH = "/api/sei/public/login";
|
|
15
|
+
export declare const ACCOUNT_CHECK_CODE_PATH = "/api/sei/public/checkCode";
|
|
16
|
+
export declare const QUERY_PATH = "/api/sei/data/public/query";
|
|
17
|
+
export declare const SAVE_PATH = "/api/sei/data/public/save";
|
|
18
|
+
export declare const QUERY_SQL_PATH = "/api/sei/data/querySQL";
|
|
19
|
+
export declare const DDL_EXECUTE_PATH = "/api/sei/mcp/ddl/execute";
|
|
20
|
+
export declare const OPENAPI_DOCS_PATH = "/v3/api-docs";
|
|
21
|
+
export declare const DICT_MODULE = "sys_dic";
|
|
22
|
+
export declare const DICT_DEFAULT_SYSID = "sys";
|
|
23
|
+
export declare const DICT_FIELDS: readonly ["_UUID", "_PID", "_SYSID", "_TYPE", "_CTYPE", "_CODE", "_NAME", "_ENAME", "_DICT", "_SORT", "_BODY", "_MEMO"];
|
|
24
|
+
export declare const BASE_SEED_DEFAULT_SYSID = "sys";
|
|
25
|
+
export declare const BASE_SEED_DEFAULT_ADMIN_UID = "admin";
|
|
26
|
+
export declare const BASE_SEED_DEFAULT_ADMIN_ROLE = "admin";
|
|
27
|
+
export declare const BASE_SEED_DEFAULT_ADMIN_PASSWORD = "123456";
|
|
28
|
+
export declare const ACCOUNT_LOGIN_DEFAULT_PROJECT = "sys";
|
|
29
|
+
export declare const ACCOUNT_LOGIN_DEFAULT_CHECKCODE = "abcd";
|
|
30
|
+
export declare const ACCOUNT_LOGIN_DEFAULT_TYPE = "login";
|
|
31
|
+
export declare const ACCOUNT_LOGIN_DEFAULT_OS = 0;
|
|
32
|
+
export declare const TOKEN_CACHE_DIR_NAME = "sei-ai";
|
|
33
|
+
export declare const TOKEN_CACHE_FILE_PREFIX = "token-";
|
|
34
|
+
export declare const TOKEN_CACHE_FILE_SUFFIX = ".json";
|
|
35
|
+
export declare const TOKEN_CACHE_VERSION = 1;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const PACKAGE_NAME = 'sei-ai';
|
|
2
|
+
export const BIN_NAME = 'sei-ai';
|
|
3
|
+
export const SERVER_NAME = 'sei-ai-mcp-server';
|
|
4
|
+
export const SERVER_VERSION = '0.2.0';
|
|
5
|
+
export const DEFAULT_BASE_URL = 'http://127.0.0.1:8081';
|
|
6
|
+
export const DEFAULT_AI_KEY = 'dev-ai-secret';
|
|
7
|
+
export const DEFAULT_TIMEOUT_MS = 30_000;
|
|
8
|
+
export const DEFAULT_LOG_LEVEL = 'info';
|
|
9
|
+
export const DEFAULT_QUERY_LIMIT = 20;
|
|
10
|
+
export const DEFAULT_QUERY_SQL_PAGE = 1;
|
|
11
|
+
export const DEFAULT_QUERY_SQL_SIZE = 20;
|
|
12
|
+
export const MAX_RESPONSE_TEXT = 20_000;
|
|
13
|
+
export const MAX_LOG_TEXT = 2_000;
|
|
14
|
+
export const LOGIN_PATH = '/api/sei/public/login';
|
|
15
|
+
export const ACCOUNT_CHECK_CODE_PATH = '/api/sei/public/checkCode';
|
|
16
|
+
export const QUERY_PATH = '/api/sei/data/public/query';
|
|
17
|
+
export const SAVE_PATH = '/api/sei/data/public/save';
|
|
18
|
+
export const QUERY_SQL_PATH = '/api/sei/data/querySQL';
|
|
19
|
+
export const DDL_EXECUTE_PATH = '/api/sei/mcp/ddl/execute';
|
|
20
|
+
export const OPENAPI_DOCS_PATH = '/v3/api-docs';
|
|
21
|
+
export const DICT_MODULE = 'sys_dic';
|
|
22
|
+
export const DICT_DEFAULT_SYSID = 'sys';
|
|
23
|
+
export const DICT_FIELDS = [
|
|
24
|
+
'_UUID',
|
|
25
|
+
'_PID',
|
|
26
|
+
'_SYSID',
|
|
27
|
+
'_TYPE',
|
|
28
|
+
'_CTYPE',
|
|
29
|
+
'_CODE',
|
|
30
|
+
'_NAME',
|
|
31
|
+
'_ENAME',
|
|
32
|
+
'_DICT',
|
|
33
|
+
'_SORT',
|
|
34
|
+
'_BODY',
|
|
35
|
+
'_MEMO',
|
|
36
|
+
];
|
|
37
|
+
export const BASE_SEED_DEFAULT_SYSID = 'sys';
|
|
38
|
+
export const BASE_SEED_DEFAULT_ADMIN_UID = 'admin';
|
|
39
|
+
export const BASE_SEED_DEFAULT_ADMIN_ROLE = 'admin';
|
|
40
|
+
export const BASE_SEED_DEFAULT_ADMIN_PASSWORD = '123456';
|
|
41
|
+
export const ACCOUNT_LOGIN_DEFAULT_PROJECT = 'sys';
|
|
42
|
+
export const ACCOUNT_LOGIN_DEFAULT_CHECKCODE = 'abcd';
|
|
43
|
+
export const ACCOUNT_LOGIN_DEFAULT_TYPE = 'login';
|
|
44
|
+
export const ACCOUNT_LOGIN_DEFAULT_OS = 0;
|
|
45
|
+
export const TOKEN_CACHE_DIR_NAME = 'sei-ai';
|
|
46
|
+
export const TOKEN_CACHE_FILE_PREFIX = 'token-';
|
|
47
|
+
export const TOKEN_CACHE_FILE_SUFFIX = '.json';
|
|
48
|
+
export const TOKEN_CACHE_VERSION = 1;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function loadWorkingDirEnv(cwd?: string, env?: NodeJS.ProcessEnv): Promise<void>;
|
package/dist/core/env.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
const DEFAULT_ENV_FILES = ['.env.local', '.env'];
|
|
4
|
+
export async function loadWorkingDirEnv(cwd = process.cwd(), env = process.env) {
|
|
5
|
+
for (const fileName of DEFAULT_ENV_FILES) {
|
|
6
|
+
await loadEnvFile(resolve(cwd, fileName), env);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
async function loadEnvFile(path, env) {
|
|
10
|
+
try {
|
|
11
|
+
const text = await readFile(path, 'utf8');
|
|
12
|
+
const parsed = parseEnvText(text);
|
|
13
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
14
|
+
if (env[key] === undefined) {
|
|
15
|
+
env[key] = value;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (isMissingFile(error)) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function isMissingFile(error) {
|
|
27
|
+
if (!error || typeof error !== 'object') {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const withCode = error;
|
|
31
|
+
return withCode.code === 'ENOENT';
|
|
32
|
+
}
|
|
33
|
+
function parseEnvText(text) {
|
|
34
|
+
const result = {};
|
|
35
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
36
|
+
const line = rawLine.trim();
|
|
37
|
+
if (!line || line.startsWith('#')) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const equalsIndex = line.indexOf('=');
|
|
41
|
+
if (equalsIndex === -1) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const key = line.slice(0, equalsIndex).trim();
|
|
45
|
+
if (!key) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
let value = line.slice(equalsIndex + 1).trim();
|
|
49
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
50
|
+
value = value.slice(1, -1);
|
|
51
|
+
}
|
|
52
|
+
result[key] = value;
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { JsonValue } from './utils.js';
|
|
2
|
+
export declare class SeiMcpError extends Error {
|
|
3
|
+
readonly code: string;
|
|
4
|
+
readonly details?: Record<string, unknown>;
|
|
5
|
+
constructor(message: string, code?: string, details?: Record<string, unknown>);
|
|
6
|
+
}
|
|
7
|
+
export declare function isSeiMcpError(error: unknown): error is SeiMcpError;
|
|
8
|
+
export declare function normalizeErrorMessage(error: unknown): string;
|
|
9
|
+
export declare function formatCliError(error: unknown): string;
|
|
10
|
+
export declare function toErrorLogMeta(error: unknown): JsonValue;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export class SeiMcpError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
details;
|
|
4
|
+
constructor(message, code = 'INTERNAL_ERROR', details) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'SeiMcpError';
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.details = details;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function isSeiMcpError(error) {
|
|
12
|
+
return error instanceof SeiMcpError;
|
|
13
|
+
}
|
|
14
|
+
export function normalizeErrorMessage(error) {
|
|
15
|
+
return error instanceof Error ? error.message : 'Unknown error';
|
|
16
|
+
}
|
|
17
|
+
export function formatCliError(error) {
|
|
18
|
+
if (error instanceof SeiMcpError) {
|
|
19
|
+
return `[${error.code}] ${error.message}`;
|
|
20
|
+
}
|
|
21
|
+
return `[INTERNAL_ERROR] ${normalizeErrorMessage(error)}`;
|
|
22
|
+
}
|
|
23
|
+
export function toErrorLogMeta(error) {
|
|
24
|
+
if (error instanceof SeiMcpError) {
|
|
25
|
+
return {
|
|
26
|
+
code: error.code,
|
|
27
|
+
message: error.message,
|
|
28
|
+
details: toJsonValue(error.details),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (error instanceof Error) {
|
|
32
|
+
return {
|
|
33
|
+
message: error.message,
|
|
34
|
+
stack: error.stack ?? '',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
message: normalizeErrorMessage(error),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function toJsonValue(value) {
|
|
42
|
+
if (value === null) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
return value.map((item) => toJsonValue(item));
|
|
50
|
+
}
|
|
51
|
+
if (value && typeof value === 'object') {
|
|
52
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, toJsonValue(item)]));
|
|
53
|
+
}
|
|
54
|
+
return String(value);
|
|
55
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from './cli-actions.js';
|
|
2
|
+
export * from './cli-helpers.js';
|
|
3
|
+
export * from './config.js';
|
|
4
|
+
export * from './constants.js';
|
|
5
|
+
export * from './env.js';
|
|
6
|
+
export * from './errors.js';
|
|
7
|
+
export * from './logger.js';
|
|
8
|
+
export * from './openapi.js';
|
|
9
|
+
export * from './sei-client.js';
|
|
10
|
+
export * from './types.js';
|
|
11
|
+
export * from './utils.js';
|
|
12
|
+
export * from './command-base/output.js';
|
|
13
|
+
export * from './command-base/payload.js';
|
|
14
|
+
export * from './command-base/sei-command.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from './cli-actions.js';
|
|
2
|
+
export * from './cli-helpers.js';
|
|
3
|
+
export * from './config.js';
|
|
4
|
+
export * from './constants.js';
|
|
5
|
+
export * from './env.js';
|
|
6
|
+
export * from './errors.js';
|
|
7
|
+
export * from './logger.js';
|
|
8
|
+
export * from './openapi.js';
|
|
9
|
+
export * from './sei-client.js';
|
|
10
|
+
export * from './types.js';
|
|
11
|
+
export * from './utils.js';
|
|
12
|
+
export * from './command-base/output.js';
|
|
13
|
+
export * from './command-base/payload.js';
|
|
14
|
+
export * from './command-base/sei-command.js';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { DEFAULT_LOG_LEVEL, MAX_LOG_TEXT } from './constants.js';
|
|
2
|
+
import { truncateText } from './utils.js';
|
|
3
|
+
const LEVEL_PRIORITY = {
|
|
4
|
+
error: 0,
|
|
5
|
+
warn: 1,
|
|
6
|
+
info: 2,
|
|
7
|
+
debug: 3,
|
|
8
|
+
};
|
|
9
|
+
const SENSITIVE_KEYS = new Set([
|
|
10
|
+
'authorization',
|
|
11
|
+
'cookie',
|
|
12
|
+
'password',
|
|
13
|
+
'token',
|
|
14
|
+
'aiKey',
|
|
15
|
+
'ai_key',
|
|
16
|
+
'secret',
|
|
17
|
+
'body',
|
|
18
|
+
]);
|
|
19
|
+
export function createLogger(level = DEFAULT_LOG_LEVEL) {
|
|
20
|
+
const threshold = LEVEL_PRIORITY[normalizeLevel(level)] ?? LEVEL_PRIORITY.info;
|
|
21
|
+
function write(targetLevel, message, meta) {
|
|
22
|
+
if (LEVEL_PRIORITY[targetLevel] > threshold) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const entry = {
|
|
26
|
+
level: targetLevel,
|
|
27
|
+
message: truncateText(message, MAX_LOG_TEXT),
|
|
28
|
+
meta: sanitizeMeta(meta),
|
|
29
|
+
time: new Date().toISOString(),
|
|
30
|
+
};
|
|
31
|
+
process.stderr.write(`${JSON.stringify(entry)}\n`);
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
debug(message, meta) {
|
|
35
|
+
write('debug', message, meta);
|
|
36
|
+
},
|
|
37
|
+
info(message, meta) {
|
|
38
|
+
write('info', message, meta);
|
|
39
|
+
},
|
|
40
|
+
warn(message, meta) {
|
|
41
|
+
write('warn', message, meta);
|
|
42
|
+
},
|
|
43
|
+
error(message, meta) {
|
|
44
|
+
write('error', message, meta);
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function normalizeLevel(level) {
|
|
49
|
+
const normalized = level.trim().toLowerCase();
|
|
50
|
+
if (normalized === 'debug' || normalized === 'info' || normalized === 'warn' || normalized === 'error') {
|
|
51
|
+
return normalized;
|
|
52
|
+
}
|
|
53
|
+
return 'info';
|
|
54
|
+
}
|
|
55
|
+
function sanitizeMeta(value) {
|
|
56
|
+
if (Array.isArray(value)) {
|
|
57
|
+
return value.map((item) => sanitizeMeta(item));
|
|
58
|
+
}
|
|
59
|
+
if (!value || typeof value !== 'object') {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
const result = {};
|
|
63
|
+
for (const [key, item] of Object.entries(value)) {
|
|
64
|
+
if (SENSITIVE_KEYS.has(key)) {
|
|
65
|
+
result[key] = '[REDACTED]';
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
result[key] = sanitizeMeta(item);
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|