@zhanngning/hecode 0.7.0 → 1.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 +13 -270
- package/bin/hecode +2 -0
- package/dist/index.js +103 -14705
- package/package.json +20 -38
- package/dist/chunk-5WRI5ZAA.js +0 -31
- package/dist/chunk-5WRI5ZAA.js.map +0 -1
- package/dist/chunk-I4W33CWB.js +0 -670
- package/dist/chunk-I4W33CWB.js.map +0 -1
- package/dist/chunk-YTG4MQHX.js +0 -10177
- package/dist/chunk-YTG4MQHX.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/node-JCJZZBSH.js +0 -872
- package/dist/node-JCJZZBSH.js.map +0 -1
- package/dist/orchestrator-2GXELO2X.js +0 -8
- package/dist/orchestrator-2GXELO2X.js.map +0 -1
- package/skills/code-review/SKILL.md +0 -69
- package/skills/coding/SKILL.md +0 -11
- package/skills/content/SKILL.md +0 -77
- package/skills/data-analysis/SKILL.md +0 -76
- package/skills/docs/SKILL.md +0 -63
- package/skills/explain/SKILL.md +0 -67
- package/skills/finance/SKILL.md +0 -51
- package/skills/git/SKILL.md +0 -81
- package/skills/perf/SKILL.md +0 -89
- package/skills/planning/SKILL.md +0 -84
- package/skills/ppt/SKILL.md +0 -47
- package/skills/refactor/SKILL.md +0 -73
- package/skills/security/SKILL.md +0 -86
- package/skills/testing/SKILL.md +0 -36
- package/skills/translate/SKILL.md +0 -75
package/dist/chunk-I4W33CWB.js
DELETED
|
@@ -1,670 +0,0 @@
|
|
|
1
|
-
// src/tools/read_file.ts
|
|
2
|
-
import { readFile } from "fs/promises";
|
|
3
|
-
var readFileTool = {
|
|
4
|
-
name: "read_file",
|
|
5
|
-
description: "Read file content. Supports offset and limit for large files.",
|
|
6
|
-
parameters: {
|
|
7
|
-
type: "object",
|
|
8
|
-
properties: {
|
|
9
|
-
file_path: { type: "string", description: "Absolute path to the file" },
|
|
10
|
-
offset: { type: "number", description: "Line number to start from (1-indexed)" },
|
|
11
|
-
limit: { type: "number", description: "Max lines to read (default 2000)" }
|
|
12
|
-
},
|
|
13
|
-
required: ["file_path"]
|
|
14
|
-
},
|
|
15
|
-
async execute(params) {
|
|
16
|
-
try {
|
|
17
|
-
const content = await readFile(params.file_path, "utf-8");
|
|
18
|
-
const lines = content.split("\n");
|
|
19
|
-
const offset = params.offset || 1;
|
|
20
|
-
const limit = params.limit || 2e3;
|
|
21
|
-
const sliced = lines.slice(offset - 1, offset - 1 + limit);
|
|
22
|
-
const numbered = sliced.map((line, i) => `${offset + i}: ${line}`).join("\n");
|
|
23
|
-
return { output: numbered };
|
|
24
|
-
} catch (e) {
|
|
25
|
-
return { output: "", error: e.message };
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// src/tools/write_file.ts
|
|
31
|
-
import { writeFile, mkdir } from "fs/promises";
|
|
32
|
-
import { dirname } from "path";
|
|
33
|
-
var writeFileTool = {
|
|
34
|
-
name: "write_file",
|
|
35
|
-
description: "Write content to a file. Creates parent directories if needed.",
|
|
36
|
-
parameters: {
|
|
37
|
-
type: "object",
|
|
38
|
-
properties: {
|
|
39
|
-
file_path: { type: "string", description: "Absolute path to the file" },
|
|
40
|
-
content: { type: "string", description: "Content to write" }
|
|
41
|
-
},
|
|
42
|
-
required: ["file_path", "content"]
|
|
43
|
-
},
|
|
44
|
-
async execute(params) {
|
|
45
|
-
try {
|
|
46
|
-
await mkdir(dirname(params.file_path), { recursive: true });
|
|
47
|
-
await writeFile(params.file_path, params.content, "utf-8");
|
|
48
|
-
return { output: `File written: ${params.file_path}` };
|
|
49
|
-
} catch (e) {
|
|
50
|
-
return { output: "", error: e.message };
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// src/tools/edit_file.ts
|
|
56
|
-
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
57
|
-
var editFileTool = {
|
|
58
|
-
name: "edit_file",
|
|
59
|
-
description: "Replace exact string match in a file. Fails if old_string not found or matches multiple times.",
|
|
60
|
-
parameters: {
|
|
61
|
-
type: "object",
|
|
62
|
-
properties: {
|
|
63
|
-
file_path: { type: "string", description: "Absolute path to the file" },
|
|
64
|
-
old_string: { type: "string", description: "Exact string to replace" },
|
|
65
|
-
new_string: { type: "string", description: "Replacement string" },
|
|
66
|
-
replace_all: { type: "boolean", description: "Replace all occurrences (default false)" }
|
|
67
|
-
},
|
|
68
|
-
required: ["file_path", "old_string", "new_string"]
|
|
69
|
-
},
|
|
70
|
-
async execute(params) {
|
|
71
|
-
try {
|
|
72
|
-
const content = await readFile2(params.file_path, "utf-8");
|
|
73
|
-
const oldStr = params.old_string;
|
|
74
|
-
const newStr = params.new_string;
|
|
75
|
-
const replaceAll = params.replace_all;
|
|
76
|
-
if (!content.includes(oldStr)) {
|
|
77
|
-
return { output: "", error: `old_string not found in ${params.file_path}` };
|
|
78
|
-
}
|
|
79
|
-
let result;
|
|
80
|
-
if (replaceAll) {
|
|
81
|
-
result = content.replaceAll(oldStr, newStr);
|
|
82
|
-
} else {
|
|
83
|
-
const count = content.split(oldStr).length - 1;
|
|
84
|
-
if (count > 1) {
|
|
85
|
-
return {
|
|
86
|
-
output: "",
|
|
87
|
-
error: `Found ${count} matches for old_string. Provide more context or set replace_all=true.`
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
result = content.replace(oldStr, newStr);
|
|
91
|
-
}
|
|
92
|
-
await writeFile2(params.file_path, result, "utf-8");
|
|
93
|
-
return { output: `Edited: ${params.file_path}` };
|
|
94
|
-
} catch (e) {
|
|
95
|
-
return { output: "", error: e.message };
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
// src/tools/bash.ts
|
|
101
|
-
import { exec } from "child_process";
|
|
102
|
-
var bashTool = {
|
|
103
|
-
name: "bash",
|
|
104
|
-
description: "Execute a shell command. Returns stdout and stderr.",
|
|
105
|
-
parameters: {
|
|
106
|
-
type: "object",
|
|
107
|
-
properties: {
|
|
108
|
-
command: { type: "string", description: "The command to execute" },
|
|
109
|
-
timeout: { type: "number", description: "Timeout in ms (default 120000)" },
|
|
110
|
-
workdir: { type: "string", description: "Working directory" }
|
|
111
|
-
},
|
|
112
|
-
required: ["command"]
|
|
113
|
-
},
|
|
114
|
-
async execute(params) {
|
|
115
|
-
return new Promise((resolve) => {
|
|
116
|
-
const timeout = params.timeout || 12e4;
|
|
117
|
-
exec(
|
|
118
|
-
params.command,
|
|
119
|
-
{
|
|
120
|
-
timeout,
|
|
121
|
-
cwd: params.workdir || process.cwd(),
|
|
122
|
-
encoding: "utf-8"
|
|
123
|
-
},
|
|
124
|
-
(error, stdout, stderr) => {
|
|
125
|
-
if (error && error.killed) {
|
|
126
|
-
resolve({
|
|
127
|
-
output: stdout ?? "",
|
|
128
|
-
error: `Command timed out after ${timeout}ms`
|
|
129
|
-
});
|
|
130
|
-
} else if (error && !stdout && !stderr) {
|
|
131
|
-
resolve({ output: "", error: error.message });
|
|
132
|
-
} else {
|
|
133
|
-
resolve({ output: [stdout, stderr].filter(Boolean).join("\n").trim() });
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
);
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
// src/tools/glob.ts
|
|
142
|
-
import { glob } from "fs/promises";
|
|
143
|
-
var globTool = {
|
|
144
|
-
name: "glob",
|
|
145
|
-
description: "Find files matching a glob pattern.",
|
|
146
|
-
parameters: {
|
|
147
|
-
type: "object",
|
|
148
|
-
properties: {
|
|
149
|
-
pattern: {
|
|
150
|
-
type: "string",
|
|
151
|
-
description: "Glob pattern (e.g. '**/*.ts', 'src/**/*.test.*')"
|
|
152
|
-
},
|
|
153
|
-
path: { type: "string", description: "Directory to search in (default: cwd)" }
|
|
154
|
-
},
|
|
155
|
-
required: ["pattern"]
|
|
156
|
-
},
|
|
157
|
-
async execute(params) {
|
|
158
|
-
try {
|
|
159
|
-
const files = [];
|
|
160
|
-
for await (const f of glob(params.pattern, {
|
|
161
|
-
cwd: params.path || process.cwd()
|
|
162
|
-
})) {
|
|
163
|
-
files.push(f);
|
|
164
|
-
}
|
|
165
|
-
files.sort();
|
|
166
|
-
return { output: files.join("\n") || "No files found" };
|
|
167
|
-
} catch (e) {
|
|
168
|
-
return { output: "", error: e.message };
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
// src/tools/grep.ts
|
|
174
|
-
import { readFile as readFile3, readdir } from "fs/promises";
|
|
175
|
-
import { join } from "path";
|
|
176
|
-
var grepTool = {
|
|
177
|
-
name: "grep",
|
|
178
|
-
description: "Search file contents using regex. Returns file paths and matching line numbers.",
|
|
179
|
-
parameters: {
|
|
180
|
-
type: "object",
|
|
181
|
-
properties: {
|
|
182
|
-
pattern: { type: "string", description: "Regex pattern to search for" },
|
|
183
|
-
path: { type: "string", description: "Directory to search in (default: cwd)" },
|
|
184
|
-
include: { type: "string", description: "File pattern to include (e.g. '*.ts')" }
|
|
185
|
-
},
|
|
186
|
-
required: ["pattern"]
|
|
187
|
-
},
|
|
188
|
-
async execute(params) {
|
|
189
|
-
try {
|
|
190
|
-
const regex = new RegExp(params.pattern, "gi");
|
|
191
|
-
const rootDir = params.path || process.cwd();
|
|
192
|
-
const includePattern = params.include;
|
|
193
|
-
const results = [];
|
|
194
|
-
async function searchDir(dir, depth) {
|
|
195
|
-
if (depth > 10 || results.length >= 200) return;
|
|
196
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
197
|
-
for (const entry of entries) {
|
|
198
|
-
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
199
|
-
const fullPath = join(dir, entry.name);
|
|
200
|
-
if (entry.isDirectory()) {
|
|
201
|
-
await searchDir(fullPath, depth + 1);
|
|
202
|
-
} else if (entry.isFile()) {
|
|
203
|
-
if (includePattern && !matchGlob(entry.name, includePattern)) continue;
|
|
204
|
-
try {
|
|
205
|
-
const content = await readFile3(fullPath, "utf-8");
|
|
206
|
-
const lines = content.split("\n");
|
|
207
|
-
for (let i = 0; i < lines.length; i++) {
|
|
208
|
-
if (regex.test(lines[i])) {
|
|
209
|
-
results.push(`${fullPath}:${i + 1}: ${lines[i].trim()}`);
|
|
210
|
-
if (results.length >= 200) return;
|
|
211
|
-
}
|
|
212
|
-
regex.lastIndex = 0;
|
|
213
|
-
}
|
|
214
|
-
} catch {
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
await searchDir(rootDir, 0);
|
|
220
|
-
return { output: results.join("\n") || "No matches found" };
|
|
221
|
-
} catch (e) {
|
|
222
|
-
return { output: "", error: e.message };
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
};
|
|
226
|
-
function matchGlob(filename, pattern) {
|
|
227
|
-
const regexStr = "^" + pattern.replace(/\*/g, ".*").replace(/\?/g, ".") + "$";
|
|
228
|
-
return new RegExp(regexStr, "i").test(filename);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// src/datasources/akshare.ts
|
|
232
|
-
import { exec as exec2 } from "child_process";
|
|
233
|
-
import { promisify } from "util";
|
|
234
|
-
import path from "path";
|
|
235
|
-
var execAsync = promisify(exec2);
|
|
236
|
-
var AkshareDataSource = class {
|
|
237
|
-
scriptPath;
|
|
238
|
-
constructor() {
|
|
239
|
-
this.scriptPath = path.join(import.meta.dirname, "akshare_datasource.py");
|
|
240
|
-
}
|
|
241
|
-
async getStockInfo(code, market = "A") {
|
|
242
|
-
const { stdout } = await execAsync(
|
|
243
|
-
`python ${this.scriptPath} info ${code} ${market}`
|
|
244
|
-
);
|
|
245
|
-
const data = JSON.parse(stdout);
|
|
246
|
-
if (data.error) throw new Error(data.error);
|
|
247
|
-
return {
|
|
248
|
-
code,
|
|
249
|
-
name: data[0]?.name || code,
|
|
250
|
-
market,
|
|
251
|
-
date: data[0]?.date,
|
|
252
|
-
open: data[0]?.open,
|
|
253
|
-
close: data[0]?.close,
|
|
254
|
-
high: data[0]?.high,
|
|
255
|
-
low: data[0]?.low,
|
|
256
|
-
volume: data[0]?.volume,
|
|
257
|
-
amount: data[0]?.amount,
|
|
258
|
-
change_pct: data[0]?.change_pct
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
async getFinancialData(code, market = "A") {
|
|
262
|
-
const { stdout } = await execAsync(
|
|
263
|
-
`python ${this.scriptPath} financial ${code} ${market}`
|
|
264
|
-
);
|
|
265
|
-
const data = JSON.parse(stdout);
|
|
266
|
-
if (data.error) throw new Error(data.error);
|
|
267
|
-
return {
|
|
268
|
-
code,
|
|
269
|
-
price: data[0]?.price,
|
|
270
|
-
change_pct: data[0]?.change_pct,
|
|
271
|
-
volume: data[0]?.volume,
|
|
272
|
-
amount: data[0]?.amount,
|
|
273
|
-
turnover: data[0]?.turnover
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
async getStockHistory(code, market = "A", days = 30) {
|
|
277
|
-
const { stdout } = await execAsync(
|
|
278
|
-
`python ${this.scriptPath} history ${code} ${market} ${days}`
|
|
279
|
-
);
|
|
280
|
-
const data = JSON.parse(stdout);
|
|
281
|
-
if (data.error) throw new Error(data.error);
|
|
282
|
-
return data.map((item) => ({
|
|
283
|
-
date: item.date,
|
|
284
|
-
open: item.open,
|
|
285
|
-
close: item.close,
|
|
286
|
-
high: item.high,
|
|
287
|
-
low: item.low,
|
|
288
|
-
volume: item.volume,
|
|
289
|
-
change_pct: item.change_pct
|
|
290
|
-
}));
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
// src/workflow/state.ts
|
|
295
|
-
function createInitialState(target) {
|
|
296
|
-
return {
|
|
297
|
-
target,
|
|
298
|
-
data: {},
|
|
299
|
-
analysis: {},
|
|
300
|
-
output: {},
|
|
301
|
-
status: "pending"
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// src/workflow/engine.ts
|
|
306
|
-
var WorkflowEngine = class {
|
|
307
|
-
nodes;
|
|
308
|
-
onStateChange;
|
|
309
|
-
constructor(config) {
|
|
310
|
-
this.nodes = config.nodes;
|
|
311
|
-
this.onStateChange = config.onStateChange;
|
|
312
|
-
}
|
|
313
|
-
async execute(target) {
|
|
314
|
-
let state = createInitialState(target);
|
|
315
|
-
for (const node of this.nodes) {
|
|
316
|
-
state = await node(state);
|
|
317
|
-
this.onStateChange?.(state);
|
|
318
|
-
if (state.status === "error") {
|
|
319
|
-
throw new Error(state.error);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return state;
|
|
323
|
-
}
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
// src/workflow/nodes/data-collection.ts
|
|
327
|
-
async function dataCollectionNode(state, dataSource) {
|
|
328
|
-
const { code, market } = state.target;
|
|
329
|
-
try {
|
|
330
|
-
const [stockInfo, financial, history] = await Promise.all([
|
|
331
|
-
dataSource.getStockInfo(code, market),
|
|
332
|
-
dataSource.getFinancialData(code, market),
|
|
333
|
-
dataSource.getStockHistory(code, market, 30)
|
|
334
|
-
]);
|
|
335
|
-
return {
|
|
336
|
-
...state,
|
|
337
|
-
data: {
|
|
338
|
-
stockInfo,
|
|
339
|
-
financial,
|
|
340
|
-
history
|
|
341
|
-
},
|
|
342
|
-
status: "collecting"
|
|
343
|
-
};
|
|
344
|
-
} catch (error) {
|
|
345
|
-
return {
|
|
346
|
-
...state,
|
|
347
|
-
status: "error",
|
|
348
|
-
error: `\u6570\u636E\u91C7\u96C6\u5931\u8D25: ${error.message}`
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// src/workflow/nodes/analysis.ts
|
|
354
|
-
function calculateMA(data, period) {
|
|
355
|
-
if (data.length < period) return void 0;
|
|
356
|
-
const slice = data.slice(-period);
|
|
357
|
-
return slice.reduce((a, b) => a + b, 0) / period;
|
|
358
|
-
}
|
|
359
|
-
function calculateRSI(prices, period = 14) {
|
|
360
|
-
if (prices.length < period + 1) return void 0;
|
|
361
|
-
let gains = 0;
|
|
362
|
-
let losses = 0;
|
|
363
|
-
for (let i = prices.length - period; i < prices.length; i++) {
|
|
364
|
-
const change = prices[i] - prices[i - 1];
|
|
365
|
-
if (change > 0) {
|
|
366
|
-
gains += change;
|
|
367
|
-
} else {
|
|
368
|
-
losses -= change;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
const avgGain = gains / period;
|
|
372
|
-
const avgLoss = losses / period;
|
|
373
|
-
if (avgLoss === 0) return 100;
|
|
374
|
-
const rs = avgGain / avgLoss;
|
|
375
|
-
return 100 - 100 / (1 + rs);
|
|
376
|
-
}
|
|
377
|
-
async function analysisNode(state) {
|
|
378
|
-
if (state.status === "error") return state;
|
|
379
|
-
const { financial, history, stockInfo } = state.data;
|
|
380
|
-
try {
|
|
381
|
-
const prices = history?.map((h) => h.close) || [];
|
|
382
|
-
const ma5 = calculateMA(prices, 5);
|
|
383
|
-
const ma10 = calculateMA(prices, 10);
|
|
384
|
-
const ma20 = calculateMA(prices, 20);
|
|
385
|
-
const rsi = calculateRSI(prices);
|
|
386
|
-
const financialAnalysis = {
|
|
387
|
-
price: financial?.price,
|
|
388
|
-
change_pct: financial?.change_pct,
|
|
389
|
-
volume: financial?.volume,
|
|
390
|
-
amount: financial?.amount,
|
|
391
|
-
turnover: financial?.turnover
|
|
392
|
-
};
|
|
393
|
-
const trend = {
|
|
394
|
-
ma5: ma5 ? Math.round(ma5 * 100) / 100 : void 0,
|
|
395
|
-
ma10: ma10 ? Math.round(ma10 * 100) / 100 : void 0,
|
|
396
|
-
ma20: ma20 ? Math.round(ma20 * 100) / 100 : void 0,
|
|
397
|
-
rsi: rsi ? Math.round(rsi * 100) / 100 : void 0
|
|
398
|
-
};
|
|
399
|
-
let trendSignal = "\u4E2D\u6027";
|
|
400
|
-
if (ma5 && ma10 && ma20) {
|
|
401
|
-
if (ma5 > ma10 && ma10 > ma20) {
|
|
402
|
-
trendSignal = "\u4E0A\u5347\u8D8B\u52BF";
|
|
403
|
-
} else if (ma5 < ma10 && ma10 < ma20) {
|
|
404
|
-
trendSignal = "\u4E0B\u964D\u8D8B\u52BF";
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
return {
|
|
408
|
-
...state,
|
|
409
|
-
analysis: {
|
|
410
|
-
financial: financialAnalysis,
|
|
411
|
-
trend,
|
|
412
|
-
comparison: {
|
|
413
|
-
industry: stockInfo?.industry || "\u672A\u77E5",
|
|
414
|
-
trendSignal
|
|
415
|
-
}
|
|
416
|
-
},
|
|
417
|
-
status: "analyzing"
|
|
418
|
-
};
|
|
419
|
-
} catch (error) {
|
|
420
|
-
return {
|
|
421
|
-
...state,
|
|
422
|
-
status: "error",
|
|
423
|
-
error: `\u5206\u6790\u5931\u8D25: ${error.message}`
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// src/workflow/nodes/report.ts
|
|
429
|
-
async function reportNode(state) {
|
|
430
|
-
if (state.status === "error") return state;
|
|
431
|
-
const { target, analysis, data } = state;
|
|
432
|
-
try {
|
|
433
|
-
const report = `# ${target.company} (${target.code}) \u7814\u7A76\u62A5\u544A
|
|
434
|
-
|
|
435
|
-
## \u516C\u53F8\u6982\u51B5
|
|
436
|
-
- **\u80A1\u7968\u4EE3\u7801**: ${target.code}
|
|
437
|
-
- **\u5E02\u573A**: ${target.market}
|
|
438
|
-
- **\u884C\u4E1A**: ${analysis.comparison?.industry || "\u672A\u77E5"}
|
|
439
|
-
|
|
440
|
-
## \u4EF7\u683C\u4FE1\u606F
|
|
441
|
-
- **\u5F53\u524D\u4EF7\u683C**: \xA5${analysis.financial?.price || "N/A"}
|
|
442
|
-
- **\u6DA8\u8DCC\u5E45**: ${analysis.financial?.change_pct || "N/A"}%
|
|
443
|
-
- **\u6210\u4EA4\u91CF**: ${analysis.financial?.volume ? (analysis.financial.volume / 1e4).toFixed(2) + "\u4E07\u624B" : "N/A"}
|
|
444
|
-
- **\u6210\u4EA4\u989D**: ${analysis.financial?.amount ? (analysis.financial.amount / 1e8).toFixed(2) + "\u4EBF" : "N/A"}
|
|
445
|
-
|
|
446
|
-
## \u6280\u672F\u5206\u6790
|
|
447
|
-
- **5\u65E5\u5747\u7EBF**: \xA5${analysis.trend?.ma5 || "N/A"}
|
|
448
|
-
- **10\u65E5\u5747\u7EBF**: \xA5${analysis.trend?.ma10 || "N/A"}
|
|
449
|
-
- **20\u65E5\u5747\u7EBF**: \xA5${analysis.trend?.ma20 || "N/A"}
|
|
450
|
-
- **RSI(14)**: ${analysis.trend?.rsi || "N/A"}
|
|
451
|
-
- **\u8D8B\u52BF\u4FE1\u53F7**: ${analysis.comparison?.trendSignal || "\u4E2D\u6027"}
|
|
452
|
-
|
|
453
|
-
## \u8FD1\u671F\u8D70\u52BF
|
|
454
|
-
${data.history ? data.history.slice(-5).map(
|
|
455
|
-
(h) => `- ${h.date}: \u5F00\u76D8 \xA5${h.open} | \u6536\u76D8 \xA5${h.close} | \u6DA8\u8DCC ${h.change_pct}%`
|
|
456
|
-
).join("\n") : "\u65E0\u6570\u636E"}
|
|
457
|
-
|
|
458
|
-
## \u6295\u8D44\u5EFA\u8BAE
|
|
459
|
-
\u57FA\u4E8E\u6280\u672F\u5206\u6790\uFF0C${target.company} \u5F53\u524D\u5904\u4E8E **${analysis.comparison?.trendSignal || "\u4E2D\u6027"}**\u3002
|
|
460
|
-
|
|
461
|
-
${analysis.trend?.rsi && analysis.trend.rsi > 70 ? "\u26A0\uFE0F RSI \u8D85\u4E70\u533A\u57DF\uFF0C\u6CE8\u610F\u56DE\u8C03\u98CE\u9669" : ""}
|
|
462
|
-
${analysis.trend?.rsi && analysis.trend.rsi < 30 ? "\u2705 RSI \u8D85\u5356\u533A\u57DF\uFF0C\u53EF\u80FD\u5B58\u5728\u53CD\u5F39\u673A\u4F1A" : ""}
|
|
463
|
-
|
|
464
|
-
---
|
|
465
|
-
*\u62A5\u544A\u751F\u6210\u65F6\u95F4: ${(/* @__PURE__ */ new Date()).toISOString()}*
|
|
466
|
-
*\u6570\u636E\u6765\u6E90: akshare (\u514D\u8D39\u6570\u636E)*
|
|
467
|
-
`;
|
|
468
|
-
return {
|
|
469
|
-
...state,
|
|
470
|
-
output: {
|
|
471
|
-
report,
|
|
472
|
-
format: "markdown"
|
|
473
|
-
},
|
|
474
|
-
status: "done"
|
|
475
|
-
};
|
|
476
|
-
} catch (error) {
|
|
477
|
-
return {
|
|
478
|
-
...state,
|
|
479
|
-
status: "error",
|
|
480
|
-
error: `\u62A5\u544A\u751F\u6210\u5931\u8D25: ${error.message}`
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
// src/tools/finance.ts
|
|
486
|
-
var financeTool = {
|
|
487
|
-
name: "finance_analyze",
|
|
488
|
-
description: "\u5206\u6790\u4E0A\u5E02\u516C\u53F8\u8D22\u52A1\u6570\u636E\u5E76\u751F\u6210\u7814\u7A76\u62A5\u544A",
|
|
489
|
-
parameters: {
|
|
490
|
-
type: "object",
|
|
491
|
-
properties: {
|
|
492
|
-
company: {
|
|
493
|
-
type: "string",
|
|
494
|
-
description: "\u516C\u53F8\u540D\u79F0"
|
|
495
|
-
},
|
|
496
|
-
code: {
|
|
497
|
-
type: "string",
|
|
498
|
-
description: "\u80A1\u7968\u4EE3\u7801"
|
|
499
|
-
},
|
|
500
|
-
market: {
|
|
501
|
-
type: "string",
|
|
502
|
-
enum: ["A", "HK"],
|
|
503
|
-
description: "\u5E02\u573A\u7C7B\u578B (A: A\u80A1, HK: \u6E2F\u80A1)"
|
|
504
|
-
}
|
|
505
|
-
},
|
|
506
|
-
required: ["company", "code"]
|
|
507
|
-
},
|
|
508
|
-
execute: async (params) => {
|
|
509
|
-
try {
|
|
510
|
-
const dataSource = new AkshareDataSource();
|
|
511
|
-
const engine = new WorkflowEngine({
|
|
512
|
-
nodes: [
|
|
513
|
-
(state) => dataCollectionNode(state, dataSource),
|
|
514
|
-
analysisNode,
|
|
515
|
-
reportNode
|
|
516
|
-
]
|
|
517
|
-
});
|
|
518
|
-
const result = await engine.execute({
|
|
519
|
-
company: params.company,
|
|
520
|
-
code: params.code,
|
|
521
|
-
market: params.market || "A"
|
|
522
|
-
});
|
|
523
|
-
return {
|
|
524
|
-
output: result.output.report || "\u5206\u6790\u5B8C\u6210"
|
|
525
|
-
};
|
|
526
|
-
} catch (error) {
|
|
527
|
-
return {
|
|
528
|
-
output: "",
|
|
529
|
-
error: error.message
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
};
|
|
534
|
-
|
|
535
|
-
// src/tools/index.ts
|
|
536
|
-
var builtinTools = [
|
|
537
|
-
readFileTool,
|
|
538
|
-
writeFileTool,
|
|
539
|
-
editFileTool,
|
|
540
|
-
bashTool,
|
|
541
|
-
globTool,
|
|
542
|
-
grepTool,
|
|
543
|
-
financeTool
|
|
544
|
-
];
|
|
545
|
-
|
|
546
|
-
// src/core/orchestrator.ts
|
|
547
|
-
var Orchestrator = class {
|
|
548
|
-
messages = [];
|
|
549
|
-
tools;
|
|
550
|
-
model;
|
|
551
|
-
systemPrompt;
|
|
552
|
-
maxIterations;
|
|
553
|
-
callbacks;
|
|
554
|
-
constructor(opts) {
|
|
555
|
-
this.model = opts.model;
|
|
556
|
-
this.systemPrompt = opts.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
557
|
-
if (opts.skillInstructions) {
|
|
558
|
-
this.systemPrompt += "\n\n" + opts.skillInstructions;
|
|
559
|
-
}
|
|
560
|
-
this.tools = opts.tools ?? builtinTools;
|
|
561
|
-
this.maxIterations = opts.maxIterations ?? 20;
|
|
562
|
-
this.callbacks = {
|
|
563
|
-
onToken: opts.onToken,
|
|
564
|
-
onToolStart: opts.onToolStart,
|
|
565
|
-
onToolEnd: opts.onToolEnd
|
|
566
|
-
};
|
|
567
|
-
if (this.systemPrompt) {
|
|
568
|
-
this.messages.push({ role: "system", content: this.systemPrompt });
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
async run(userMessage) {
|
|
572
|
-
this.messages.push({ role: "user", content: userMessage });
|
|
573
|
-
for (let i = 0; i < this.maxIterations; i++) {
|
|
574
|
-
const response = await this.model.chat(this.messages, this.tools);
|
|
575
|
-
if (response.content) {
|
|
576
|
-
this.messages.push({
|
|
577
|
-
role: "assistant",
|
|
578
|
-
content: response.content,
|
|
579
|
-
tool_calls: response.tool_calls
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
if (!response.tool_calls?.length) {
|
|
583
|
-
return response.content;
|
|
584
|
-
}
|
|
585
|
-
for (const tc of response.tool_calls) {
|
|
586
|
-
this.callbacks.onToolStart?.(
|
|
587
|
-
tc.function.name,
|
|
588
|
-
JSON.parse(tc.function.arguments)
|
|
589
|
-
);
|
|
590
|
-
const result = await this.executeTool(tc);
|
|
591
|
-
this.callbacks.onToolEnd?.(tc.function.name, result);
|
|
592
|
-
this.messages.push({
|
|
593
|
-
role: "tool",
|
|
594
|
-
content: result.error ? `Error: ${result.error}` : result.output,
|
|
595
|
-
tool_call_id: tc.id
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
return "Max iterations reached.";
|
|
600
|
-
}
|
|
601
|
-
async *runStream(userMessage) {
|
|
602
|
-
this.messages.push({ role: "user", content: userMessage });
|
|
603
|
-
for (let i = 0; i < this.maxIterations; i++) {
|
|
604
|
-
let fullContent = "";
|
|
605
|
-
let toolCalls = [];
|
|
606
|
-
for await (const chunk of this.model.stream(this.messages, this.tools)) {
|
|
607
|
-
if (chunk.content) {
|
|
608
|
-
fullContent += chunk.content;
|
|
609
|
-
yield chunk.content;
|
|
610
|
-
}
|
|
611
|
-
if (chunk.tool_calls) {
|
|
612
|
-
toolCalls = chunk.tool_calls;
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
if (!toolCalls.length) {
|
|
616
|
-
this.messages.push({ role: "assistant", content: fullContent });
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
this.messages.push({
|
|
620
|
-
role: "assistant",
|
|
621
|
-
content: fullContent,
|
|
622
|
-
tool_calls: toolCalls
|
|
623
|
-
});
|
|
624
|
-
for (const tc of toolCalls) {
|
|
625
|
-
this.callbacks.onToolStart?.(
|
|
626
|
-
tc.function.name,
|
|
627
|
-
JSON.parse(tc.function.arguments)
|
|
628
|
-
);
|
|
629
|
-
const result = await this.executeTool(tc);
|
|
630
|
-
this.callbacks.onToolEnd?.(tc.function.name, result);
|
|
631
|
-
this.messages.push({
|
|
632
|
-
role: "tool",
|
|
633
|
-
content: result.error ? `Error: ${result.error}` : result.output,
|
|
634
|
-
tool_call_id: tc.id
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
async executeTool(tc) {
|
|
640
|
-
const tool = this.tools.find((t) => t.name === tc.function.name);
|
|
641
|
-
if (!tool) return { output: "", error: `Unknown tool: ${tc.function.name}` };
|
|
642
|
-
try {
|
|
643
|
-
const params = JSON.parse(tc.function.arguments);
|
|
644
|
-
return await tool.execute(params);
|
|
645
|
-
} catch (e) {
|
|
646
|
-
return { output: "", error: e.message };
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
getMessages() {
|
|
650
|
-
return [...this.messages];
|
|
651
|
-
}
|
|
652
|
-
clearMessages() {
|
|
653
|
-
this.messages = [];
|
|
654
|
-
if (this.systemPrompt) {
|
|
655
|
-
this.messages.push({ role: "system", content: this.systemPrompt });
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
};
|
|
659
|
-
var DEFAULT_SYSTEM_PROMPT = `You are Hecode, an AI coding assistant. You help users with software engineering tasks using the tools available to you.
|
|
660
|
-
|
|
661
|
-
Key principles:
|
|
662
|
-
- Be concise and direct
|
|
663
|
-
- Use tools to read/write files, execute commands, and search code
|
|
664
|
-
- Verify your work by running tests or checks when possible
|
|
665
|
-
- Follow existing code conventions in the project`;
|
|
666
|
-
|
|
667
|
-
export {
|
|
668
|
-
Orchestrator
|
|
669
|
-
};
|
|
670
|
-
//# sourceMappingURL=chunk-I4W33CWB.js.map
|