qijiu-cli 1.0.7
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/bin/qijiu.cjs +4 -0
- package/bin/qijiu.mjs +83 -0
- package/build.mjs +12 -0
- package/package.json +42 -0
- package/src/config.js +28 -0
- package/src/index.js +83 -0
- package/src/mcp-client.js +79 -0
package/bin/qijiu.cjs
ADDED
package/bin/qijiu.mjs
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* qijiu-cli — 企久数据命令行工具
|
|
4
|
+
*
|
|
5
|
+
* 用法:
|
|
6
|
+
* qijiu init --key <app_key> --secret ***
|
|
7
|
+
* qijiu company get_company_baseinfo 阿里巴巴
|
|
8
|
+
*/
|
|
9
|
+
import { getConfig, saveConfig } from "../src/config.js";
|
|
10
|
+
import { connectAndCall } from "../src/mcp-client.js";
|
|
11
|
+
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
|
|
14
|
+
// ==================== init ====================
|
|
15
|
+
if (args[0] === "init") {
|
|
16
|
+
const getArg = (flag) => {
|
|
17
|
+
const idx = args.indexOf(flag);
|
|
18
|
+
return idx >= 0 ? args[idx + 1] : null;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const app_key = getArg("--key") || getArg("-k");
|
|
22
|
+
const app_secret = getArg("--secret") || getArg("-s");
|
|
23
|
+
const server = getArg("--server") || "https://mcp.79cloud.cn";
|
|
24
|
+
|
|
25
|
+
if (!app_key || !app_secret) {
|
|
26
|
+
console.log("qijiu init — 绑定 API Key");
|
|
27
|
+
console.log("");
|
|
28
|
+
console.log("用法:");
|
|
29
|
+
console.log(" qijiu init --key <app_key> --secret ***");
|
|
30
|
+
console.log(" qijiu init --key <app_key> --secret *** --server <url>");
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
saveConfig({ app_key, app_secret, server });
|
|
35
|
+
console.log("✅ 配置已保存");
|
|
36
|
+
console.log(` Server: ${server}`);
|
|
37
|
+
console.log(` App Key: ${app_key.substring(0, 8)}...`);
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ==================== 帮助 ====================
|
|
42
|
+
if (args.length === 0) {
|
|
43
|
+
console.log("企久数据 CLI v1.0.0");
|
|
44
|
+
console.log("");
|
|
45
|
+
console.log("用法:");
|
|
46
|
+
console.log(" qijiu init --key <key> --secret *** 绑定 API Key");
|
|
47
|
+
console.log(" qijiu <模块> <工具名> <参数...> 查询");
|
|
48
|
+
console.log("");
|
|
49
|
+
console.log("模块:");
|
|
50
|
+
console.log(" company 企业基座 (18 tools)");
|
|
51
|
+
console.log(" risk 风控大脑 (8 tools)");
|
|
52
|
+
console.log(" ipr 知产引擎 (7 tools)");
|
|
53
|
+
console.log(" operation 经营罗盘 (8 tools)");
|
|
54
|
+
console.log(" history 历史存档 (10 tools)");
|
|
55
|
+
console.log(" person 董监高画像 (10 tools)");
|
|
56
|
+
console.log("");
|
|
57
|
+
console.log("示例:");
|
|
58
|
+
console.log(" qijiu company get_company_baseinfo 阿里巴巴");
|
|
59
|
+
console.log(" qijiu risk get_judicial_info 华为");
|
|
60
|
+
console.log(" qijiu ipr get_patent_info 腾讯");
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ==================== 执行查询 ====================
|
|
65
|
+
if (args.length < 2) {
|
|
66
|
+
console.error("❌ 参数不足。格式: qijiu <模块> <工具名> <参数...>");
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const moduleName = args[0];
|
|
71
|
+
const toolName = args[1];
|
|
72
|
+
const toolArgs = args.slice(2);
|
|
73
|
+
const config = getConfig();
|
|
74
|
+
|
|
75
|
+
(async () => {
|
|
76
|
+
try {
|
|
77
|
+
const result = await connectAndCall(config, moduleName, toolName, toolArgs);
|
|
78
|
+
console.log(result);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
console.error(`❌ ${e.message}`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
})();
|
package/build.mjs
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as esbuild from "esbuild";
|
|
2
|
+
|
|
3
|
+
await esbuild.build({
|
|
4
|
+
entryPoints: ["src/index.js"],
|
|
5
|
+
bundle: true,
|
|
6
|
+
platform: "node",
|
|
7
|
+
target: "node18",
|
|
8
|
+
format: "cjs",
|
|
9
|
+
outfile: "dist/bundle.cjs",
|
|
10
|
+
external: [],
|
|
11
|
+
});
|
|
12
|
+
console.log("[build] -> dist/bundle.cjs");
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "qijiu-cli",
|
|
3
|
+
"version": "1.0.7",
|
|
4
|
+
"description": "企久数据 CLI - 企业大数据智能查询工具",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/wyqing/qijiu-cli"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"bin": {
|
|
11
|
+
"qijiu": "./bin/qijiu.cjs"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "node build.mjs && pkg dist/bundle.cjs --targets node18-linux-x64 --output dist/qijiu",
|
|
15
|
+
"build:win": "node build.mjs && pkg dist/bundle.cjs --targets node18-win-x64 --output dist/qijiu.exe"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"cli",
|
|
19
|
+
"mcp",
|
|
20
|
+
"qijiu",
|
|
21
|
+
"enterprise",
|
|
22
|
+
"business-data",
|
|
23
|
+
"企业数据"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"bin/",
|
|
30
|
+
"src/",
|
|
31
|
+
"build.mjs"
|
|
32
|
+
],
|
|
33
|
+
"preferGlobal": true,
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@yao-pkg/pkg": "^6.20.0",
|
|
39
|
+
"esbuild": "^0.28.1",
|
|
40
|
+
"pkg": "^5.8.1"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/config.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 配置管理 — 读写 ~/.qijiu/config.json
|
|
3
|
+
*/
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import os from "node:os";
|
|
7
|
+
|
|
8
|
+
const CONFIG_DIR = path.join(os.homedir(), ".qijiu");
|
|
9
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
10
|
+
|
|
11
|
+
export function loadConfig() {
|
|
12
|
+
if (!fs.existsSync(CONFIG_FILE)) return null;
|
|
13
|
+
try { return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8")); } catch { return null; }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function saveConfig(config) {
|
|
17
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
18
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function getConfig() {
|
|
22
|
+
const cfg = loadConfig();
|
|
23
|
+
if (!cfg) {
|
|
24
|
+
console.error("❌ 未初始化,请先运行: qijiu init --key <app_key> --secret ***");
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
return cfg;
|
|
28
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* qijiu-cli — 企久数据命令行工具
|
|
4
|
+
*
|
|
5
|
+
* 用法:
|
|
6
|
+
* qijiu init --key <app_key> --secret ***
|
|
7
|
+
* qijiu company get_company_baseinfo 阿里巴巴
|
|
8
|
+
*/
|
|
9
|
+
import { getConfig, saveConfig } from "./config.js";
|
|
10
|
+
import { connectAndCall } from "./mcp-client.js";
|
|
11
|
+
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
|
|
14
|
+
// ==================== init ====================
|
|
15
|
+
if (args[0] === "init") {
|
|
16
|
+
const getArg = (flag) => {
|
|
17
|
+
const idx = args.indexOf(flag);
|
|
18
|
+
return idx >= 0 ? args[idx + 1] : null;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const app_key = getArg("--key") || getArg("-k");
|
|
22
|
+
const app_secret = getArg("--secret") || getArg("-s");
|
|
23
|
+
const server = getArg("--server") || "https://mcp.79cloud.cn";
|
|
24
|
+
|
|
25
|
+
if (!app_key || !app_secret) {
|
|
26
|
+
console.log("qijiu init — 绑定 API Key");
|
|
27
|
+
console.log("");
|
|
28
|
+
console.log("用法:");
|
|
29
|
+
console.log(" qijiu init --key <app_key> --secret ***");
|
|
30
|
+
console.log(" qijiu init --key <app_key> --secret *** --server <url>");
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
saveConfig({ app_key, app_secret, server });
|
|
35
|
+
console.log("✅ 配置已保存");
|
|
36
|
+
console.log(` Server: ${server}`);
|
|
37
|
+
console.log(` App Key: ${app_key.substring(0, 8)}...`);
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ==================== 帮助 ====================
|
|
42
|
+
if (args.length === 0) {
|
|
43
|
+
console.log("企久数据 CLI v1.0.0");
|
|
44
|
+
console.log("");
|
|
45
|
+
console.log("用法:");
|
|
46
|
+
console.log(" qijiu init --key <key> --secret *** 绑定 API Key");
|
|
47
|
+
console.log(" qijiu <模块> <工具名> <参数...> 查询");
|
|
48
|
+
console.log("");
|
|
49
|
+
console.log("模块:");
|
|
50
|
+
console.log(" company 企业基座 (18 tools)");
|
|
51
|
+
console.log(" risk 风控大脑 (8 tools)");
|
|
52
|
+
console.log(" ipr 知产引擎 (7 tools)");
|
|
53
|
+
console.log(" operation 经营罗盘 (8 tools)");
|
|
54
|
+
console.log(" history 历史存档 (10 tools)");
|
|
55
|
+
console.log(" person 董监高画像 (10 tools)");
|
|
56
|
+
console.log("");
|
|
57
|
+
console.log("示例:");
|
|
58
|
+
console.log(" qijiu company get_company_baseinfo 阿里巴巴");
|
|
59
|
+
console.log(" qijiu risk get_judicial_info 华为");
|
|
60
|
+
console.log(" qijiu ipr get_patent_info 腾讯");
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ==================== 执行查询 ====================
|
|
65
|
+
if (args.length < 2) {
|
|
66
|
+
console.error("❌ 参数不足。格式: qijiu <模块> <工具名> <参数...>");
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const moduleName = args[0];
|
|
71
|
+
const toolName = args[1];
|
|
72
|
+
const toolArgs = args.slice(2);
|
|
73
|
+
const config = getConfig();
|
|
74
|
+
|
|
75
|
+
(async () => {
|
|
76
|
+
try {
|
|
77
|
+
const result = await connectAndCall(config, moduleName, toolName, toolArgs);
|
|
78
|
+
console.log(result);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
console.error(`❌ ${e.message}`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
})();
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP 客户端 — 按模块连接并调用工具
|
|
3
|
+
*/
|
|
4
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
5
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
6
|
+
|
|
7
|
+
// 模块 → MCP 路径
|
|
8
|
+
const MODULE_PATHS = {
|
|
9
|
+
company: "/mcp/company/stream",
|
|
10
|
+
risk: "/mcp/risk/stream",
|
|
11
|
+
ipr: "/mcp/ipr/stream",
|
|
12
|
+
operation: "/mcp/operation/stream",
|
|
13
|
+
history: "/mcp/history/stream",
|
|
14
|
+
person: "/mcp/person/stream",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export async function connectAndCall(config, moduleName, toolName, rawArgs) {
|
|
18
|
+
const { app_key, app_secret, server = "https://mcp.79cloud.cn" } = config;
|
|
19
|
+
const baseUrl = server.replace(/\/$/, "");
|
|
20
|
+
const path = MODULE_PATHS[moduleName];
|
|
21
|
+
|
|
22
|
+
if (!path) {
|
|
23
|
+
throw new Error(`未知模块: ${moduleName}。可用: ${Object.keys(MODULE_PATHS).join(", ")}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 连接 MCP Server
|
|
27
|
+
const transport = new StreamableHTTPClientTransport(new URL(`${baseUrl}${path}`), {
|
|
28
|
+
requestInit: {
|
|
29
|
+
headers: {
|
|
30
|
+
"X-App-Key": app_key,
|
|
31
|
+
"X-App-Secret": app_secret,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
const client = new Client({ name: "qijiu-cli", version: "1.0.0" }, { capabilities: {} });
|
|
36
|
+
await client.connect(transport);
|
|
37
|
+
|
|
38
|
+
// 获取工具列表,验证工具名
|
|
39
|
+
const { tools } = await client.listTools();
|
|
40
|
+
const tool = tools.find((t) => t.name === toolName);
|
|
41
|
+
if (!tool) {
|
|
42
|
+
const names = tools.map((t) => t.name).join(", ");
|
|
43
|
+
throw new Error(`工具 "${toolName}" 不存在。\n${moduleName} 下可用: ${names}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 解析参数
|
|
47
|
+
const args = parseArgs(rawArgs, tool.inputSchema);
|
|
48
|
+
|
|
49
|
+
// 调用工具
|
|
50
|
+
const result = await client.callTool({ name: toolName, arguments: args });
|
|
51
|
+
|
|
52
|
+
// 格式化输出
|
|
53
|
+
const output = result.content
|
|
54
|
+
.map((c) => (c.type === "text" ? c.text : JSON.stringify(c)))
|
|
55
|
+
.join("\n");
|
|
56
|
+
|
|
57
|
+
try { await client.close(); } catch {}
|
|
58
|
+
return output;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function parseArgs(rawArgs, inputSchema) {
|
|
62
|
+
if (!rawArgs || rawArgs.length === 0) return {};
|
|
63
|
+
const schema = inputSchema?.properties || {};
|
|
64
|
+
const keys = Object.keys(schema);
|
|
65
|
+
|
|
66
|
+
if (rawArgs.length === 1 && keys.length >= 1) {
|
|
67
|
+
return { [keys[0]]: rawArgs[0] };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const args = {};
|
|
71
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
72
|
+
if (rawArgs[i].startsWith("--")) {
|
|
73
|
+
const key = rawArgs[i].replace(/^--/, "");
|
|
74
|
+
const val = rawArgs[i + 1] && !rawArgs[i + 1].startsWith("--") ? rawArgs[++i] : null;
|
|
75
|
+
if (val !== null) args[key] = val;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return args;
|
|
79
|
+
}
|