echopai 2.0.0
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 +386 -0
- package/dist/_generated/commands.js +274 -0
- package/dist/_generated/help.js +190 -0
- package/dist/_generated/operations.js +1306 -0
- package/dist/bin.js +170 -0
- package/dist/runtime/auth.js +95 -0
- package/dist/runtime/envelope.js +52 -0
- package/dist/runtime/errors.js +186 -0
- package/dist/runtime/filters.js +153 -0
- package/dist/runtime/format.js +143 -0
- package/dist/runtime/http.js +65 -0
- package/dist/runtime/idempotency.js +18 -0
- package/dist/runtime/invoker.js +387 -0
- package/dist/runtime/io.js +16 -0
- package/dist/runtime/paginator.js +146 -0
- package/dist/runtime/trace.js +99 -0
- package/dist/runtime/tty.js +51 -0
- package/dist/runtime/verb_cmd.js +70 -0
- package/dist/runtime/verb_runner.js +152 -0
- package/dist/runtime/whoami_cache.js +109 -0
- package/dist/tools/api.js +81 -0
- package/dist/tools/completion.js +116 -0
- package/dist/tools/config.js +123 -0
- package/dist/tools/doctor.js +183 -0
- package/dist/tools/login.js +99 -0
- package/dist/tools/mcp.js +141 -0
- package/dist/tools/raw.js +96 -0
- package/dist/tools/schema.js +58 -0
- package/dist/tools/trace.js +54 -0
- package/dist/tools/whoami.js +132 -0
- package/dist/verbs/_spec.js +15 -0
- package/dist/verbs/bars_batch.js +66 -0
- package/dist/verbs/chart.js +110 -0
- package/dist/verbs/digest.js +342 -0
- package/dist/verbs/hot.js +29 -0
- package/dist/verbs/index.js +49 -0
- package/dist/verbs/lookup.js +72 -0
- package/dist/verbs/news.js +67 -0
- package/dist/verbs/quote.js +53 -0
- package/dist/verbs/research.js +44 -0
- package/dist/verbs/scan.js +42 -0
- package/dist/verbs/sentiment.js +46 -0
- package/dist/verbs/views.js +83 -0
- package/dist/version.js +5 -0
- package/package.json +58 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `echopai scan` + MCP tool `scan`.
|
|
3
|
+
*/
|
|
4
|
+
import { Command, Option } from "commander";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { OPERATIONS } from "../_generated/operations.js";
|
|
7
|
+
import { executeVerb, emitVerbError } from "../runtime/verb_cmd.js";
|
|
8
|
+
import { callOp } from "../runtime/verb_runner.js";
|
|
9
|
+
export const scanSpec = {
|
|
10
|
+
name: "scan",
|
|
11
|
+
description: "Full-market real-time quote scan (~5800 A-share securities in one round-trip). Use for universe discovery; agents should slim output with field/byte limits in their tool host or post-processing.",
|
|
12
|
+
inputSchema: {
|
|
13
|
+
exchange: z
|
|
14
|
+
.enum(["SSE", "SZSE", "BSE"])
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("Filter by exchange (omit for all)"),
|
|
17
|
+
},
|
|
18
|
+
handler: async (args, ctx) => {
|
|
19
|
+
const op = OPERATIONS["quote.scan"];
|
|
20
|
+
if (!op)
|
|
21
|
+
throw new Error("quote.scan op missing");
|
|
22
|
+
const callArgs = {};
|
|
23
|
+
if (args.exchange)
|
|
24
|
+
callArgs.exchange = args.exchange;
|
|
25
|
+
return callOp(op, callArgs, ctx);
|
|
26
|
+
},
|
|
27
|
+
backingOps: ["quote.scan"],
|
|
28
|
+
};
|
|
29
|
+
export function buildScanCommand() {
|
|
30
|
+
const cmd = new Command(scanSpec.name).description(scanSpec.description);
|
|
31
|
+
cmd.addOption(new Option("--exchange <code>", "Filter by exchange").choices(["SSE", "SZSE", "BSE"]));
|
|
32
|
+
cmd.action(async (opts) => {
|
|
33
|
+
if (!OPERATIONS["quote.scan"]) {
|
|
34
|
+
emitVerbError("internal_error", "quote.scan missing", undefined, 2);
|
|
35
|
+
}
|
|
36
|
+
const args = {};
|
|
37
|
+
if (opts.exchange)
|
|
38
|
+
args.exchange = opts.exchange;
|
|
39
|
+
await executeVerb(async (ctx) => scanSpec.handler(args, ctx));
|
|
40
|
+
});
|
|
41
|
+
return cmd;
|
|
42
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `echopai sentiment [--scope <universe>]` + MCP tool `sentiment`.
|
|
3
|
+
*/
|
|
4
|
+
import { Command, Option } from "commander";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { OPERATIONS } from "../_generated/operations.js";
|
|
7
|
+
import { executeVerb, emitVerbError } from "../runtime/verb_cmd.js";
|
|
8
|
+
import { callOp } from "../runtime/verb_runner.js";
|
|
9
|
+
const SCOPE_VALUES = [
|
|
10
|
+
"all_a",
|
|
11
|
+
"all_a_ex_st",
|
|
12
|
+
"main_board",
|
|
13
|
+
"star_market",
|
|
14
|
+
"chinext",
|
|
15
|
+
"bse",
|
|
16
|
+
];
|
|
17
|
+
export const sentimentSpec = {
|
|
18
|
+
name: "sentiment",
|
|
19
|
+
description: "Aggregate market sentiment indicators (limit-up/down counts, breadth, divergence index, top movers). Defaults to all_a_ex_st (all A-shares ex-ST).",
|
|
20
|
+
inputSchema: {
|
|
21
|
+
scope: z
|
|
22
|
+
.enum(SCOPE_VALUES)
|
|
23
|
+
.default("all_a_ex_st")
|
|
24
|
+
.describe("Universe filter"),
|
|
25
|
+
},
|
|
26
|
+
handler: async (args, ctx) => {
|
|
27
|
+
const op = OPERATIONS["sentiment.overview"];
|
|
28
|
+
if (!op)
|
|
29
|
+
throw new Error("sentiment.overview op missing");
|
|
30
|
+
return callOp(op, { scope: args.scope }, ctx);
|
|
31
|
+
},
|
|
32
|
+
backingOps: ["sentiment.overview"],
|
|
33
|
+
};
|
|
34
|
+
export function buildSentimentCommand() {
|
|
35
|
+
const cmd = new Command(sentimentSpec.name).description(sentimentSpec.description);
|
|
36
|
+
cmd.addOption(new Option("--scope <universe>", "Universe filter")
|
|
37
|
+
.choices([...SCOPE_VALUES])
|
|
38
|
+
.default("all_a_ex_st"));
|
|
39
|
+
cmd.action(async (opts) => {
|
|
40
|
+
if (!OPERATIONS["sentiment.overview"]) {
|
|
41
|
+
emitVerbError("internal_error", "sentiment.overview missing", undefined, 2);
|
|
42
|
+
}
|
|
43
|
+
await executeVerb(async (ctx) => sentimentSpec.handler({ scope: opts.scope }, ctx));
|
|
44
|
+
});
|
|
45
|
+
return cmd;
|
|
46
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `echopai views ...` + MCP tool `views`.
|
|
3
|
+
*
|
|
4
|
+
* PRIMARY research source (feedback_views_over_news.md).
|
|
5
|
+
*/
|
|
6
|
+
import { Command, Option } from "commander";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { OPERATIONS } from "../_generated/operations.js";
|
|
9
|
+
import { executeVerb, emitVerbError } from "../runtime/verb_cmd.js";
|
|
10
|
+
import { callOp } from "../runtime/verb_runner.js";
|
|
11
|
+
export const viewsSpec = {
|
|
12
|
+
name: "views",
|
|
13
|
+
description: "PRIMARY research source for stock judgement: analyst views / sell-side reports / long-form opinion stream, with research_entity_id attribution (use `research` verb to query hit-rate). Prefer this over `news` when forming an investment opinion.",
|
|
14
|
+
inputSchema: {
|
|
15
|
+
code: z
|
|
16
|
+
.string()
|
|
17
|
+
.regex(/^(SSE|SZSE|BSE|SH|SZ|BJ):[0-9]{6}$/)
|
|
18
|
+
.optional()
|
|
19
|
+
.describe("Filter by security canonical_code (e.g. SSE:600519)"),
|
|
20
|
+
analyst: z.string().optional().describe("Analyst Chinese name (exact / fuzzy)"),
|
|
21
|
+
institution: z.string().optional().describe("Broker / institution Chinese name"),
|
|
22
|
+
since_days: z
|
|
23
|
+
.number()
|
|
24
|
+
.int()
|
|
25
|
+
.min(1)
|
|
26
|
+
.max(90)
|
|
27
|
+
.default(7)
|
|
28
|
+
.describe("Lookback window in days (research time-horizon is longer than news)"),
|
|
29
|
+
limit: z.number().int().min(1).max(100).default(30).describe("Max items"),
|
|
30
|
+
},
|
|
31
|
+
handler: async (args, ctx) => {
|
|
32
|
+
const op = OPERATIONS["views.recent"];
|
|
33
|
+
if (!op)
|
|
34
|
+
throw new Error("views.recent op missing from codegen");
|
|
35
|
+
const callArgs = {
|
|
36
|
+
since_days: args.since_days,
|
|
37
|
+
limit: args.limit,
|
|
38
|
+
};
|
|
39
|
+
if (args.code)
|
|
40
|
+
callArgs.security = args.code;
|
|
41
|
+
if (args.analyst)
|
|
42
|
+
callArgs.analyst = args.analyst;
|
|
43
|
+
if (args.institution)
|
|
44
|
+
callArgs.institution = args.institution;
|
|
45
|
+
return callOp(op, callArgs, ctx);
|
|
46
|
+
},
|
|
47
|
+
backingOps: ["views.recent"],
|
|
48
|
+
};
|
|
49
|
+
function clamp(raw, min, max, fallback) {
|
|
50
|
+
const n = Math.floor(Number(raw));
|
|
51
|
+
if (!Number.isFinite(n))
|
|
52
|
+
return fallback;
|
|
53
|
+
if (n < min)
|
|
54
|
+
return min;
|
|
55
|
+
if (n > max)
|
|
56
|
+
return max;
|
|
57
|
+
return n;
|
|
58
|
+
}
|
|
59
|
+
export function buildViewsCommand() {
|
|
60
|
+
const cmd = new Command(viewsSpec.name).description(viewsSpec.description);
|
|
61
|
+
cmd.addOption(new Option("--code <canonical_code>", "Filter by security canonical_code"));
|
|
62
|
+
cmd.addOption(new Option("--analyst <name>", "Analyst Chinese name (exact / fuzzy)"));
|
|
63
|
+
cmd.addOption(new Option("--institution <name>", "Broker / institution Chinese name"));
|
|
64
|
+
cmd.addOption(new Option("--since-days <n>", "Lookback window (1-90 days)").default("7"));
|
|
65
|
+
cmd.addOption(new Option("--limit <n>", "Max items (1-100)").default("30"));
|
|
66
|
+
cmd.action(async (opts) => {
|
|
67
|
+
if (!OPERATIONS["views.recent"]) {
|
|
68
|
+
emitVerbError("internal_error", "views.recent missing from codegen", undefined, 2);
|
|
69
|
+
}
|
|
70
|
+
const args = {
|
|
71
|
+
since_days: clamp(opts.sinceDays, 1, 90, 7),
|
|
72
|
+
limit: clamp(opts.limit, 1, 100, 30),
|
|
73
|
+
};
|
|
74
|
+
if (opts.code)
|
|
75
|
+
args.code = opts.code;
|
|
76
|
+
if (opts.analyst)
|
|
77
|
+
args.analyst = opts.analyst;
|
|
78
|
+
if (opts.institution)
|
|
79
|
+
args.institution = opts.institution;
|
|
80
|
+
await executeVerb(async (ctx) => viewsSpec.handler(args, ctx));
|
|
81
|
+
});
|
|
82
|
+
return cmd;
|
|
83
|
+
}
|
package/dist/version.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "echopai",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Command-line interface for the EchoPai Open Platform: stock-market data, news, analyst views, sentiment, signals, backtests.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://echopai.com",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/evanzhangx/EchoPulse.git",
|
|
10
|
+
"directory": "cli"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"echopai",
|
|
14
|
+
"stock-market",
|
|
15
|
+
"ai",
|
|
16
|
+
"agent",
|
|
17
|
+
"cli",
|
|
18
|
+
"openapi"
|
|
19
|
+
],
|
|
20
|
+
"type": "module",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=20"
|
|
23
|
+
},
|
|
24
|
+
"bin": {
|
|
25
|
+
"echopai": "dist/bin.js"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"codegen": "cd .. && (test -x scripts/codegen/.venv/bin/python || (python3 -m venv scripts/codegen/.venv && scripts/codegen/.venv/bin/pip install -q -r scripts/codegen/requirements.txt)) && scripts/codegen/.venv/bin/python scripts/codegen/generate_cli_v2.py --in docs/api-contract/openapi.yaml --out cli/src/_generated",
|
|
33
|
+
"prebuild": "npm run codegen",
|
|
34
|
+
"build": "tsc",
|
|
35
|
+
"pretest": "npm run codegen",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"test:watch": "vitest",
|
|
38
|
+
"dev": "npm run codegen && tsx src/bin.ts",
|
|
39
|
+
"prepublishOnly": "npm run build"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
43
|
+
"ajv": "^8.17.1",
|
|
44
|
+
"ajv-formats": "^3.0.1",
|
|
45
|
+
"commander": "^12.1.0",
|
|
46
|
+
"jmespath": "^0.16.0",
|
|
47
|
+
"smol-toml": "^1.4.2",
|
|
48
|
+
"undici": "^7.16.0",
|
|
49
|
+
"zod": "^4.4.3"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/jmespath": "^0.15.2",
|
|
53
|
+
"@types/node": "^20.0.0",
|
|
54
|
+
"tsx": "^4.20.6",
|
|
55
|
+
"typescript": "^5.6.3",
|
|
56
|
+
"vitest": "^2.1.9"
|
|
57
|
+
}
|
|
58
|
+
}
|