@zhanngning/hecode 0.1.0 → 0.2.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 +52 -1
- package/dist/{chunk-ECQ3AREB.js → chunk-I4W33CWB.js} +307 -2
- package/dist/chunk-I4W33CWB.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/orchestrator-QX3OE4IN.js +7 -0
- package/package.json +20 -3
- package/skills/coding/SKILL.md +11 -0
- package/skills/finance/SKILL.md +51 -0
- package/dist/chunk-ECQ3AREB.js.map +0 -1
- package/dist/orchestrator-VEQUC74P.js +0 -7
- /package/dist/{orchestrator-VEQUC74P.js.map → orchestrator-QX3OE4IN.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Hecode
|
|
2
2
|
|
|
3
|
-
Your AI Coding Assistant CLI.
|
|
3
|
+
Your AI Coding Assistant CLI with Financial Analysis.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -9,6 +9,7 @@ Your AI Coding Assistant CLI.
|
|
|
9
9
|
- **Skill System**: Loadable domain skills (coding, data analysis, finance, etc.)
|
|
10
10
|
- **Memory System**: Session, project, and global memory with search
|
|
11
11
|
- **Interactive REPL**: Streaming output, slash commands, tool status display
|
|
12
|
+
- **Financial Analysis**: Stock analysis, technical indicators, research reports
|
|
12
13
|
|
|
13
14
|
## Install
|
|
14
15
|
|
|
@@ -68,6 +69,56 @@ Edit `~/.hecode/config.json`:
|
|
|
68
69
|
| `bash` | Execute shell commands |
|
|
69
70
|
| `glob` | File pattern matching |
|
|
70
71
|
| `grep` | Content regex search |
|
|
72
|
+
| `finance_analyze` | Financial analysis and research reports |
|
|
73
|
+
|
|
74
|
+
## Financial Analysis
|
|
75
|
+
|
|
76
|
+
Analyze stocks and generate research reports using free data sources.
|
|
77
|
+
|
|
78
|
+
### Usage
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Interactive mode with finance skill
|
|
82
|
+
hecode --skill finance "分析贵州茅台"
|
|
83
|
+
|
|
84
|
+
# Direct tool call
|
|
85
|
+
hecode "分析股票 600519"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Features
|
|
89
|
+
|
|
90
|
+
- **Price Analysis**: Current price, change percentage, volume
|
|
91
|
+
- **Technical Indicators**: MA5, MA10, MA20, RSI(14)
|
|
92
|
+
- **Trend Detection**: Uptrend, downtrend, or neutral
|
|
93
|
+
- **Research Reports**: Comprehensive Markdown reports
|
|
94
|
+
|
|
95
|
+
### Supported Markets
|
|
96
|
+
|
|
97
|
+
- **A-Shares**: Shanghai and Shenzhen stock exchanges
|
|
98
|
+
- **HK Stocks**: Hong Kong stock exchange
|
|
99
|
+
|
|
100
|
+
### Prerequisites
|
|
101
|
+
|
|
102
|
+
Install Python and akshare:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pip install akshare pandas
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Example Output
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
# 贵州茅台 (600519) 研究报告
|
|
112
|
+
|
|
113
|
+
## 价格信息
|
|
114
|
+
- 当前价格: ¥1168.63
|
|
115
|
+
- 涨跌幅: -1.3%
|
|
116
|
+
|
|
117
|
+
## 技术分析
|
|
118
|
+
- 5日均线: ¥1180.25
|
|
119
|
+
- RSI(14): 45.32
|
|
120
|
+
- 趋势信号: 中性
|
|
121
|
+
```
|
|
71
122
|
|
|
72
123
|
## REPL Commands
|
|
73
124
|
|
|
@@ -228,6 +228,310 @@ function matchGlob(filename, pattern) {
|
|
|
228
228
|
return new RegExp(regexStr, "i").test(filename);
|
|
229
229
|
}
|
|
230
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
|
+
|
|
231
535
|
// src/tools/index.ts
|
|
232
536
|
var builtinTools = [
|
|
233
537
|
readFileTool,
|
|
@@ -235,7 +539,8 @@ var builtinTools = [
|
|
|
235
539
|
editFileTool,
|
|
236
540
|
bashTool,
|
|
237
541
|
globTool,
|
|
238
|
-
grepTool
|
|
542
|
+
grepTool,
|
|
543
|
+
financeTool
|
|
239
544
|
];
|
|
240
545
|
|
|
241
546
|
// src/core/orchestrator.ts
|
|
@@ -362,4 +667,4 @@ Key principles:
|
|
|
362
667
|
export {
|
|
363
668
|
Orchestrator
|
|
364
669
|
};
|
|
365
|
-
//# sourceMappingURL=chunk-
|
|
670
|
+
//# sourceMappingURL=chunk-I4W33CWB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tools/read_file.ts","../src/tools/write_file.ts","../src/tools/edit_file.ts","../src/tools/bash.ts","../src/tools/glob.ts","../src/tools/grep.ts","../src/datasources/akshare.ts","../src/workflow/state.ts","../src/workflow/engine.ts","../src/workflow/nodes/data-collection.ts","../src/workflow/nodes/analysis.ts","../src/workflow/nodes/report.ts","../src/tools/finance.ts","../src/tools/index.ts","../src/core/orchestrator.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const readFileTool: Tool = {\n name: \"read_file\",\n description: \"Read file content. Supports offset and limit for large files.\",\n parameters: {\n type: \"object\",\n properties: {\n file_path: { type: \"string\", description: \"Absolute path to the file\" },\n offset: { type: \"number\", description: \"Line number to start from (1-indexed)\" },\n limit: { type: \"number\", description: \"Max lines to read (default 2000)\" },\n },\n required: [\"file_path\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n const content = await readFile(params.file_path as string, \"utf-8\");\n const lines = content.split(\"\\n\");\n const offset = (params.offset as number) || 1;\n const limit = (params.limit as number) || 2000;\n const sliced = lines.slice(offset - 1, offset - 1 + limit);\n const numbered = sliced.map((line, i) => `${offset + i}: ${line}`).join(\"\\n\");\n return { output: numbered };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n","import { writeFile, mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const writeFileTool: Tool = {\n name: \"write_file\",\n description: \"Write content to a file. Creates parent directories if needed.\",\n parameters: {\n type: \"object\",\n properties: {\n file_path: { type: \"string\", description: \"Absolute path to the file\" },\n content: { type: \"string\", description: \"Content to write\" },\n },\n required: [\"file_path\", \"content\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n await mkdir(dirname(params.file_path as string), { recursive: true });\n await writeFile(params.file_path as string, params.content as string, \"utf-8\");\n return { output: `File written: ${params.file_path}` };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const editFileTool: Tool = {\n name: \"edit_file\",\n description:\n \"Replace exact string match in a file. Fails if old_string not found or matches multiple times.\",\n parameters: {\n type: \"object\",\n properties: {\n file_path: { type: \"string\", description: \"Absolute path to the file\" },\n old_string: { type: \"string\", description: \"Exact string to replace\" },\n new_string: { type: \"string\", description: \"Replacement string\" },\n replace_all: { type: \"boolean\", description: \"Replace all occurrences (default false)\" },\n },\n required: [\"file_path\", \"old_string\", \"new_string\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n const content = await readFile(params.file_path as string, \"utf-8\");\n const oldStr = params.old_string as string;\n const newStr = params.new_string as string;\n const replaceAll = params.replace_all as boolean;\n\n if (!content.includes(oldStr)) {\n return { output: \"\", error: `old_string not found in ${params.file_path}` };\n }\n\n let result: string;\n if (replaceAll) {\n result = content.replaceAll(oldStr, newStr);\n } else {\n const count = content.split(oldStr).length - 1;\n if (count > 1) {\n return {\n output: \"\",\n error: `Found ${count} matches for old_string. Provide more context or set replace_all=true.`,\n };\n }\n result = content.replace(oldStr, newStr);\n }\n\n await writeFile(params.file_path as string, result, \"utf-8\");\n return { output: `Edited: ${params.file_path}` };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n","import { exec } from \"node:child_process\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const bashTool: Tool = {\n name: \"bash\",\n description: \"Execute a shell command. Returns stdout and stderr.\",\n parameters: {\n type: \"object\",\n properties: {\n command: { type: \"string\", description: \"The command to execute\" },\n timeout: { type: \"number\", description: \"Timeout in ms (default 120000)\" },\n workdir: { type: \"string\", description: \"Working directory\" },\n },\n required: [\"command\"],\n },\n async execute(params): Promise<ToolResult> {\n return new Promise((resolve) => {\n const timeout = (params.timeout as number) || 120_000;\n exec(\n params.command as string,\n {\n timeout,\n cwd: (params.workdir as string) || process.cwd(),\n encoding: \"utf-8\",\n },\n (error, stdout, stderr) => {\n if (error && error.killed) {\n resolve({\n output: stdout ?? \"\",\n error: `Command timed out after ${timeout}ms`,\n });\n } else if (error && !stdout && !stderr) {\n resolve({ output: \"\", error: error.message });\n } else {\n resolve({ output: [stdout, stderr].filter(Boolean).join(\"\\n\").trim() });\n }\n },\n );\n });\n },\n};\n","import { glob } from \"node:fs/promises\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const globTool: Tool = {\n name: \"glob\",\n description: \"Find files matching a glob pattern.\",\n parameters: {\n type: \"object\",\n properties: {\n pattern: {\n type: \"string\",\n description: \"Glob pattern (e.g. '**/*.ts', 'src/**/*.test.*')\",\n },\n path: { type: \"string\", description: \"Directory to search in (default: cwd)\" },\n },\n required: [\"pattern\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n const files: string[] = [];\n for await (const f of glob(params.pattern as string, {\n cwd: (params.path as string) || process.cwd(),\n })) {\n files.push(f);\n }\n files.sort();\n return { output: files.join(\"\\n\") || \"No files found\" };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n","import { readFile, readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const grepTool: Tool = {\n name: \"grep\",\n description:\n \"Search file contents using regex. Returns file paths and matching line numbers.\",\n parameters: {\n type: \"object\",\n properties: {\n pattern: { type: \"string\", description: \"Regex pattern to search for\" },\n path: { type: \"string\", description: \"Directory to search in (default: cwd)\" },\n include: { type: \"string\", description: \"File pattern to include (e.g. '*.ts')\" },\n },\n required: [\"pattern\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n const regex = new RegExp(params.pattern as string, \"gi\");\n const rootDir = (params.path as string) || process.cwd();\n const includePattern = params.include as string | undefined;\n const results: string[] = [];\n\n async function searchDir(dir: string, depth: number) {\n if (depth > 10 || results.length >= 200) return;\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue;\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n await searchDir(fullPath, depth + 1);\n } else if (entry.isFile()) {\n if (includePattern && !matchGlob(entry.name, includePattern)) continue;\n try {\n const content = await readFile(fullPath, \"utf-8\");\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (regex.test(lines[i]!)) {\n results.push(`${fullPath}:${i + 1}: ${lines[i]!.trim()}`);\n if (results.length >= 200) return;\n }\n regex.lastIndex = 0;\n }\n } catch {\n /* skip binary/unreadable files */\n }\n }\n }\n }\n\n await searchDir(rootDir, 0);\n return { output: results.join(\"\\n\") || \"No matches found\" };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n\nfunction matchGlob(filename: string, pattern: string): boolean {\n const regexStr = \"^\" + pattern.replace(/\\*/g, \".*\").replace(/\\?/g, \".\") + \"$\";\n return new RegExp(regexStr, \"i\").test(filename);\n}\n","import { exec } from \"child_process\";\nimport { promisify } from \"util\";\nimport path from \"path\";\nimport { DataSource, StockInfo, FinancialData, HistoryData } from \"./index.js\";\n\nconst execAsync = promisify(exec);\n\nexport class AkshareDataSource implements DataSource {\n private scriptPath: string;\n\n constructor() {\n this.scriptPath = path.join(import.meta.dirname, \"akshare_datasource.py\");\n }\n\n async getStockInfo(code: string, market: string = \"A\"): Promise<StockInfo> {\n const { stdout } = await execAsync(\n `python ${this.scriptPath} info ${code} ${market}`\n );\n const data = JSON.parse(stdout);\n if (data.error) throw new Error(data.error);\n \n return {\n code,\n name: data[0]?.name || code,\n market,\n date: data[0]?.date,\n open: data[0]?.open,\n close: data[0]?.close,\n high: data[0]?.high,\n low: data[0]?.low,\n volume: data[0]?.volume,\n amount: data[0]?.amount,\n change_pct: data[0]?.change_pct,\n };\n }\n\n async getFinancialData(code: string, market: string = \"A\"): Promise<FinancialData> {\n const { stdout } = await execAsync(\n `python ${this.scriptPath} financial ${code} ${market}`\n );\n const data = JSON.parse(stdout);\n if (data.error) throw new Error(data.error);\n \n return {\n code,\n price: data[0]?.price,\n change_pct: data[0]?.change_pct,\n volume: data[0]?.volume,\n amount: data[0]?.amount,\n turnover: data[0]?.turnover,\n };\n }\n\n async getStockHistory(code: string, market: string = \"A\", days: number = 30): Promise<HistoryData[]> {\n const { stdout } = await execAsync(\n `python ${this.scriptPath} history ${code} ${market} ${days}`\n );\n const data = JSON.parse(stdout);\n if (data.error) throw new Error(data.error);\n \n return data.map((item: any) => ({\n date: item.date,\n open: item.open,\n close: item.close,\n high: item.high,\n low: item.low,\n volume: item.volume,\n change_pct: item.change_pct,\n }));\n }\n}\n","export interface TargetInfo {\n company: string;\n code: string;\n market: string;\n}\n\nexport interface CollectedData {\n stockInfo?: any;\n financial?: any;\n history?: any[];\n shareholder?: any;\n industry?: any;\n}\n\nexport interface AnalysisResult {\n financial?: {\n revenue?: number;\n netProfit?: number;\n roe?: number;\n growth?: number;\n price?: number;\n change_pct?: number;\n volume?: number;\n amount?: number;\n turnover?: number;\n };\n valuation?: {\n pe?: number;\n pb?: number;\n dcf?: number;\n };\n comparison?: {\n industry?: string;\n peers?: any[];\n trendSignal?: string;\n };\n trend?: {\n ma5?: number;\n ma10?: number;\n ma20?: number;\n rsi?: number;\n macd?: number;\n };\n}\n\nexport interface OutputResult {\n report?: string;\n charts?: string[];\n format?: \"markdown\" | \"word\";\n}\n\nexport interface WorkflowState {\n target: TargetInfo;\n data: CollectedData;\n analysis: AnalysisResult;\n output: OutputResult;\n status: \"pending\" | \"collecting\" | \"analyzing\" | \"generating\" | \"done\" | \"error\";\n error?: string;\n}\n\nexport function createInitialState(target: TargetInfo): WorkflowState {\n return {\n target,\n data: {},\n analysis: {},\n output: {},\n status: \"pending\",\n };\n}\n","import { WorkflowState, createInitialState, TargetInfo } from \"./state.js\";\n\nexport type NodeFunction = (state: WorkflowState) => Promise<WorkflowState>;\n\nexport interface WorkflowConfig {\n nodes: NodeFunction[];\n onStateChange?: (state: WorkflowState) => void;\n}\n\nexport class WorkflowEngine {\n private nodes: NodeFunction[];\n private onStateChange?: (state: WorkflowState) => void;\n\n constructor(config: WorkflowConfig) {\n this.nodes = config.nodes;\n this.onStateChange = config.onStateChange;\n }\n\n async execute(target: TargetInfo): Promise<WorkflowState> {\n let state = createInitialState(target);\n\n for (const node of this.nodes) {\n state = await node(state);\n this.onStateChange?.(state);\n\n if (state.status === \"error\") {\n throw new Error(state.error);\n }\n }\n\n return state;\n }\n}\n","import { WorkflowState } from \"../state.js\";\nimport { DataSource } from \"../../datasources/index.js\";\n\nexport async function dataCollectionNode(\n state: WorkflowState,\n dataSource: DataSource\n): Promise<WorkflowState> {\n const { code, market } = state.target;\n \n try {\n const [stockInfo, financial, history] = await Promise.all([\n dataSource.getStockInfo(code, market),\n dataSource.getFinancialData(code, market),\n dataSource.getStockHistory(code, market, 30),\n ]);\n\n return {\n ...state,\n data: {\n stockInfo,\n financial,\n history,\n },\n status: \"collecting\",\n };\n } catch (error: any) {\n return {\n ...state,\n status: \"error\",\n error: `数据采集失败: ${error.message}`,\n };\n }\n}\n","import { WorkflowState } from \"../state.js\";\n\nfunction calculateMA(data: number[], period: number): number | undefined {\n if (data.length < period) return undefined;\n const slice = data.slice(-period);\n return slice.reduce((a, b) => a + b, 0) / period;\n}\n\nfunction calculateRSI(prices: number[], period: number = 14): number | undefined {\n if (prices.length < period + 1) return undefined;\n \n let gains = 0;\n let losses = 0;\n \n for (let i = prices.length - period; i < prices.length; i++) {\n const change = prices[i] - prices[i - 1];\n if (change > 0) {\n gains += change;\n } else {\n losses -= change;\n }\n }\n \n const avgGain = gains / period;\n const avgLoss = losses / period;\n \n if (avgLoss === 0) return 100;\n \n const rs = avgGain / avgLoss;\n return 100 - (100 / (1 + rs));\n}\n\nexport async function analysisNode(state: WorkflowState): Promise<WorkflowState> {\n if (state.status === \"error\") return state;\n\n const { financial, history, stockInfo } = state.data;\n\n try {\n // 价格数据\n const prices = history?.map((h: any) => h.close) || [];\n \n // 计算技术指标\n const ma5 = calculateMA(prices, 5);\n const ma10 = calculateMA(prices, 10);\n const ma20 = calculateMA(prices, 20);\n const rsi = calculateRSI(prices);\n\n // 财务分析\n const financialAnalysis = {\n price: financial?.price,\n change_pct: financial?.change_pct,\n volume: financial?.volume,\n amount: financial?.amount,\n turnover: financial?.turnover,\n };\n\n // 趋势分析\n const trend = {\n ma5: ma5 ? Math.round(ma5 * 100) / 100 : undefined,\n ma10: ma10 ? Math.round(ma10 * 100) / 100 : undefined,\n ma20: ma20 ? Math.round(ma20 * 100) / 100 : undefined,\n rsi: rsi ? Math.round(rsi * 100) / 100 : undefined,\n };\n\n // 趋势判断\n let trendSignal = \"中性\";\n if (ma5 && ma10 && ma20) {\n if (ma5 > ma10 && ma10 > ma20) {\n trendSignal = \"上升趋势\";\n } else if (ma5 < ma10 && ma10 < ma20) {\n trendSignal = \"下降趋势\";\n }\n }\n\n return {\n ...state,\n analysis: {\n financial: financialAnalysis,\n trend,\n comparison: {\n industry: stockInfo?.industry || \"未知\",\n trendSignal,\n },\n },\n status: \"analyzing\",\n };\n } catch (error: any) {\n return {\n ...state,\n status: \"error\",\n error: `分析失败: ${error.message}`,\n };\n }\n}\n","import { WorkflowState } from \"../state.js\";\n\nexport async function reportNode(state: WorkflowState): Promise<WorkflowState> {\n if (state.status === \"error\") return state;\n\n const { target, analysis, data } = state;\n\n try {\n const report = `# ${target.company} (${target.code}) 研究报告\n\n## 公司概况\n- **股票代码**: ${target.code}\n- **市场**: ${target.market}\n- **行业**: ${analysis.comparison?.industry || \"未知\"}\n\n## 价格信息\n- **当前价格**: ¥${analysis.financial?.price || \"N/A\"}\n- **涨跌幅**: ${analysis.financial?.change_pct || \"N/A\"}%\n- **成交量**: ${analysis.financial?.volume ? (analysis.financial.volume / 10000).toFixed(2) + \"万手\" : \"N/A\"}\n- **成交额**: ${analysis.financial?.amount ? (analysis.financial.amount / 100000000).toFixed(2) + \"亿\" : \"N/A\"}\n\n## 技术分析\n- **5日均线**: ¥${analysis.trend?.ma5 || \"N/A\"}\n- **10日均线**: ¥${analysis.trend?.ma10 || \"N/A\"}\n- **20日均线**: ¥${analysis.trend?.ma20 || \"N/A\"}\n- **RSI(14)**: ${analysis.trend?.rsi || \"N/A\"}\n- **趋势信号**: ${analysis.comparison?.trendSignal || \"中性\"}\n\n## 近期走势\n${data.history ? data.history.slice(-5).map((h: any) => \n `- ${h.date}: 开盘 ¥${h.open} | 收盘 ¥${h.close} | 涨跌 ${h.change_pct}%`\n).join(\"\\n\") : \"无数据\"}\n\n## 投资建议\n基于技术分析,${target.company} 当前处于 **${analysis.comparison?.trendSignal || \"中性\"}**。\n\n${analysis.trend?.rsi && analysis.trend.rsi > 70 ? \"⚠️ RSI 超买区域,注意回调风险\" : \"\"}\n${analysis.trend?.rsi && analysis.trend.rsi < 30 ? \"✅ RSI 超卖区域,可能存在反弹机会\" : \"\"}\n\n---\n*报告生成时间: ${new Date().toISOString()}*\n*数据来源: akshare (免费数据)*\n`;\n\n return {\n ...state,\n output: {\n report,\n format: \"markdown\",\n },\n status: \"done\",\n };\n } catch (error: any) {\n return {\n ...state,\n status: \"error\",\n error: `报告生成失败: ${error.message}`,\n };\n }\n}\n","import { AkshareDataSource } from \"../datasources/akshare.js\";\nimport { WorkflowEngine } from \"../workflow/engine.js\";\nimport { dataCollectionNode } from \"../workflow/nodes/data-collection.js\";\nimport { analysisNode } from \"../workflow/nodes/analysis.js\";\nimport { reportNode } from \"../workflow/nodes/report.js\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const financeTool: Tool = {\n name: \"finance_analyze\",\n description: \"分析上市公司财务数据并生成研究报告\",\n parameters: {\n type: \"object\",\n properties: {\n company: {\n type: \"string\",\n description: \"公司名称\",\n },\n code: {\n type: \"string\",\n description: \"股票代码\",\n },\n market: {\n type: \"string\",\n enum: [\"A\", \"HK\"],\n description: \"市场类型 (A: A股, HK: 港股)\",\n },\n },\n required: [\"company\", \"code\"],\n },\n execute: async (params: Record<string, unknown>): Promise<ToolResult> => {\n try {\n const dataSource = new AkshareDataSource();\n \n const engine = new WorkflowEngine({\n nodes: [\n (state) => dataCollectionNode(state, dataSource),\n analysisNode,\n reportNode,\n ],\n });\n\n const result = await engine.execute({\n company: params.company as string,\n code: params.code as string,\n market: (params.market as string) || \"A\",\n });\n\n return {\n output: result.output.report || \"分析完成\",\n };\n } catch (error: any) {\n return {\n output: \"\",\n error: error.message,\n };\n }\n },\n};\n\nexport const financeTools = [financeTool];\n","import type { Tool } from \"../core/types.js\";\nimport { readFileTool } from \"./read_file.js\";\nimport { writeFileTool } from \"./write_file.js\";\nimport { editFileTool } from \"./edit_file.js\";\nimport { bashTool } from \"./bash.js\";\nimport { globTool } from \"./glob.js\";\nimport { grepTool } from \"./grep.js\";\nimport { financeTool } from \"./finance.js\";\n\nexport const builtinTools: Tool[] = [\n readFileTool,\n writeFileTool,\n editFileTool,\n bashTool,\n globTool,\n grepTool,\n financeTool,\n];\n\nexport function getToolsByNames(names: string[]): Tool[] {\n return builtinTools.filter((t) => names.includes(t.name));\n}\n\nexport { readFileTool } from \"./read_file.js\";\nexport { writeFileTool } from \"./write_file.js\";\nexport { editFileTool } from \"./edit_file.js\";\nexport { bashTool } from \"./bash.js\";\nexport { globTool } from \"./glob.js\";\nexport { grepTool } from \"./grep.js\";\nexport { financeTool } from \"./finance.js\";\n","import type { ModelProvider, Message, Tool, ToolCall, ToolResult } from \"./types.js\";\nimport { builtinTools } from \"../tools/index.js\";\n\nexport interface OrchestratorOptions {\n model: ModelProvider;\n systemPrompt?: string;\n skillInstructions?: string;\n tools?: Tool[];\n maxIterations?: number;\n onToken?: (token: string) => void;\n onToolStart?: (name: string, params: Record<string, unknown>) => void;\n onToolEnd?: (name: string, result: ToolResult) => void;\n}\n\nexport class Orchestrator {\n private messages: Message[] = [];\n private tools: Tool[];\n private model: ModelProvider;\n private systemPrompt: string;\n private maxIterations: number;\n private callbacks: Pick<\n OrchestratorOptions,\n \"onToken\" | \"onToolStart\" | \"onToolEnd\"\n >;\n\n constructor(opts: OrchestratorOptions) {\n this.model = opts.model;\n this.systemPrompt = opts.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;\n if (opts.skillInstructions) {\n this.systemPrompt += \"\\n\\n\" + opts.skillInstructions;\n }\n this.tools = opts.tools ?? builtinTools;\n this.maxIterations = opts.maxIterations ?? 20;\n this.callbacks = {\n onToken: opts.onToken,\n onToolStart: opts.onToolStart,\n onToolEnd: opts.onToolEnd,\n };\n\n if (this.systemPrompt) {\n this.messages.push({ role: \"system\", content: this.systemPrompt });\n }\n }\n\n async run(userMessage: string): Promise<string> {\n this.messages.push({ role: \"user\", content: userMessage });\n\n for (let i = 0; i < this.maxIterations; i++) {\n const response = await this.model.chat(this.messages, this.tools);\n\n if (response.content) {\n this.messages.push({\n role: \"assistant\",\n content: response.content,\n tool_calls: response.tool_calls,\n });\n }\n\n if (!response.tool_calls?.length) {\n return response.content;\n }\n\n for (const tc of response.tool_calls) {\n this.callbacks.onToolStart?.(\n tc.function.name,\n JSON.parse(tc.function.arguments),\n );\n const result = await this.executeTool(tc);\n this.callbacks.onToolEnd?.(tc.function.name, result);\n this.messages.push({\n role: \"tool\",\n content: result.error ? `Error: ${result.error}` : result.output,\n tool_call_id: tc.id,\n });\n }\n }\n\n return \"Max iterations reached.\";\n }\n\n async *runStream(userMessage: string): AsyncIterable<string> {\n this.messages.push({ role: \"user\", content: userMessage });\n\n for (let i = 0; i < this.maxIterations; i++) {\n let fullContent = \"\";\n let toolCalls: ToolCall[] = [];\n\n for await (const chunk of this.model.stream(this.messages, this.tools)) {\n if (chunk.content) {\n fullContent += chunk.content;\n yield chunk.content;\n }\n if (chunk.tool_calls) {\n toolCalls = chunk.tool_calls;\n }\n }\n\n if (!toolCalls.length) {\n this.messages.push({ role: \"assistant\", content: fullContent });\n return;\n }\n\n this.messages.push({\n role: \"assistant\",\n content: fullContent,\n tool_calls: toolCalls,\n });\n\n for (const tc of toolCalls) {\n this.callbacks.onToolStart?.(\n tc.function.name,\n JSON.parse(tc.function.arguments),\n );\n const result = await this.executeTool(tc);\n this.callbacks.onToolEnd?.(tc.function.name, result);\n this.messages.push({\n role: \"tool\",\n content: result.error ? `Error: ${result.error}` : result.output,\n tool_call_id: tc.id,\n });\n }\n }\n }\n\n private async executeTool(tc: ToolCall): Promise<ToolResult> {\n const tool = this.tools.find((t) => t.name === tc.function.name);\n if (!tool) return { output: \"\", error: `Unknown tool: ${tc.function.name}` };\n try {\n const params = JSON.parse(tc.function.arguments);\n return await tool.execute(params);\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n }\n\n getMessages(): Message[] {\n return [...this.messages];\n }\n\n clearMessages(): void {\n this.messages = [];\n if (this.systemPrompt) {\n this.messages.push({ role: \"system\", content: this.systemPrompt });\n }\n }\n}\n\nconst DEFAULT_SYSTEM_PROMPT = `You are Hecode, an AI coding assistant. You help users with software engineering tasks using the tools available to you.\n\nKey principles:\n- Be concise and direct\n- Use tools to read/write files, execute commands, and search code\n- Verify your work by running tests or checks when possible\n- Follow existing code conventions in the project`;\n"],"mappings":"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","names":["readFile","writeFile","readFile","exec"]}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
Orchestrator
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-I4W33CWB.js";
|
|
5
5
|
|
|
6
6
|
// src/cli/commands.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -484,7 +484,7 @@ function createProgram() {
|
|
|
484
484
|
if (model) modelConfig.model = model;
|
|
485
485
|
const modelProvider = createProvider(provider, modelConfig);
|
|
486
486
|
if (prompt.length) {
|
|
487
|
-
const { Orchestrator: Orchestrator2 } = await import("./orchestrator-
|
|
487
|
+
const { Orchestrator: Orchestrator2 } = await import("./orchestrator-QX3OE4IN.js");
|
|
488
488
|
const orch = new Orchestrator2({ model: modelProvider });
|
|
489
489
|
const result = await orch.run(prompt.join(" "));
|
|
490
490
|
console.log(result);
|
package/package.json
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhanngning/hecode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"hecode": "./dist/index.js"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
10
|
-
"README.md"
|
|
10
|
+
"README.md",
|
|
11
|
+
"skills"
|
|
11
12
|
],
|
|
12
13
|
"scripts": {
|
|
13
14
|
"build": "tsup",
|
|
14
15
|
"dev": "tsx src/index.ts",
|
|
15
16
|
"test": "vitest run",
|
|
16
|
-
"lint": "tsc --noEmit"
|
|
17
|
+
"lint": "tsc --noEmit",
|
|
18
|
+
"finance": "python src/datasources/akshare_datasource.py"
|
|
17
19
|
},
|
|
18
20
|
"engines": {
|
|
19
21
|
"node": ">=20.0.0"
|
|
@@ -31,5 +33,20 @@
|
|
|
31
33
|
"chalk": "^5.6.2",
|
|
32
34
|
"commander": "^15.0.0",
|
|
33
35
|
"openai": "^6.45.0"
|
|
36
|
+
},
|
|
37
|
+
"optionalDependencies": {
|
|
38
|
+
"akshare": ">=1.18.0"
|
|
39
|
+
},
|
|
40
|
+
"description": "Your AI Coding Assistant CLI with financial analysis capabilities",
|
|
41
|
+
"keywords": [
|
|
42
|
+
"ai",
|
|
43
|
+
"cli",
|
|
44
|
+
"coding",
|
|
45
|
+
"financial-analysis",
|
|
46
|
+
"stock"
|
|
47
|
+
],
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://github.com/zhanngning/hecode"
|
|
34
51
|
}
|
|
35
52
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Coding Assistant
|
|
2
|
+
|
|
3
|
+
trigger: code, fix, debug, refactor, implement, write, create, build, test
|
|
4
|
+
|
|
5
|
+
You are a skilled software engineer. Follow these principles:
|
|
6
|
+
- Write clean, minimal code
|
|
7
|
+
- Follow existing project conventions
|
|
8
|
+
- Run tests to verify changes
|
|
9
|
+
- Be concise in explanations
|
|
10
|
+
- Use tools to read files before editing them
|
|
11
|
+
- Verify builds pass after changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# 金融分析技能
|
|
2
|
+
|
|
3
|
+
trigger: finance, 金融, 股票分析, 财务分析, 研究报告, 股票, 股价
|
|
4
|
+
|
|
5
|
+
## 功能
|
|
6
|
+
|
|
7
|
+
分析上市公司财务数据,生成研究报告。
|
|
8
|
+
|
|
9
|
+
## 使用方法
|
|
10
|
+
|
|
11
|
+
用户可以说:
|
|
12
|
+
- "分析贵州茅台"
|
|
13
|
+
- "生成腾讯的研究报告"
|
|
14
|
+
- "分析股票 600519"
|
|
15
|
+
- "查看比亚迪股价"
|
|
16
|
+
|
|
17
|
+
## 工具
|
|
18
|
+
|
|
19
|
+
使用 `finance_analyze` 工具,参数:
|
|
20
|
+
- company: 公司名称
|
|
21
|
+
- code: 股票代码
|
|
22
|
+
- market: 市场(A股/HK)
|
|
23
|
+
|
|
24
|
+
## 输出
|
|
25
|
+
|
|
26
|
+
生成包含以下内容的报告:
|
|
27
|
+
1. 公司概况(股票代码、市场、行业)
|
|
28
|
+
2. 价格信息(当前价格、涨跌幅、成交量)
|
|
29
|
+
3. 技术分析(均线、RSI、趋势信号)
|
|
30
|
+
4. 近期走势
|
|
31
|
+
5. 投资建议
|
|
32
|
+
|
|
33
|
+
## 数据源
|
|
34
|
+
|
|
35
|
+
使用 akshare 获取免费金融数据:
|
|
36
|
+
- A股数据:沪深交易所
|
|
37
|
+
- 港股数据:港交所
|
|
38
|
+
|
|
39
|
+
## 示例
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
用户: 分析贵州茅台
|
|
43
|
+
助手: 我来分析贵州茅台的财务数据...
|
|
44
|
+
[调用 finance_analyze 工具,参数: { company: "贵州茅台", code: "600519", market: "A" }]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 注意事项
|
|
48
|
+
|
|
49
|
+
- 数据仅供参考,不构成投资建议
|
|
50
|
+
- 数据来源为免费公开数据
|
|
51
|
+
- 历史数据最近30天
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tools/read_file.ts","../src/tools/write_file.ts","../src/tools/edit_file.ts","../src/tools/bash.ts","../src/tools/glob.ts","../src/tools/grep.ts","../src/tools/index.ts","../src/core/orchestrator.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const readFileTool: Tool = {\n name: \"read_file\",\n description: \"Read file content. Supports offset and limit for large files.\",\n parameters: {\n type: \"object\",\n properties: {\n file_path: { type: \"string\", description: \"Absolute path to the file\" },\n offset: { type: \"number\", description: \"Line number to start from (1-indexed)\" },\n limit: { type: \"number\", description: \"Max lines to read (default 2000)\" },\n },\n required: [\"file_path\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n const content = await readFile(params.file_path as string, \"utf-8\");\n const lines = content.split(\"\\n\");\n const offset = (params.offset as number) || 1;\n const limit = (params.limit as number) || 2000;\n const sliced = lines.slice(offset - 1, offset - 1 + limit);\n const numbered = sliced.map((line, i) => `${offset + i}: ${line}`).join(\"\\n\");\n return { output: numbered };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n","import { writeFile, mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const writeFileTool: Tool = {\n name: \"write_file\",\n description: \"Write content to a file. Creates parent directories if needed.\",\n parameters: {\n type: \"object\",\n properties: {\n file_path: { type: \"string\", description: \"Absolute path to the file\" },\n content: { type: \"string\", description: \"Content to write\" },\n },\n required: [\"file_path\", \"content\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n await mkdir(dirname(params.file_path as string), { recursive: true });\n await writeFile(params.file_path as string, params.content as string, \"utf-8\");\n return { output: `File written: ${params.file_path}` };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const editFileTool: Tool = {\n name: \"edit_file\",\n description:\n \"Replace exact string match in a file. Fails if old_string not found or matches multiple times.\",\n parameters: {\n type: \"object\",\n properties: {\n file_path: { type: \"string\", description: \"Absolute path to the file\" },\n old_string: { type: \"string\", description: \"Exact string to replace\" },\n new_string: { type: \"string\", description: \"Replacement string\" },\n replace_all: { type: \"boolean\", description: \"Replace all occurrences (default false)\" },\n },\n required: [\"file_path\", \"old_string\", \"new_string\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n const content = await readFile(params.file_path as string, \"utf-8\");\n const oldStr = params.old_string as string;\n const newStr = params.new_string as string;\n const replaceAll = params.replace_all as boolean;\n\n if (!content.includes(oldStr)) {\n return { output: \"\", error: `old_string not found in ${params.file_path}` };\n }\n\n let result: string;\n if (replaceAll) {\n result = content.replaceAll(oldStr, newStr);\n } else {\n const count = content.split(oldStr).length - 1;\n if (count > 1) {\n return {\n output: \"\",\n error: `Found ${count} matches for old_string. Provide more context or set replace_all=true.`,\n };\n }\n result = content.replace(oldStr, newStr);\n }\n\n await writeFile(params.file_path as string, result, \"utf-8\");\n return { output: `Edited: ${params.file_path}` };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n","import { exec } from \"node:child_process\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const bashTool: Tool = {\n name: \"bash\",\n description: \"Execute a shell command. Returns stdout and stderr.\",\n parameters: {\n type: \"object\",\n properties: {\n command: { type: \"string\", description: \"The command to execute\" },\n timeout: { type: \"number\", description: \"Timeout in ms (default 120000)\" },\n workdir: { type: \"string\", description: \"Working directory\" },\n },\n required: [\"command\"],\n },\n async execute(params): Promise<ToolResult> {\n return new Promise((resolve) => {\n const timeout = (params.timeout as number) || 120_000;\n exec(\n params.command as string,\n {\n timeout,\n cwd: (params.workdir as string) || process.cwd(),\n encoding: \"utf-8\",\n },\n (error, stdout, stderr) => {\n if (error && error.killed) {\n resolve({\n output: stdout ?? \"\",\n error: `Command timed out after ${timeout}ms`,\n });\n } else if (error && !stdout && !stderr) {\n resolve({ output: \"\", error: error.message });\n } else {\n resolve({ output: [stdout, stderr].filter(Boolean).join(\"\\n\").trim() });\n }\n },\n );\n });\n },\n};\n","import { glob } from \"node:fs/promises\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const globTool: Tool = {\n name: \"glob\",\n description: \"Find files matching a glob pattern.\",\n parameters: {\n type: \"object\",\n properties: {\n pattern: {\n type: \"string\",\n description: \"Glob pattern (e.g. '**/*.ts', 'src/**/*.test.*')\",\n },\n path: { type: \"string\", description: \"Directory to search in (default: cwd)\" },\n },\n required: [\"pattern\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n const files: string[] = [];\n for await (const f of glob(params.pattern as string, {\n cwd: (params.path as string) || process.cwd(),\n })) {\n files.push(f);\n }\n files.sort();\n return { output: files.join(\"\\n\") || \"No files found\" };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n","import { readFile, readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const grepTool: Tool = {\n name: \"grep\",\n description:\n \"Search file contents using regex. Returns file paths and matching line numbers.\",\n parameters: {\n type: \"object\",\n properties: {\n pattern: { type: \"string\", description: \"Regex pattern to search for\" },\n path: { type: \"string\", description: \"Directory to search in (default: cwd)\" },\n include: { type: \"string\", description: \"File pattern to include (e.g. '*.ts')\" },\n },\n required: [\"pattern\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n const regex = new RegExp(params.pattern as string, \"gi\");\n const rootDir = (params.path as string) || process.cwd();\n const includePattern = params.include as string | undefined;\n const results: string[] = [];\n\n async function searchDir(dir: string, depth: number) {\n if (depth > 10 || results.length >= 200) return;\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue;\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n await searchDir(fullPath, depth + 1);\n } else if (entry.isFile()) {\n if (includePattern && !matchGlob(entry.name, includePattern)) continue;\n try {\n const content = await readFile(fullPath, \"utf-8\");\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (regex.test(lines[i]!)) {\n results.push(`${fullPath}:${i + 1}: ${lines[i]!.trim()}`);\n if (results.length >= 200) return;\n }\n regex.lastIndex = 0;\n }\n } catch {\n /* skip binary/unreadable files */\n }\n }\n }\n }\n\n await searchDir(rootDir, 0);\n return { output: results.join(\"\\n\") || \"No matches found\" };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n\nfunction matchGlob(filename: string, pattern: string): boolean {\n const regexStr = \"^\" + pattern.replace(/\\*/g, \".*\").replace(/\\?/g, \".\") + \"$\";\n return new RegExp(regexStr, \"i\").test(filename);\n}\n","import type { Tool } from \"../core/types.js\";\nimport { readFileTool } from \"./read_file.js\";\nimport { writeFileTool } from \"./write_file.js\";\nimport { editFileTool } from \"./edit_file.js\";\nimport { bashTool } from \"./bash.js\";\nimport { globTool } from \"./glob.js\";\nimport { grepTool } from \"./grep.js\";\n\nexport const builtinTools: Tool[] = [\n readFileTool,\n writeFileTool,\n editFileTool,\n bashTool,\n globTool,\n grepTool,\n];\n\nexport function getToolsByNames(names: string[]): Tool[] {\n return builtinTools.filter((t) => names.includes(t.name));\n}\n\nexport { readFileTool } from \"./read_file.js\";\nexport { writeFileTool } from \"./write_file.js\";\nexport { editFileTool } from \"./edit_file.js\";\nexport { bashTool } from \"./bash.js\";\nexport { globTool } from \"./glob.js\";\nexport { grepTool } from \"./grep.js\";\n","import type { ModelProvider, Message, Tool, ToolCall, ToolResult } from \"./types.js\";\nimport { builtinTools } from \"../tools/index.js\";\n\nexport interface OrchestratorOptions {\n model: ModelProvider;\n systemPrompt?: string;\n skillInstructions?: string;\n tools?: Tool[];\n maxIterations?: number;\n onToken?: (token: string) => void;\n onToolStart?: (name: string, params: Record<string, unknown>) => void;\n onToolEnd?: (name: string, result: ToolResult) => void;\n}\n\nexport class Orchestrator {\n private messages: Message[] = [];\n private tools: Tool[];\n private model: ModelProvider;\n private systemPrompt: string;\n private maxIterations: number;\n private callbacks: Pick<\n OrchestratorOptions,\n \"onToken\" | \"onToolStart\" | \"onToolEnd\"\n >;\n\n constructor(opts: OrchestratorOptions) {\n this.model = opts.model;\n this.systemPrompt = opts.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;\n if (opts.skillInstructions) {\n this.systemPrompt += \"\\n\\n\" + opts.skillInstructions;\n }\n this.tools = opts.tools ?? builtinTools;\n this.maxIterations = opts.maxIterations ?? 20;\n this.callbacks = {\n onToken: opts.onToken,\n onToolStart: opts.onToolStart,\n onToolEnd: opts.onToolEnd,\n };\n\n if (this.systemPrompt) {\n this.messages.push({ role: \"system\", content: this.systemPrompt });\n }\n }\n\n async run(userMessage: string): Promise<string> {\n this.messages.push({ role: \"user\", content: userMessage });\n\n for (let i = 0; i < this.maxIterations; i++) {\n const response = await this.model.chat(this.messages, this.tools);\n\n if (response.content) {\n this.messages.push({\n role: \"assistant\",\n content: response.content,\n tool_calls: response.tool_calls,\n });\n }\n\n if (!response.tool_calls?.length) {\n return response.content;\n }\n\n for (const tc of response.tool_calls) {\n this.callbacks.onToolStart?.(\n tc.function.name,\n JSON.parse(tc.function.arguments),\n );\n const result = await this.executeTool(tc);\n this.callbacks.onToolEnd?.(tc.function.name, result);\n this.messages.push({\n role: \"tool\",\n content: result.error ? `Error: ${result.error}` : result.output,\n tool_call_id: tc.id,\n });\n }\n }\n\n return \"Max iterations reached.\";\n }\n\n async *runStream(userMessage: string): AsyncIterable<string> {\n this.messages.push({ role: \"user\", content: userMessage });\n\n for (let i = 0; i < this.maxIterations; i++) {\n let fullContent = \"\";\n let toolCalls: ToolCall[] = [];\n\n for await (const chunk of this.model.stream(this.messages, this.tools)) {\n if (chunk.content) {\n fullContent += chunk.content;\n yield chunk.content;\n }\n if (chunk.tool_calls) {\n toolCalls = chunk.tool_calls;\n }\n }\n\n if (!toolCalls.length) {\n this.messages.push({ role: \"assistant\", content: fullContent });\n return;\n }\n\n this.messages.push({\n role: \"assistant\",\n content: fullContent,\n tool_calls: toolCalls,\n });\n\n for (const tc of toolCalls) {\n this.callbacks.onToolStart?.(\n tc.function.name,\n JSON.parse(tc.function.arguments),\n );\n const result = await this.executeTool(tc);\n this.callbacks.onToolEnd?.(tc.function.name, result);\n this.messages.push({\n role: \"tool\",\n content: result.error ? `Error: ${result.error}` : result.output,\n tool_call_id: tc.id,\n });\n }\n }\n }\n\n private async executeTool(tc: ToolCall): Promise<ToolResult> {\n const tool = this.tools.find((t) => t.name === tc.function.name);\n if (!tool) return { output: \"\", error: `Unknown tool: ${tc.function.name}` };\n try {\n const params = JSON.parse(tc.function.arguments);\n return await tool.execute(params);\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n }\n\n getMessages(): Message[] {\n return [...this.messages];\n }\n\n clearMessages(): void {\n this.messages = [];\n if (this.systemPrompt) {\n this.messages.push({ role: \"system\", content: this.systemPrompt });\n }\n }\n}\n\nconst DEFAULT_SYSTEM_PROMPT = `You are Hecode, an AI coding assistant. You help users with software engineering tasks using the tools available to you.\n\nKey principles:\n- Be concise and direct\n- Use tools to read/write files, execute commands, and search code\n- Verify your work by running tests or checks when possible\n- Follow existing code conventions in the project`;\n"],"mappings":"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","names":["readFile","writeFile","readFile"]}
|
|
File without changes
|