@dsh-ft/finance-all-in-one 0.0.0-stage → 1.0.1
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/LICENSE +21 -0
- package/README.md +73 -2
- package/cordis.patch.yml +257 -0
- package/icon.png +0 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.js +8 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +69 -4
- package/scripts/kline-mcp.mjs +79 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ben
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,74 @@
|
|
|
1
|
-
#
|
|
1
|
+
# FT 金融工作台:行情、K 线、模拟盘
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@dsh-ft/finance-all-in-one)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
一次安装,把 DeepSeek Harness 组装成一座金融工作台:FTShare 数据面、K 线图表、出图技能、 A 股 / 商品期货模拟盘。
|
|
7
|
+
|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
> DSH ≥ 0.2.1-rc.2 · 装完新会话就是金融模式 · K 线由依赖安装 · 账本保存在本地
|
|
11
|
+
|
|
12
|
+
## 效果
|
|
13
|
+
|
|
14
|
+
下单与撤单:市价单在收盘后自动排队到下一交易时段,状态与原因(待开盘 / 已撤 / 被拒)都写在订单页,成交前随时可以撤。
|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
|
|
18
|
+
## 装了什么
|
|
19
|
+
|
|
20
|
+
| 组件 | 作用 |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| 金融模式(`ft-finance`)预设 | 新会话的默认工作方式:金融人设、行情与取数工具、出图技能 |
|
|
23
|
+
| `@dsh-ft/dsh-fft-settings` | 设置页「金融终端」分区与 API Key 凭据 |
|
|
24
|
+
| `@dsh-ft/dsh-fft-ftshare` | FTShare 数据面工具:行情、板块、资金流、财务等 |
|
|
25
|
+
| `@ftshare-lab/dsh-kline` | K 线图表与侧栏,随依赖安装 |
|
|
26
|
+
| `@dsh-ft/dsh-fft-plot` | 出图技能:把取数结果渲染成内联 SVG |
|
|
27
|
+
| `@dsh-ft/dsh-fft-paper-trading` | 模拟盘:本地账本、下单、持仓与复盘 |
|
|
28
|
+
|
|
29
|
+
## 安装
|
|
30
|
+
|
|
31
|
+
在「设置 → 插件管理 → 添加插件」里输入包名:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
dsh plugin add @dsh-ft/finance-all-in-one
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
装完重启一次应用。不需要改 pnpm 配置,也不需要 ssh:所有依赖都从 npm 解析。
|
|
38
|
+
|
|
39
|
+
- **不要**与同样自带 FTShare 数据服务的入口包(如 `@dsh-ft/dsh-fft-paper-trading`)同时安装:数据服务行会重复,插件管理器里相关项将无法单独开关。
|
|
40
|
+
- 完整 K 线视图依赖本机 Python 3.10+,首次启动会联网准备运行环境;准备失败不影响取数、出图、下单与复盘。
|
|
41
|
+
|
|
42
|
+
## 上手三步
|
|
43
|
+
|
|
44
|
+
1. **配置数据源(可选)**:DSH「设置 → 金融终端」里填 FTShare API Key,免费申请地址 <https://ftai.chat/me/profile?tab=api-key&utm_source=dsh-fft>,无 key 时使用匿名额度。
|
|
45
|
+
2. **新建会话**:默认就是金融模式,不用再选预设。
|
|
46
|
+
3. **直接问**:
|
|
47
|
+
|
|
48
|
+
- 「贵州茅台最近走势怎么样?」
|
|
49
|
+
- 「今天涨停集中在哪些板块?」
|
|
50
|
+
- 「把近 20 个交易日的成交额画出来」
|
|
51
|
+
|
|
52
|
+
## 能力范围
|
|
53
|
+
|
|
54
|
+
- **模拟盘**:A 股与商品期货(日盘),本地账本,支持批量建仓、挂单撤单、复盘与风控。
|
|
55
|
+
- **K 线**:多市场行情、技术指标与支撑压力位,在侧栏打开。
|
|
56
|
+
- **出图**:把取数结果渲染成内联 SVG,图随回答一起显示。
|
|
57
|
+
- **数据**:行情、板块、资金流、财务报表等经 FTShare 数据面提供。
|
|
58
|
+
|
|
59
|
+
## 数据与隐私
|
|
60
|
+
|
|
61
|
+
- 模拟盘的账本保存在本机 DSH 数据目录(默认 `~/.dsh`)下的 `paper-trading/`,不上传任何服务器。
|
|
62
|
+
- 除了向 FTShare 发起行情与数据查询外,本插件不向外部发送数据,也不含遥测。
|
|
63
|
+
- 仅用于研究与模拟,不构成投资建议。
|
|
64
|
+
|
|
65
|
+
## 反馈
|
|
66
|
+
|
|
67
|
+
遇到 bug 或想加功能,走 GitHub Issues:
|
|
68
|
+
|
|
69
|
+
- [报告 bug](https://github.com/FTShare-Lab/dsh-plugin-fft-bundle/issues/new)
|
|
70
|
+
- [功能建议](https://github.com/FTShare-Lab/dsh-plugin-fft-bundle/issues/new)
|
|
71
|
+
|
|
72
|
+
贴日志前先删掉 API Key、账户数据与账本路径。
|
|
73
|
+
|
|
74
|
+
本项目以 [MIT](LICENSE) 许可开源。变更记录见 [CHANGELOG.md](https://github.com/FTShare-Lab/dsh-plugin-fft-bundle/blob/dev/CHANGELOG.md)。
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# dsh-fft-bundle patch layer: inserts the FT workbench plugin rows with their
|
|
2
|
+
# shared defaults. Applied when this package is installed via
|
|
3
|
+
#
|
|
4
|
+
# dsh plugin --profile <name> add @dsh-ft/finance-all-in-one
|
|
5
|
+
#
|
|
6
|
+
# Two planes:
|
|
7
|
+
# * the host rows (settings service, SSO, kline sidebar) stay global — a
|
|
8
|
+
# service provider cannot be mounted from a preset, and client halves live
|
|
9
|
+
# in the profile's browser module graph;
|
|
10
|
+
# * everything that is only true in the finance working mode goes into
|
|
11
|
+
# `preset-ft-finance`: the FT persona, the prompt contract entry, the
|
|
12
|
+
# kline MCP client and the FTShare tool surface. That preset copies the
|
|
13
|
+
# official `standard` composition, because a preset's `plugins` list is
|
|
14
|
+
# complete and inherits nothing.
|
|
15
|
+
#
|
|
16
|
+
# The preset's tool registrations are scoped to the preset subtree, so the
|
|
17
|
+
# standard mode keeps none of them. That is what keeps `ftshare_*` and
|
|
18
|
+
# the projection hook out of the standard mode: the FTShare service row is
|
|
19
|
+
# global because a `provide` cannot live in a preset, while everything that
|
|
20
|
+
# registers a tool or a hook is mounted from `preset-ft-finance`.
|
|
21
|
+
#
|
|
22
|
+
# Last: make `ft-finance` the default new-session preset. The registry resolves
|
|
23
|
+
# `selectedDefault` first, but that field is volatile and never reaches disk, so
|
|
24
|
+
# the durable default is this row's `default`. Overriding the row replaces its
|
|
25
|
+
# whole config — the official row carries only `default` today, and
|
|
26
|
+
# `tests/preset-ft-finance.test.mjs` fails if that changes.
|
|
27
|
+
|
|
28
|
+
- insert:
|
|
29
|
+
- id: dsh-fft-settings
|
|
30
|
+
name: '@dsh-ft/dsh-fft-settings'
|
|
31
|
+
# FTShare 公用底座。必须是全局行:preset 内 `provide` 会抛
|
|
32
|
+
# "Preset services require isolate realms",而加上 isolate 之后服务变成 preset
|
|
33
|
+
# 私有、preset 之外的插件 inject 不到。工具与投影钩子在 preset(见下)。
|
|
34
|
+
- id: dsh-fft-ftshare
|
|
35
|
+
name: '@dsh-ft/dsh-fft-ftshare'
|
|
36
|
+
- id: dsh-kline-sidebar
|
|
37
|
+
name: '@ftshare-lab/dsh-kline'
|
|
38
|
+
# 模拟盘:一行同时承载宿主半(RPC 路由与 paper_stock_* / paper_futures_* /
|
|
39
|
+
# paper_ledger 工具)与浏览器半(侧栏「模拟交易」标签)。bare-name 全局行是 DSH
|
|
40
|
+
# 浏览器模块扫描唯一能看到的形态,不能放进 preset(preset 行不产生浏览器模块源)。
|
|
41
|
+
# 它从依赖取得本包(registry 上的精确版本),因此本行必须与 package.json 的
|
|
42
|
+
# @dsh-ft/dsh-fft-paper-trading 钉版成对存在。
|
|
43
|
+
- id: ft-paper-trading
|
|
44
|
+
name: '@dsh-ft/dsh-fft-paper-trading'
|
|
45
|
+
- id: preset-ft-finance
|
|
46
|
+
name: '@deepseek-ai/dsh-agent-preset'
|
|
47
|
+
config:
|
|
48
|
+
id: ft-finance
|
|
49
|
+
name: 金融模式
|
|
50
|
+
description: 金融研究与盯盘:行情指标、K 线与 FTShare 数据面。试试「贵州茅台最近走势」「今天涨停集中在哪些板块」「用 ftshare 查一下这只票的现金流」
|
|
51
|
+
order: 5
|
|
52
|
+
plugins:
|
|
53
|
+
- id: persona
|
|
54
|
+
name: '@deepseek-ai/dsh-persona'
|
|
55
|
+
config:
|
|
56
|
+
# No suffix on purpose. DSH 0.2.1 assembles prompt variables
|
|
57
|
+
# strictly and registers only `provider` / `model` (agent-loop), so
|
|
58
|
+
# the old working-directory clause failed step 1 with "unknown
|
|
59
|
+
# prompt variable". The working-directory service supplies the
|
|
60
|
+
# directory as runtime context instead.
|
|
61
|
+
# persona 只负责**触发**:告诉模型"什么时候该去加载绘图 skill"。
|
|
62
|
+
# 具体怎么画(产物路径、是否用 present、哪些情形不画、图文比例)全部
|
|
63
|
+
# 写在 skill 正文里——那些规则只在画图时成立,塞进每轮注入的 persona
|
|
64
|
+
# 会平白占用上下文,也会让不适用的任务被这些措辞带偏。
|
|
65
|
+
prefix: |-
|
|
66
|
+
你是非凸(FT)金融助手,帮助用户获取金融信息,进行金融研究。乐于助人,语言精准客观
|
|
67
|
+
## 数据出图
|
|
68
|
+
FTShare 接口取到的数据,只要涉及时间趋势、横截面排名、分布或对比,就应出图;图比表格更容易看出形态。
|
|
69
|
+
出图前先加载 skill `dsh-fft-plot` 并按其说明执行。
|
|
70
|
+
- id: agent-instructions
|
|
71
|
+
name: '@deepseek-ai/dsh-agent-instructions'
|
|
72
|
+
config:
|
|
73
|
+
maxBytes: 65536
|
|
74
|
+
- id: tool-bash
|
|
75
|
+
name: '@deepseek-ai/dsh-tool-bash'
|
|
76
|
+
disabled: !!js process.platform === 'win32'
|
|
77
|
+
- id: tool-pwsh
|
|
78
|
+
name: '@deepseek-ai/dsh-tool-pwsh'
|
|
79
|
+
disabled: !!js process.platform !== 'win32'
|
|
80
|
+
- id: tool-fs
|
|
81
|
+
name: '@deepseek-ai/dsh-tool-fs'
|
|
82
|
+
# Host default since 0.2.2: the dedicated apply_patch tool is off.
|
|
83
|
+
config:
|
|
84
|
+
applyPatch: false
|
|
85
|
+
- id: tool-fs-search
|
|
86
|
+
name: '@deepseek-ai/dsh-tool-fs-search'
|
|
87
|
+
config:
|
|
88
|
+
sampleOverCapGlobResults: false
|
|
89
|
+
- id: tool-jobs
|
|
90
|
+
name: '@deepseek-ai/dsh-tool-jobs'
|
|
91
|
+
- id: skill-filesystem
|
|
92
|
+
name: '@deepseek-ai/dsh-skill-filesystem'
|
|
93
|
+
- id: tool-skill
|
|
94
|
+
name: '@deepseek-ai/dsh-tool-skill'
|
|
95
|
+
- id: command-goal
|
|
96
|
+
name: '@deepseek-ai/dsh-command-goal'
|
|
97
|
+
- id: tool-goal
|
|
98
|
+
name: '@deepseek-ai/dsh-tool-goal'
|
|
99
|
+
- id: planning
|
|
100
|
+
name: cordis:group
|
|
101
|
+
group: true
|
|
102
|
+
isolate:
|
|
103
|
+
planMode: true
|
|
104
|
+
config:
|
|
105
|
+
- id: plan-mode
|
|
106
|
+
name: '@deepseek-ai/dsh-plan-mode'
|
|
107
|
+
config:
|
|
108
|
+
section: |
|
|
109
|
+
You are in plan mode. Stay in plan mode until the user approves your plan through exit_plan_mode or switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
|
|
110
|
+
|
|
111
|
+
Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
|
|
112
|
+
|
|
113
|
+
The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
|
|
114
|
+
|
|
115
|
+
Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
|
|
116
|
+
|
|
117
|
+
Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
|
|
118
|
+
|
|
119
|
+
When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
|
|
120
|
+
- id: compaction
|
|
121
|
+
name: cordis:group
|
|
122
|
+
group: true
|
|
123
|
+
isolate:
|
|
124
|
+
compaction: true
|
|
125
|
+
toolResultPruner: true
|
|
126
|
+
config:
|
|
127
|
+
- id: compaction-basic
|
|
128
|
+
name: '@deepseek-ai/dsh-compaction-basic'
|
|
129
|
+
- id: command-compact
|
|
130
|
+
name: '@deepseek-ai/dsh-command-compact'
|
|
131
|
+
- id: tool-result-pruner
|
|
132
|
+
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
|
133
|
+
config:
|
|
134
|
+
thresholdChars: 8192
|
|
135
|
+
headChars: 4096
|
|
136
|
+
tailChars: 1024
|
|
137
|
+
- id: delegation
|
|
138
|
+
name: cordis:group
|
|
139
|
+
group: true
|
|
140
|
+
isolate:
|
|
141
|
+
workflowEngine: true
|
|
142
|
+
config:
|
|
143
|
+
- id: tool-subagent-control
|
|
144
|
+
name: '@deepseek-ai/dsh-tool-subagent-control'
|
|
145
|
+
# 0.2.1 registers list_agents only as this subpath; 0.2.2 inlined it
|
|
146
|
+
# into the entry above and dropped the subpath. Mounting a missing
|
|
147
|
+
# row fails the whole preset mount, so mount it only when the entry
|
|
148
|
+
# does not already register the tool.
|
|
149
|
+
- id: tool-subagent-list-agents
|
|
150
|
+
name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
|
|
151
|
+
disabled: !!js process.getBuiltinModule('node:fs').readFileSync(process.getBuiltinModule('node:path').join(process.resourcesPath, 'app.asar', 'dsh', 'node_modules', '@deepseek-ai', 'dsh-tool-subagent-control', 'lib', 'index.js'), 'utf8').includes('list_agents')
|
|
152
|
+
# Model selection follows the 0.2.2 host: the spawn tool exposes
|
|
153
|
+
# the optional route fields and owns `list_subagent_models`, the
|
|
154
|
+
# fork tool keeps both off to preserve inherited-prefix reuse.
|
|
155
|
+
- id: tool-subagent
|
|
156
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
157
|
+
config:
|
|
158
|
+
provider: spawn
|
|
159
|
+
toolName: subagent
|
|
160
|
+
modelSelection: true
|
|
161
|
+
modelDiscovery: true
|
|
162
|
+
- id: tool-subagent-fork
|
|
163
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
164
|
+
config:
|
|
165
|
+
provider: fork
|
|
166
|
+
toolName: subagent_fork
|
|
167
|
+
- id: workflow-ptc
|
|
168
|
+
name: '@deepseek-ai/dsh-workflow-ptc'
|
|
169
|
+
config:
|
|
170
|
+
provider: spawn
|
|
171
|
+
- id: tool-workflow
|
|
172
|
+
name: '@deepseek-ai/dsh-tool-workflow'
|
|
173
|
+
- id: tool-ask-user
|
|
174
|
+
name: '@deepseek-ai/dsh-tool-ask-user'
|
|
175
|
+
- id: tool-todo
|
|
176
|
+
name: '@deepseek-ai/dsh-tool-todo'
|
|
177
|
+
config:
|
|
178
|
+
allowParallelInProgress: true
|
|
179
|
+
- id: tool-web
|
|
180
|
+
name: '@deepseek-ai/dsh-tool-web'
|
|
181
|
+
config:
|
|
182
|
+
fetch: true
|
|
183
|
+
searchTimeoutMs: 60000
|
|
184
|
+
- id: present
|
|
185
|
+
name: '@deepseek-ai/dsh-tool-present'
|
|
186
|
+
- id: tool-plugin-manager
|
|
187
|
+
name: '@deepseek-ai/dsh-plugin-manager/tools'
|
|
188
|
+
# Declared for parity with the host composition; inert here because
|
|
189
|
+
# this package cannot resolve its row from the preset's base URL.
|
|
190
|
+
disabled: true
|
|
191
|
+
- id: ft-guidance
|
|
192
|
+
name: '@dsh-ft/dsh-fft-settings/agent'
|
|
193
|
+
- id: mcp-dsh-kline
|
|
194
|
+
name: '@deepseek-ai/dsh-mcp-client'
|
|
195
|
+
config:
|
|
196
|
+
serverName: dsh-kline
|
|
197
|
+
transport: stdio
|
|
198
|
+
# Not upstream's row verbatim: `cwd` is this package's own
|
|
199
|
+
# directory — the profile's `cordis.yml` sits next to it in every
|
|
200
|
+
# layout — and `scripts/kline-mcp.mjs` resolves kline from there.
|
|
201
|
+
# `args[0]` is relative to `cwd`, and pointing `cwd` at kline (or
|
|
202
|
+
# at DSH_KLINE_PACKAGE_ROOT) is what broke tarball installs, which
|
|
203
|
+
# nest kline inside this package. See tests/kline-rows.test.mjs.
|
|
204
|
+
command: !!js process.execPath
|
|
205
|
+
args:
|
|
206
|
+
- scripts/kline-mcp.mjs
|
|
207
|
+
cwd: !!js ((process.platform === 'win32' && /^\/[A-Za-z]:\//.test(decodeURIComponent(new URL('./node_modules/@dsh-ft/finance-all-in-one/', ctx.baseUrl).pathname)) && decodeURIComponent(new URL('./node_modules/@dsh-ft/finance-all-in-one/', ctx.baseUrl).pathname).slice(1)) || decodeURIComponent(new URL('./node_modules/@dsh-ft/finance-all-in-one/', ctx.baseUrl).pathname))
|
|
208
|
+
env:
|
|
209
|
+
DSH_KLINE_HOST_PID: !!js String(process.pid)
|
|
210
|
+
DSH_KLINE_DEFER_BOOTSTRAP: '1'
|
|
211
|
+
# The host's own value has to travel explicitly: the MCP client
|
|
212
|
+
# scrubs every `DSH_*` name out of the child environment, so the
|
|
213
|
+
# shim can only honor the documented override if the row passes
|
|
214
|
+
# it on.
|
|
215
|
+
DSH_KLINE_PACKAGE_ROOT: !!js process.env.DSH_KLINE_PACKAGE_ROOT || ''
|
|
216
|
+
DSH_KLINE_PYTHON: !!js process.env.DSH_KLINE_PYTHON || ''
|
|
217
|
+
DSH_KLINE_VENV: !!js process.env.DSH_KLINE_VENV || ''
|
|
218
|
+
DSH_KLINE_CACHE_DIR: !!js process.env.DSH_KLINE_CACHE_DIR || ''
|
|
219
|
+
DSH_KLINE_RUNTIME_DIR: !!js process.env.DSH_KLINE_RUNTIME_DIR || ''
|
|
220
|
+
DSH_KLINE_RUNTIME_MODE: !!js process.env.DSH_KLINE_RUNTIME_MODE || 'auto'
|
|
221
|
+
DSH_KLINE_CHART_HOST: !!js process.env.DSH_KLINE_CHART_HOST || '127.0.0.1'
|
|
222
|
+
DSH_KLINE_CHART_PORT: !!js process.env.DSH_KLINE_CHART_PORT || '8765'
|
|
223
|
+
FTSHARE_SDK_SRC: !!js process.env.FTSHARE_SDK_SRC || ''
|
|
224
|
+
FTSHARE_API_KEY: !!js process.env.FTSHARE_API_KEY || ''
|
|
225
|
+
FTSHARE_API_KEY_FILE: !!js process.env.FTSHARE_API_KEY_FILE || ''
|
|
226
|
+
toolCallTimeoutMs: 120000
|
|
227
|
+
# A fresh Python environment can outlast the MCP SDK's fixed 60 s
|
|
228
|
+
# discovery timeout. Let the launcher's detached bootstrap finish and
|
|
229
|
+
# let reconnect attach the tools, rather than aborting DSH Web itself.
|
|
230
|
+
failOnStartupError: false
|
|
231
|
+
reconnect:
|
|
232
|
+
enabled: true
|
|
233
|
+
initialDelayMs: 500
|
|
234
|
+
maxDelayMs: 30000
|
|
235
|
+
maxAttempts: 10
|
|
236
|
+
- id: ft-ftshare-tools
|
|
237
|
+
name: '@dsh-ft/dsh-fft-ftshare/tools'
|
|
238
|
+
# kline 的 FTShare wrapper 工具(market_pulse / market_board_detail /
|
|
239
|
+
# security_intelligence)不再下发给模型:替代能力走 ftshare_* 与
|
|
240
|
+
# ftshare_call。掩码落到每个 agent 自己的 layer,随 agent 销毁解除,
|
|
241
|
+
# 因此标准模式与 kline 侧边栏、图表一律不受影响。
|
|
242
|
+
- id: ft-ftshare-mask
|
|
243
|
+
name: '@dsh-ft/dsh-fft-ftshare/mask'
|
|
244
|
+
# P7/P8 的修复本体:把 dsh-kline 摘要式 MCP 工具藏在 structuredContent
|
|
245
|
+
# 里的明细投影回模型可见文本,并不再输出裸计数。钩子按 exec.agent 作用域
|
|
246
|
+
# 生效,因此只影响金融模式。
|
|
247
|
+
- id: ft-ftshare-project
|
|
248
|
+
name: '@dsh-ft/dsh-fft-ftshare/project'
|
|
249
|
+
# 把取数结果画成内联 SVG。随包分发一个 skill,模型按 persona 的
|
|
250
|
+
# 触发语加载它;脚本只用 Python 标准库,不引入任何第三方依赖。
|
|
251
|
+
# 挂在 preset 内:只有金融模式的 agent 能看到这个 skill。
|
|
252
|
+
- id: dsh-fft-plot
|
|
253
|
+
name: '@dsh-ft/dsh-fft-plot'
|
|
254
|
+
|
|
255
|
+
- id: agent-preset-registry
|
|
256
|
+
config:
|
|
257
|
+
default: ft-finance
|
package/icon.png
ADDED
|
Binary file
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @dsh-ft/finance-all-in-one — composition bundle for the FT financial workbench.
|
|
3
|
+
* The package's substance is `cordis.patch.yml`, declared by the
|
|
4
|
+
* `dsh.bundle.patch` manifest field and resolved by the profile composer;
|
|
5
|
+
* this module carries no runtime API.
|
|
6
|
+
* @module @dsh-ft/finance-all-in-one
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @dsh-ft/finance-all-in-one — composition bundle for the FT financial workbench.
|
|
3
|
+
* The package's substance is `cordis.patch.yml`, declared by the
|
|
4
|
+
* `dsh.bundle.patch` manifest field and resolved by the profile composer;
|
|
5
|
+
* this module carries no runtime API.
|
|
6
|
+
* @module @dsh-ft/finance-all-in-one
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
package/locale/en.json
ADDED
package/locale/zh.json
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,71 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-ft/finance-all-in-one",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Composition bundle for the FT financial workbench: installs and wires the dsh-fft plugin set with shared defaults.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"types": "lib/index.d.ts",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"author": "Ben <ben@ft.tech>",
|
|
10
|
+
"homepage": "https://github.com/FTShare-Lab/dsh-plugin-fft-bundle#readme",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/FTShare-Lab/dsh-plugin-fft-bundle.git",
|
|
14
|
+
"directory": "packages/dsh-fft-bundle"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/FTShare-Lab/dsh-plugin-fft-bundle/issues"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"dsh-plugin",
|
|
21
|
+
"deepseek-harness",
|
|
22
|
+
"finance",
|
|
23
|
+
"stock",
|
|
24
|
+
"a-share",
|
|
25
|
+
"research",
|
|
26
|
+
"paper-trading",
|
|
27
|
+
"kline"
|
|
28
|
+
],
|
|
29
|
+
"icon": "./icon.png",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./lib/index.d.ts",
|
|
33
|
+
"default": "./lib/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./src/*": "./src/*",
|
|
36
|
+
"./package.json": "./package.json",
|
|
37
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
38
|
+
"./locale/*.json": "./locale/*.json"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"icon.png",
|
|
42
|
+
"LICENSE",
|
|
43
|
+
"README.md",
|
|
44
|
+
"locale/*.json",
|
|
45
|
+
"lib/index.js",
|
|
46
|
+
"lib/index.d.ts",
|
|
47
|
+
"cordis.patch.yml",
|
|
48
|
+
"scripts/kline-mcp.mjs"
|
|
49
|
+
],
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@dsh-ft/dsh-fft-settings": "0.7.1",
|
|
55
|
+
"@dsh-ft/dsh-fft-ftshare": "0.4.2",
|
|
56
|
+
"@dsh-ft/dsh-fft-plot": "0.1.0",
|
|
57
|
+
"@dsh-ft/dsh-fft-paper-trading": "0.7.1",
|
|
58
|
+
"@ftshare-lab/dsh-kline": "0.6.11"
|
|
59
|
+
},
|
|
60
|
+
"engines": {
|
|
61
|
+
"node": ">=22.19.0"
|
|
62
|
+
},
|
|
63
|
+
"dsh": {
|
|
64
|
+
"bundle": {
|
|
65
|
+
"patch": "./cordis.patch.yml"
|
|
66
|
+
},
|
|
67
|
+
"engines": {
|
|
68
|
+
"dsh": ">=0.2.1-rc.2"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Start kline's MCP server from wherever this bundle happens to be installed.
|
|
4
|
+
*
|
|
5
|
+
* The mirrored `mcp-dsh-kline` row in `cordis.patch.yml` cannot name kline's
|
|
6
|
+
* directory: a `!!js` scalar sees only `ctx` and `process`, so a path can only
|
|
7
|
+
* be built from `ctx.baseUrl` — the profile's `cordis.yml`. That reaches a
|
|
8
|
+
* top-level `node_modules/@ftshare-lab/dsh-kline`, which is where a git or
|
|
9
|
+
* registry install hoists it, but a tarball install inlines kline *inside this
|
|
10
|
+
* package* (`<bundle>/node_modules/@ftshare-lab/dsh-kline`). `spawn` then fails
|
|
11
|
+
* on the missing directory with a bare `ENOENT` that names the executable —
|
|
12
|
+
* the one file that certainly exists — instead of the path that does not.
|
|
13
|
+
*
|
|
14
|
+
* The row therefore runs this file from this package's own directory — the
|
|
15
|
+
* profile's `cordis.yml` sits next to it in every layout — and lets Node resolve
|
|
16
|
+
* kline from here: this package's `node_modules` first, then every ancestor, so
|
|
17
|
+
* nested and hoisted installs both work without guessing at either. Nothing else
|
|
18
|
+
* moves: this file only finds kline and hands over the stdio pipes, and kline's
|
|
19
|
+
* own launcher keeps the Python runtime, the bootstrap deferral and the MCP
|
|
20
|
+
* handshake.
|
|
21
|
+
*
|
|
22
|
+
* `DSH_KLINE_PACKAGE_ROOT` still overrides the location, now read here, where a
|
|
23
|
+
* bad value can be reported as the directory it failed on. The row forwards the
|
|
24
|
+
* host's value into this process because the MCP client scrubs every `DSH_*`
|
|
25
|
+
* name out of the child environment.
|
|
26
|
+
*/
|
|
27
|
+
import { spawn } from 'node:child_process'
|
|
28
|
+
import { existsSync } from 'node:fs'
|
|
29
|
+
import { createRequire } from 'node:module'
|
|
30
|
+
import { dirname, join } from 'node:path'
|
|
31
|
+
import { fileURLToPath } from 'node:url'
|
|
32
|
+
|
|
33
|
+
/** kline's launcher, relative to its package directory. */
|
|
34
|
+
const LAUNCHER = 'scripts/run-dsh-kline.mjs'
|
|
35
|
+
|
|
36
|
+
/** The package this file has to locate. */
|
|
37
|
+
const PACKAGE = '@ftshare-lab/dsh-kline'
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Report a failure the host can act on and stop.
|
|
41
|
+
* @param message - one line naming the directory or the override to fix.
|
|
42
|
+
*/
|
|
43
|
+
function fail(message) {
|
|
44
|
+
process.stderr.write(`[dsh-fft-bundle] ${message}\n`)
|
|
45
|
+
process.exit(1)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The kline package directory: the documented override first, then Node
|
|
50
|
+
* resolution from this file.
|
|
51
|
+
* @returns absolute package directory, or undefined when kline is nowhere on
|
|
52
|
+
* the resolution path from this file.
|
|
53
|
+
*/
|
|
54
|
+
function findKlineDirectory() {
|
|
55
|
+
const override = String(process.env.DSH_KLINE_PACKAGE_ROOT ?? '').trim()
|
|
56
|
+
if (override !== '') return override
|
|
57
|
+
try {
|
|
58
|
+
return dirname(createRequire(import.meta.url).resolve(`${PACKAGE}/package.json`))
|
|
59
|
+
} catch {
|
|
60
|
+
return undefined
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const directory = findKlineDirectory()
|
|
65
|
+
if (directory === undefined) {
|
|
66
|
+
fail(`cannot resolve ${PACKAGE} from ${fileURLToPath(import.meta.url)}; set DSH_KLINE_PACKAGE_ROOT to its package directory`)
|
|
67
|
+
}
|
|
68
|
+
const launcher = join(directory, LAUNCHER)
|
|
69
|
+
if (!existsSync(launcher)) {
|
|
70
|
+
fail(`kline launcher does not exist: ${launcher}; set DSH_KLINE_PACKAGE_ROOT to its package directory`)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// kline's launcher expects to be `argv[1]` and owns the child process tree from
|
|
74
|
+
// here on, so run it rather than importing it. `inherit` keeps the MCP stdio
|
|
75
|
+
// pipes between the host and kline's Python server untouched.
|
|
76
|
+
const child = spawn(process.execPath, [launcher], { cwd: directory, stdio: 'inherit', env: process.env })
|
|
77
|
+
for (const signal of ['SIGINT', 'SIGTERM']) process.on(signal, () => child.kill(signal))
|
|
78
|
+
child.on('error', error => fail(`cannot start ${launcher}: ${error.message}`))
|
|
79
|
+
child.on('exit', code => { process.exitCode = code ?? 1 })
|