@tcos/broker-parser 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/.claude/skills/parse-statement/SKILL.md +10 -38
- package/README.en.md +66 -0
- package/README.md +331 -57
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +60 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/install-skill.d.ts +36 -0
- package/dist/cli/install-skill.d.ts.map +1 -0
- package/dist/cli/install-skill.js +205 -0
- package/dist/cli/install-skill.js.map +1 -0
- package/dist/cli/setup.d.ts +20 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +210 -0
- package/dist/cli/setup.js.map +1 -0
- package/package.json +1 -1
|
@@ -14,46 +14,18 @@ description: 解析券商 PDF 结单文件,提取交易记录、持仓和资
|
|
|
14
14
|
|
|
15
15
|
## Setup
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
先运行以下命令确保环境就绪:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
# 2. 检查 Python 3
|
|
30
|
-
if ! command -v python3 &>/dev/null; then
|
|
31
|
-
if command -v brew &>/dev/null; then
|
|
32
|
-
brew install python3
|
|
33
|
-
elif command -v apt-get &>/dev/null; then
|
|
34
|
-
sudo apt-get install -y python3 python3-pip
|
|
35
|
-
else
|
|
36
|
-
echo "ERROR: Cannot install Python automatically. Please install Python 3 manually."
|
|
37
|
-
exit 1
|
|
38
|
-
fi
|
|
39
|
-
fi
|
|
40
|
-
|
|
41
|
-
# 3. 检查并安装 pdfplumber
|
|
42
|
-
if ! python3 -c "import pdfplumber" 2>/dev/null; then
|
|
43
|
-
pip3 install pdfplumber
|
|
44
|
-
fi
|
|
45
|
-
|
|
46
|
-
# 4. 检查 poppler(pdfplumber 底层依赖)
|
|
47
|
-
if ! command -v pdftotext &>/dev/null; then
|
|
48
|
-
if command -v brew &>/dev/null; then
|
|
49
|
-
brew install poppler
|
|
50
|
-
elif command -v apt-get &>/dev/null; then
|
|
51
|
-
sudo apt-get install -y poppler-utils
|
|
52
|
-
fi
|
|
53
|
-
fi
|
|
54
|
-
|
|
55
|
-
echo "tcos-parse setup complete"
|
|
56
|
-
tcos-parse --version
|
|
20
|
+
npx @tcos/broker-parser setup
|
|
21
|
+
npx @tcos/broker-parser install-skill
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
如果已经全局安装过 `@tcos/broker-parser`,也可以使用:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
tcos-parse setup
|
|
28
|
+
tcos-parse install-skill
|
|
57
29
|
```
|
|
58
30
|
|
|
59
31
|
## 使用方式
|
package/README.en.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# @tcos/broker-parser
|
|
2
|
+
|
|
3
|
+
> English reference page. The primary documentation is maintained in Chinese.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/biggersun/broker-parser/actions)
|
|
6
|
+
[](https://www.npmjs.com/package/@tcos/broker-parser)
|
|
7
|
+
[](./LICENSE)
|
|
8
|
+
|
|
9
|
+
Primary documentation: [README.md](./README.md)
|
|
10
|
+
|
|
11
|
+
## What this package does
|
|
12
|
+
|
|
13
|
+
`@tcos/broker-parser` parses brokerage PDF statements into structured JSON.
|
|
14
|
+
|
|
15
|
+
Current support:
|
|
16
|
+
|
|
17
|
+
- Phillip Securities
|
|
18
|
+
|
|
19
|
+
Usage modes:
|
|
20
|
+
|
|
21
|
+
- CLI
|
|
22
|
+
- npm package
|
|
23
|
+
- AI skill for Claude Code, Codex, and OpenClaw
|
|
24
|
+
|
|
25
|
+
## Recommended setup
|
|
26
|
+
|
|
27
|
+
For full details, troubleshooting, environment compatibility, and upgrade notes, see the Chinese README:
|
|
28
|
+
|
|
29
|
+
- [安装与环境说明](./README.md#运行环境要求)
|
|
30
|
+
- [Skill 安装详解](./README.md#skill-安装详解)
|
|
31
|
+
- [常见问题](./README.md#常见问题)
|
|
32
|
+
- [方案评审结论](./README.md#方案评审结论)
|
|
33
|
+
|
|
34
|
+
Typical commands:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx @tcos/broker-parser setup
|
|
38
|
+
npx @tcos/broker-parser install-skill
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
CLI example:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install -g @tcos/broker-parser
|
|
45
|
+
tcos-parse statement.pdf
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
SDK example:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { ParsePipeline, PhillipPlugin, PluginRegistry } from '@tcos/broker-parser';
|
|
52
|
+
|
|
53
|
+
const registry = new PluginRegistry();
|
|
54
|
+
registry.register(new PhillipPlugin());
|
|
55
|
+
|
|
56
|
+
const pipeline = new ParsePipeline(registry);
|
|
57
|
+
const result = await pipeline.parse('./statement.pdf');
|
|
58
|
+
|
|
59
|
+
console.log(result.data);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Notes
|
|
63
|
+
|
|
64
|
+
- The Chinese README is the source of truth.
|
|
65
|
+
- The English file is intentionally brief to avoid documentation drift.
|
|
66
|
+
- If any detail differs, follow [README.md](./README.md).
|
package/README.md
CHANGED
|
@@ -1,74 +1,359 @@
|
|
|
1
1
|
# @tcos/broker-parser
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> 将券商 PDF 结单解析为结构化 JSON
|
|
4
4
|
|
|
5
5
|
[](https://github.com/biggersun/broker-parser/actions)
|
|
6
6
|
[](https://www.npmjs.com/package/@tcos/broker-parser)
|
|
7
7
|
[](./LICENSE)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
English reference: [README.en.md](./README.en.md)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
| ----------------------------- | --------- |
|
|
13
|
-
| Phillip Securities (辉立证券) | Supported |
|
|
11
|
+
`@tcos/broker-parser` 目前支持 3 种使用方式:
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
- `CLI`:直接在命令行解析 PDF
|
|
14
|
+
- `npm package`:在你自己的 Node.js / TypeScript 项目中集成解析能力
|
|
15
|
+
- `AI Skill`:为 Claude Code、Codex、OpenClaw 安装 `/parse-statement`
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
## 支持的券商
|
|
18
|
+
|
|
19
|
+
| 券商 | 状态 |
|
|
20
|
+
| ------------------------------ | ------ |
|
|
21
|
+
| 辉立证券(Phillip Securities) | 已支持 |
|
|
22
|
+
|
|
23
|
+
## 运行环境要求
|
|
24
|
+
|
|
25
|
+
当前版本主要面向类 Unix 环境:
|
|
26
|
+
|
|
27
|
+
- macOS + Homebrew
|
|
28
|
+
- Ubuntu / Debian + `apt-get`
|
|
29
|
+
- 其他 Linux 发行版:如果系统里已经有 `python3`、`pip`、`pdftotext`,也可以使用
|
|
30
|
+
|
|
31
|
+
运行时依赖:
|
|
32
|
+
|
|
33
|
+
- Node.js 18+
|
|
34
|
+
- Python 3.8+
|
|
35
|
+
- Python 包:`pdfplumber`
|
|
36
|
+
- `poppler` 提供的 `pdftotext`
|
|
37
|
+
|
|
38
|
+
内置的 `setup` 命令会在 macOS 和 Ubuntu/Debian 上自动安装或校验这些依赖。其他系统不会强行猜测包管理器,而是提示你手动补齐。
|
|
39
|
+
|
|
40
|
+
## 快速开始
|
|
41
|
+
|
|
42
|
+
### 1. 命令行直接解析
|
|
18
43
|
|
|
19
44
|
```bash
|
|
20
|
-
# Install
|
|
21
45
|
npm install -g @tcos/broker-parser
|
|
22
|
-
|
|
23
|
-
# Parse a PDF statement
|
|
24
46
|
tcos-parse statement.pdf
|
|
47
|
+
```
|
|
25
48
|
|
|
26
|
-
|
|
49
|
+
输出到文件:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
27
52
|
tcos-parse statement.pdf -o result.json
|
|
28
53
|
```
|
|
29
54
|
|
|
30
|
-
###
|
|
55
|
+
### 2. 作为 AI Skill 安装
|
|
56
|
+
|
|
57
|
+
如果你希望在 Agent 里直接使用 `/parse-statement`,推荐按下面顺序执行:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx @tcos/broker-parser setup
|
|
61
|
+
npx @tcos/broker-parser install-skill
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
这两步的职责不同:
|
|
65
|
+
|
|
66
|
+
1. `setup`
|
|
67
|
+
- 安装或检查 `tcos-parse`
|
|
68
|
+
- 安装或检查 `python3`
|
|
69
|
+
- 安装或检查 `pip`
|
|
70
|
+
- 安装或检查 `pdfplumber`
|
|
71
|
+
- 安装或检查 `pdftotext` / `poppler`
|
|
72
|
+
2. `install-skill`
|
|
73
|
+
- 将 `parse-statement` skill 安装到 Agent 可发现的目录
|
|
74
|
+
- Claude Code:`~/.claude/skills/parse-statement`
|
|
75
|
+
- Codex / OpenClaw:`~/.agents/skills/parse-statement`
|
|
76
|
+
|
|
77
|
+
安装完成后,重新打开一个新的 Agent 会话,然后可以直接说:
|
|
78
|
+
|
|
79
|
+
- `帮我解析这个券商 PDF 结单`
|
|
80
|
+
- `读取这个辉立证券结单并返回 JSON`
|
|
81
|
+
- `从这个 PDF 提取交易记录、持仓和账户汇总`
|
|
82
|
+
|
|
83
|
+
### 3. 作为 npm 包使用
|
|
31
84
|
|
|
32
85
|
```typescript
|
|
33
|
-
import { ParsePipeline,
|
|
86
|
+
import { ParsePipeline, PhillipPlugin, PluginRegistry } from '@tcos/broker-parser';
|
|
34
87
|
|
|
35
88
|
const registry = new PluginRegistry();
|
|
36
89
|
registry.register(new PhillipPlugin());
|
|
37
|
-
const pipeline = new ParsePipeline(registry);
|
|
38
90
|
|
|
91
|
+
const pipeline = new ParsePipeline(registry);
|
|
39
92
|
const result = await pipeline.parse('./statement.pdf');
|
|
93
|
+
|
|
40
94
|
console.log(result.data);
|
|
41
95
|
```
|
|
42
96
|
|
|
43
|
-
|
|
97
|
+
## Skill 安装详解
|
|
44
98
|
|
|
45
|
-
|
|
99
|
+
### 第一步:`setup`
|
|
46
100
|
|
|
47
|
-
|
|
101
|
+
```bash
|
|
102
|
+
npx @tcos/broker-parser setup
|
|
103
|
+
```
|
|
48
104
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
-
|
|
52
|
-
|
|
53
|
-
|
|
105
|
+
这个命令会做什么:
|
|
106
|
+
|
|
107
|
+
1. 检查 `PATH` 里是否已经有 `tcos-parse`
|
|
108
|
+
2. 如果没有,执行 `npm install -g @tcos/broker-parser`
|
|
109
|
+
3. 检查是否存在 `python3`
|
|
110
|
+
4. 如果没有:
|
|
111
|
+
- macOS:执行 `brew install python3`
|
|
112
|
+
- Ubuntu / Debian:执行 `sudo apt-get install -y python3 python3-pip`
|
|
113
|
+
5. 检查 `python3 -m pip` 是否可用
|
|
114
|
+
6. 如果不可用,执行 `python3 -m ensurepip --upgrade`
|
|
115
|
+
7. 检查是否能导入 `pdfplumber`
|
|
116
|
+
8. 如果没有,执行 `python3 -m pip install --user pdfplumber`
|
|
117
|
+
9. 检查是否存在 `pdftotext`
|
|
118
|
+
10. 如果没有:
|
|
119
|
+
- macOS:执行 `brew install poppler`
|
|
120
|
+
- Ubuntu / Debian:执行 `sudo apt-get install -y poppler-utils`
|
|
121
|
+
|
|
122
|
+
适合的环境:
|
|
123
|
+
|
|
124
|
+
- 个人 macOS 开发机器
|
|
125
|
+
- Ubuntu / Debian 开发机或云主机
|
|
126
|
+
- 允许使用 `brew` / `apt-get` / `sudo` 的 shell 环境
|
|
127
|
+
|
|
128
|
+
不太适合的环境:
|
|
129
|
+
|
|
130
|
+
- 企业受限机器
|
|
131
|
+
- 没有系统包管理器的极简容器
|
|
132
|
+
- Windows 原生环境
|
|
133
|
+
|
|
134
|
+
可能的副作用:
|
|
135
|
+
|
|
136
|
+
- 会全局安装 `@tcos/broker-parser`
|
|
137
|
+
- 在 Linux 上可能触发 `sudo` 提示
|
|
138
|
+
- 会把 `pdfplumber` 安装到当前用户的 Python 用户目录
|
|
139
|
+
- 可能升级你的系统 Python / poppler 包版本
|
|
140
|
+
|
|
141
|
+
可选参数:
|
|
142
|
+
|
|
143
|
+
- `--dry-run`:只展示即将执行的动作,不真正执行
|
|
144
|
+
|
|
145
|
+
示例:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npx @tcos/broker-parser setup --dry-run
|
|
149
|
+
tcos-parse setup
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
建议先用 `--dry-run` 的情况:
|
|
153
|
+
|
|
154
|
+
- 共享机器
|
|
155
|
+
- CI / Docker 环境
|
|
156
|
+
- 你想先确认它到底会执行哪些安装命令
|
|
157
|
+
|
|
158
|
+
### 第二步:`install-skill`
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
npx @tcos/broker-parser install-skill
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
这个命令会做什么:
|
|
165
|
+
|
|
166
|
+
1. 找到 `@tcos/broker-parser` 包内自带的 `parse-statement` skill
|
|
167
|
+
2. 自动探测宿主目录:
|
|
168
|
+
- Claude Code -> `~/.claude/skills`
|
|
169
|
+
- Codex / OpenClaw -> `~/.agents/skills`
|
|
170
|
+
3. 将 skill 复制到对应目录
|
|
171
|
+
4. 写入一个小的 manifest 文件,用于后续识别该目录是否由 broker-parser 安装
|
|
172
|
+
5. 如果检测到相同版本已经安装,会直接跳过
|
|
173
|
+
|
|
174
|
+
适合的环境:
|
|
175
|
+
|
|
176
|
+
- 本地开发机器
|
|
177
|
+
- 你拥有 `~/.claude` 或 `~/.agents` 写权限的环境
|
|
178
|
+
- 可以方便重启 Agent 会话的环境
|
|
179
|
+
|
|
180
|
+
可能的副作用:
|
|
181
|
+
|
|
182
|
+
- 会创建或更新 `~/.claude/skills/parse-statement`
|
|
183
|
+
- 会创建或更新 `~/.agents/skills/parse-statement`
|
|
184
|
+
- 不会自动重启你的 Agent 会话
|
|
185
|
+
- 加上 `--force` 时,会先删除旧目录再覆盖安装
|
|
186
|
+
|
|
187
|
+
可选参数:
|
|
188
|
+
|
|
189
|
+
- `--host auto`:自动探测宿主,默认值
|
|
190
|
+
- `--host claude`:只安装 Claude Code 版本
|
|
191
|
+
- `--host agents`:只安装 Codex / OpenClaw 版本
|
|
192
|
+
- `--dry-run`:只展示安装计划,不真正写文件
|
|
193
|
+
- `--force`:覆盖已有冲突目录
|
|
194
|
+
|
|
195
|
+
示例:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
npx @tcos/broker-parser install-skill --host claude
|
|
199
|
+
npx @tcos/broker-parser install-skill --host agents
|
|
200
|
+
npx @tcos/broker-parser install-skill --dry-run
|
|
201
|
+
```
|
|
54
202
|
|
|
55
|
-
|
|
203
|
+
一行完成首次安装:
|
|
56
204
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
205
|
+
```bash
|
|
206
|
+
npx @tcos/broker-parser setup && npx @tcos/broker-parser install-skill
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
适合直接用这一行的情况:
|
|
210
|
+
|
|
211
|
+
- 新机器首次安装
|
|
212
|
+
- 你只想要最短可复制命令
|
|
213
|
+
|
|
214
|
+
不建议直接一行跑的情况:
|
|
215
|
+
|
|
216
|
+
- 你想先审查 setup 会执行哪些命令
|
|
217
|
+
- 当前机器是共享环境或受限环境
|
|
218
|
+
- 你只想刷新 skill,不想动系统运行时
|
|
219
|
+
|
|
220
|
+
### 升级与重装
|
|
221
|
+
|
|
222
|
+
推荐升级流程:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
npm install -g @tcos/broker-parser@latest
|
|
226
|
+
tcos-parse setup
|
|
227
|
+
tcos-parse install-skill --force
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
为什么升级后建议再跑一次 `install-skill --force`:
|
|
231
|
+
|
|
232
|
+
- 当前 skill 安装方式是“复制目录”,不是软链
|
|
233
|
+
- 这样可以避免 `npx` 临时缓存路径失效
|
|
234
|
+
- 但这也意味着升级 npm 包后,旧的 skill 目录不会自动覆盖
|
|
235
|
+
|
|
236
|
+
如果你只升级了 CLI,不在意 skill 文案或 prompt 版本,也可以跳过 `install-skill --force`
|
|
237
|
+
|
|
238
|
+
### 手动 fallback
|
|
239
|
+
|
|
240
|
+
如果你明确想要用软链,而不是复制目录,可以手动这样做:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
npm install -g @tcos/broker-parser
|
|
244
|
+
mkdir -p ~/.claude/skills ~/.agents/skills
|
|
245
|
+
ln -sfn "$(npm root -g)/@tcos/broker-parser/.claude/skills/parse-statement" ~/.claude/skills/parse-statement
|
|
246
|
+
ln -sfn "$(npm root -g)/@tcos/broker-parser/.claude/skills/parse-statement" ~/.agents/skills/parse-statement
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
只有在这些情况下才推荐手动软链:
|
|
250
|
+
|
|
251
|
+
- 你明确想保持 skill 与全局 npm 包目录同步
|
|
252
|
+
- 你正在本地调试 skill 文件
|
|
253
|
+
- 你确认全局 npm 安装路径是稳定的
|
|
254
|
+
|
|
255
|
+
如果你主要依赖 `npx @tcos/broker-parser ...`,不建议手动软链,因为 `npx` 可能来自临时缓存目录。
|
|
256
|
+
|
|
257
|
+
## 环境适配建议
|
|
258
|
+
|
|
259
|
+
| 环境 | `setup` | `install-skill` | 建议 |
|
|
260
|
+
| --------------------------- | ---------- | --------------- | ------------------------- |
|
|
261
|
+
| macOS + Homebrew | 完整支持 | 完整支持 | 最佳体验 |
|
|
262
|
+
| Ubuntu / Debian + `apt-get` | 完整支持 | 完整支持 | 最佳体验 |
|
|
263
|
+
| 其他 Linux 发行版 | 部分支持 | 完整支持 | 先手动补 Python / poppler |
|
|
264
|
+
| sudo 受限的远程主机 | 部分支持 | 通常可用 | 先跑 `setup --dry-run` |
|
|
265
|
+
| CI / Docker 镜像 | 部分支持 | 通常没必要 | 更建议把依赖烘焙进镜像 |
|
|
266
|
+
| Windows 原生环境 | 未正式支持 | 不确定 | 如有需要建议使用 WSL |
|
|
267
|
+
|
|
268
|
+
## 常见问题
|
|
269
|
+
|
|
270
|
+
### `setup` 过程中要求输入 `sudo`
|
|
271
|
+
|
|
272
|
+
这是预期行为。Ubuntu / Debian 上如果缺少 `python3` 或 `poppler-utils`,会通过 `sudo apt-get` 安装。
|
|
273
|
+
|
|
274
|
+
如果当前机器没有 sudo 权限:
|
|
275
|
+
|
|
276
|
+
- 先手动安装这些系统依赖
|
|
277
|
+
- 再重新执行 `tcos-parse setup`
|
|
68
278
|
|
|
69
|
-
|
|
279
|
+
### `setup` 提示需要手动安装依赖
|
|
70
280
|
|
|
281
|
+
说明当前系统既没有 `brew`,也没有 `apt-get`。此时需要你手动补齐:
|
|
282
|
+
|
|
283
|
+
- `python3`
|
|
284
|
+
- `python3 -m pip`
|
|
285
|
+
- `python3 -m pip install --user pdfplumber`
|
|
286
|
+
- `pdftotext` / `poppler`
|
|
287
|
+
|
|
288
|
+
补齐后再跑一次 `tcos-parse setup`。
|
|
289
|
+
|
|
290
|
+
### `install-skill` 提示没有检测到支持的宿主
|
|
291
|
+
|
|
292
|
+
常见原因:
|
|
293
|
+
|
|
294
|
+
- Claude / Codex / OpenClaw 还没安装
|
|
295
|
+
- 宿主命令不在 `PATH`
|
|
296
|
+
- `~/.claude` 或 `~/.agents` 目录还没创建
|
|
297
|
+
|
|
298
|
+
这时可以显式指定:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
tcos-parse install-skill --host claude
|
|
302
|
+
tcos-parse install-skill --host agents
|
|
71
303
|
```
|
|
304
|
+
|
|
305
|
+
### `install-skill` 提示目标目录已存在
|
|
306
|
+
|
|
307
|
+
这表示 broker-parser 默认不会覆盖已有目录,以免误删你自己的 skill 内容。
|
|
308
|
+
|
|
309
|
+
确认可以覆盖后,执行:
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
tcos-parse install-skill --force
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### 安装后 skill 没有立即生效
|
|
316
|
+
|
|
317
|
+
这通常不是安装失败,而是 Agent 进程还没重新扫描 skill 目录。
|
|
318
|
+
|
|
319
|
+
做法:
|
|
320
|
+
|
|
321
|
+
- 关闭当前会话
|
|
322
|
+
- 新开一个 Claude / Codex / OpenClaw 会话
|
|
323
|
+
- 再尝试调用 `/parse-statement`
|
|
324
|
+
|
|
325
|
+
## 方案评审结论
|
|
326
|
+
|
|
327
|
+
当前方案整体可用,没有明显阻塞问题,但边界需要明确:
|
|
328
|
+
|
|
329
|
+
- `setup` 只对 `brew` 和 `apt-get` 做了自动化支持,其他 Linux 发行版依然以手动安装为主
|
|
330
|
+
- `install-skill` 的宿主探测是保守策略;探测失败时需要用户手动指定 `--host`
|
|
331
|
+
- skill 目录使用复制而不是软链,优点是不会因 `npx` 临时路径失效;代价是升级后需要显式 `--force` 刷新
|
|
332
|
+
- 当前流程默认用户拥有自己 home 目录的写权限,不适合受严格权限控制的多用户共享系统
|
|
333
|
+
|
|
334
|
+
## CLI 命令参考
|
|
335
|
+
|
|
336
|
+
| 命令 | 说明 |
|
|
337
|
+
| ------------------------------------- | ----------------------------- |
|
|
338
|
+
| `tcos-parse <pdf>` | 解析 PDF,输出 JSON 到 stdout |
|
|
339
|
+
| `tcos-parse <pdf> -o out.json` | 输出到文件 |
|
|
340
|
+
| `tcos-parse <pdf> --raw` | 只输出 Stage1 原始数据 |
|
|
341
|
+
| `tcos-parse <pdf> --no-clean` | 跳过 Stage3 清理 |
|
|
342
|
+
| `tcos-parse <pdf> -b phillip` | 指定券商,跳过自动检测 |
|
|
343
|
+
| `tcos-parse --detect <pdf>` | 检测 PDF 属于哪个券商 |
|
|
344
|
+
| `tcos-parse --list-parsers` | 列出支持的券商解析器 |
|
|
345
|
+
| `tcos-parse <pdf> -v` | 在 stderr 输出阶段耗时 |
|
|
346
|
+
| `tcos-parse <pdf> -q` | 静默模式,只输出 JSON |
|
|
347
|
+
| `tcos-parse setup` | 安装 / 检查运行时依赖 |
|
|
348
|
+
| `tcos-parse setup --dry-run` | 预览 setup 将执行的动作 |
|
|
349
|
+
| `tcos-parse install-skill` | 安装 `/parse-statement` skill |
|
|
350
|
+
| `tcos-parse install-skill --dry-run` | 预览 skill 安装目标 |
|
|
351
|
+
| `tcos-parse install-skill --force` | 覆盖已有冲突目录 |
|
|
352
|
+
| `tcos-parse install-skill --host ...` | 只安装到指定宿主 |
|
|
353
|
+
|
|
354
|
+
## 解析流程
|
|
355
|
+
|
|
356
|
+
```text
|
|
72
357
|
PDF File
|
|
73
358
|
|
|
|
74
359
|
Stage1: Extract (pdfplumber)
|
|
@@ -83,7 +368,7 @@ PDF File
|
|
|
83
368
|
JSON Output
|
|
84
369
|
```
|
|
85
370
|
|
|
86
|
-
##
|
|
371
|
+
## 输出格式
|
|
87
372
|
|
|
88
373
|
```json
|
|
89
374
|
{
|
|
@@ -98,7 +383,7 @@ PDF File
|
|
|
98
383
|
"transactionType": "BUY",
|
|
99
384
|
"quantity": 1000,
|
|
100
385
|
"price": 12.34,
|
|
101
|
-
"amount": -12340
|
|
386
|
+
"amount": -12340,
|
|
102
387
|
"currency": "HKD"
|
|
103
388
|
}
|
|
104
389
|
],
|
|
@@ -107,44 +392,33 @@ PDF File
|
|
|
107
392
|
{
|
|
108
393
|
"symbol": "HKD",
|
|
109
394
|
"assetCategory": "Cash",
|
|
110
|
-
"quantity": 50000
|
|
395
|
+
"quantity": 50000,
|
|
111
396
|
"currency": "HKD"
|
|
112
397
|
}
|
|
113
398
|
]
|
|
114
399
|
}
|
|
115
400
|
```
|
|
116
401
|
|
|
117
|
-
|
|
402
|
+
关键类型:
|
|
118
403
|
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
404
|
+
- `StatementData`:完整结单结果
|
|
405
|
+
- `TradeData`:单条交易记录
|
|
406
|
+
- `IPOData`:IPO 申购 / 分配记录
|
|
407
|
+
- `SnapshotData`:持仓快照
|
|
123
408
|
|
|
124
|
-
##
|
|
409
|
+
## 新增券商解析器
|
|
125
410
|
|
|
126
|
-
|
|
411
|
+
新增券商插件的实现方式见 [CONTRIBUTING.md](./CONTRIBUTING.md)。
|
|
127
412
|
|
|
128
|
-
##
|
|
413
|
+
## 开发
|
|
129
414
|
|
|
130
415
|
```bash
|
|
131
|
-
# Install dependencies
|
|
132
416
|
npm install
|
|
133
|
-
|
|
134
|
-
# Run CI tests (Stage2 + CLI, no PDF dependency)
|
|
135
417
|
npm test
|
|
136
|
-
|
|
137
|
-
# Run all tests including Stage1 (requires local PDFs)
|
|
138
418
|
npm run test:local
|
|
139
|
-
|
|
140
|
-
# Lint & format
|
|
141
419
|
npm run lint
|
|
142
420
|
npm run format:check
|
|
143
|
-
|
|
144
|
-
# Type check
|
|
145
421
|
npm run typecheck
|
|
146
|
-
|
|
147
|
-
# Build
|
|
148
422
|
npm run build
|
|
149
423
|
```
|
|
150
424
|
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* tcos-parse --list-parsers # 列出支持的券商
|
|
13
13
|
* tcos-parse -v <pdf> # 显示各阶段耗时
|
|
14
14
|
* tcos-parse -q <pdf> # 静默模式,只输出 JSON
|
|
15
|
+
* tcos-parse setup # 安装运行时依赖
|
|
16
|
+
* tcos-parse install-skill # 安装 parse-statement Skill
|
|
15
17
|
*/
|
|
16
18
|
export {};
|
|
17
19
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/cli/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG"}
|
package/dist/cli/index.js
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* tcos-parse --list-parsers # 列出支持的券商
|
|
14
14
|
* tcos-parse -v <pdf> # 显示各阶段耗时
|
|
15
15
|
* tcos-parse -q <pdf> # 静默模式,只输出 JSON
|
|
16
|
+
* tcos-parse setup # 安装运行时依赖
|
|
17
|
+
* tcos-parse install-skill # 安装 parse-statement Skill
|
|
16
18
|
*/
|
|
17
19
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
20
|
if (k2 === undefined) k2 = k;
|
|
@@ -54,6 +56,8 @@ const commander_1 = require("commander");
|
|
|
54
56
|
const pipeline_1 = require("../core/pipeline");
|
|
55
57
|
const registry_1 = require("../core/registry");
|
|
56
58
|
const phillip_1 = require("../parsers/phillip");
|
|
59
|
+
const install_skill_1 = require("./install-skill");
|
|
60
|
+
const setup_1 = require("./setup");
|
|
57
61
|
// 初始化插件注册表
|
|
58
62
|
const registry = new registry_1.PluginRegistry();
|
|
59
63
|
registry.register(new phillip_1.PhillipPlugin());
|
|
@@ -63,6 +67,62 @@ program
|
|
|
63
67
|
.name('tcos-parse')
|
|
64
68
|
.description('Parse brokerage PDF statements into structured JSON')
|
|
65
69
|
.version('0.1.0');
|
|
70
|
+
program
|
|
71
|
+
.command('install-skill')
|
|
72
|
+
.description('install parse-statement skill for Claude, Codex, or OpenClaw')
|
|
73
|
+
.option('--host <host>', 'install target: auto | claude | agents', 'auto')
|
|
74
|
+
.option('--force', 'replace existing target if it already exists')
|
|
75
|
+
.option('--dry-run', 'show planned install actions without writing files')
|
|
76
|
+
.action((opts) => {
|
|
77
|
+
try {
|
|
78
|
+
const result = (0, install_skill_1.installSkill)({
|
|
79
|
+
host: (0, install_skill_1.normalizeInstallHost)(opts.host),
|
|
80
|
+
force: opts.force,
|
|
81
|
+
dryRun: opts.dryRun,
|
|
82
|
+
});
|
|
83
|
+
console.log(`Skill source: ${result.sourcePath}`);
|
|
84
|
+
for (const action of result.actions) {
|
|
85
|
+
const hostLabel = action.host === 'claude' ? 'Claude Code' : 'Agent Skills';
|
|
86
|
+
console.log(`[${hostLabel}] ${action.message}: ${action.targetPath}`);
|
|
87
|
+
}
|
|
88
|
+
if (!opts.dryRun) {
|
|
89
|
+
console.log('Open a new agent session to use /parse-statement.');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
94
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
program
|
|
99
|
+
.command('setup')
|
|
100
|
+
.description('install runtime dependencies required by broker-parser')
|
|
101
|
+
.option('--dry-run', 'show planned setup actions without running commands')
|
|
102
|
+
.action((opts) => {
|
|
103
|
+
try {
|
|
104
|
+
const result = (0, setup_1.setupEnvironment)({
|
|
105
|
+
dryRun: opts.dryRun,
|
|
106
|
+
});
|
|
107
|
+
for (const action of result.actions) {
|
|
108
|
+
const prefix = `[${action.status}]`;
|
|
109
|
+
if (action.command) {
|
|
110
|
+
console.log(`${prefix} ${action.message}: ${action.command} ${action.args?.join(' ') ?? ''}`);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
console.log(`${prefix} ${action.message}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!opts.dryRun) {
|
|
117
|
+
console.log('Setup finished. You can now run tcos-parse or install the skill.');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
122
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
66
126
|
// 主命令:解析 PDF
|
|
67
127
|
program
|
|
68
128
|
.argument('[pdf]', 'PDF statement file to parse')
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;AACA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type SkillInstallHost = 'auto' | 'claude' | 'agents';
|
|
2
|
+
export type SkillTarget = 'claude' | 'agents';
|
|
3
|
+
export interface DetectHostsOptions {
|
|
4
|
+
homeDir?: string;
|
|
5
|
+
hasCommand?: (command: string) => boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface InstallSkillOptions extends DetectHostsOptions {
|
|
8
|
+
host?: SkillInstallHost;
|
|
9
|
+
dryRun?: boolean;
|
|
10
|
+
force?: boolean;
|
|
11
|
+
packageRoot?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface InstallSkillAction {
|
|
14
|
+
host: SkillTarget;
|
|
15
|
+
sourcePath: string;
|
|
16
|
+
targetPath: string;
|
|
17
|
+
status: 'installed' | 'skipped';
|
|
18
|
+
message: string;
|
|
19
|
+
}
|
|
20
|
+
export interface InstallSkillResult {
|
|
21
|
+
sourcePath: string;
|
|
22
|
+
actions: InstallSkillAction[];
|
|
23
|
+
}
|
|
24
|
+
/** 返回包内 Skill 的发布路径。 */
|
|
25
|
+
export declare function resolveSkillSourcePath(packageRoot?: string): string;
|
|
26
|
+
/** 从 src/cli 或 dist/cli 目录反推出包根目录。 */
|
|
27
|
+
export declare function resolvePackageRoot(currentDir?: string): string;
|
|
28
|
+
/** 根据本机环境探测需要安装到哪些宿主目录。 */
|
|
29
|
+
export declare function detectInstallTargets(options?: DetectHostsOptions): SkillTarget[];
|
|
30
|
+
/** 校验并规范化 host 参数。 */
|
|
31
|
+
export declare function normalizeInstallHost(host: string): SkillInstallHost;
|
|
32
|
+
/** 返回指定宿主的 Skill 安装目标路径。 */
|
|
33
|
+
export declare function resolveSkillTargetPath(host: SkillTarget, homeDir?: string): string;
|
|
34
|
+
/** 以统一规则安装 parse-statement Skill。 */
|
|
35
|
+
export declare function installSkill(options?: InstallSkillOptions): InstallSkillResult;
|
|
36
|
+
//# sourceMappingURL=install-skill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-skill.d.ts","sourceRoot":"","sources":["../../src/cli/install-skill.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAC5D,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9C,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;CAC3C;AAED,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,WAAW,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AA4CD,wBAAwB;AACxB,wBAAgB,sBAAsB,CAAC,WAAW,SAAuB,GAAG,MAAM,CAEjF;AAED,sCAAsC;AACtC,wBAAgB,kBAAkB,CAAC,UAAU,SAAY,GAAG,MAAM,CAEjE;AAED,2BAA2B;AAC3B,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,EAAE,CAiBpF;AAED,sBAAsB;AACtB,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAMnE;AAED,4BAA4B;AAC5B,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,SAAe,GAAG,MAAM,CAMxF;AA8BD,qCAAqC;AACrC,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,kBAAkB,CAiGlF"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.resolveSkillSourcePath = resolveSkillSourcePath;
|
|
37
|
+
exports.resolvePackageRoot = resolvePackageRoot;
|
|
38
|
+
exports.detectInstallTargets = detectInstallTargets;
|
|
39
|
+
exports.normalizeInstallHost = normalizeInstallHost;
|
|
40
|
+
exports.resolveSkillTargetPath = resolveSkillTargetPath;
|
|
41
|
+
exports.installSkill = installSkill;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const os = __importStar(require("os"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const SKILL_NAME = 'parse-statement';
|
|
46
|
+
const MANIFEST_FILE = '.broker-parser-install.json';
|
|
47
|
+
/** 检查命令是否存在于当前 PATH。 */
|
|
48
|
+
function commandExists(command) {
|
|
49
|
+
const pathValue = process.env.PATH;
|
|
50
|
+
if (!pathValue)
|
|
51
|
+
return false;
|
|
52
|
+
for (const dir of pathValue.split(path.delimiter)) {
|
|
53
|
+
if (!dir)
|
|
54
|
+
continue;
|
|
55
|
+
const candidate = path.join(dir, command);
|
|
56
|
+
if (fs.existsSync(candidate)) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
/** 读取当前包的基础信息。 */
|
|
63
|
+
function readPackageInfo(packageRoot) {
|
|
64
|
+
const packageJsonPath = path.join(packageRoot, 'package.json');
|
|
65
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
66
|
+
return {
|
|
67
|
+
name: packageJson.name ?? '@tcos/broker-parser',
|
|
68
|
+
version: packageJson.version ?? '0.0.0',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** 返回包内 Skill 的发布路径。 */
|
|
72
|
+
function resolveSkillSourcePath(packageRoot = resolvePackageRoot()) {
|
|
73
|
+
return path.join(packageRoot, '.claude', 'skills', SKILL_NAME);
|
|
74
|
+
}
|
|
75
|
+
/** 从 src/cli 或 dist/cli 目录反推出包根目录。 */
|
|
76
|
+
function resolvePackageRoot(currentDir = __dirname) {
|
|
77
|
+
return path.resolve(currentDir, '..', '..');
|
|
78
|
+
}
|
|
79
|
+
/** 根据本机环境探测需要安装到哪些宿主目录。 */
|
|
80
|
+
function detectInstallTargets(options = {}) {
|
|
81
|
+
const homeDir = options.homeDir ?? os.homedir();
|
|
82
|
+
const hasCommand = options.hasCommand ?? commandExists;
|
|
83
|
+
const supportsClaude = hasCommand('claude') || fs.existsSync(path.join(homeDir, '.claude'));
|
|
84
|
+
const supportsAgentSkills = hasCommand('codex') || hasCommand('openclaw') || fs.existsSync(path.join(homeDir, '.agents'));
|
|
85
|
+
const targets = [];
|
|
86
|
+
if (supportsClaude) {
|
|
87
|
+
targets.push('claude');
|
|
88
|
+
}
|
|
89
|
+
if (supportsAgentSkills) {
|
|
90
|
+
targets.push('agents');
|
|
91
|
+
}
|
|
92
|
+
return targets;
|
|
93
|
+
}
|
|
94
|
+
/** 校验并规范化 host 参数。 */
|
|
95
|
+
function normalizeInstallHost(host) {
|
|
96
|
+
if (host === 'auto' || host === 'claude' || host === 'agents') {
|
|
97
|
+
return host;
|
|
98
|
+
}
|
|
99
|
+
throw new Error(`Invalid host: ${host}. Expected auto, claude, or agents.`);
|
|
100
|
+
}
|
|
101
|
+
/** 返回指定宿主的 Skill 安装目标路径。 */
|
|
102
|
+
function resolveSkillTargetPath(host, homeDir = os.homedir()) {
|
|
103
|
+
if (host === 'claude') {
|
|
104
|
+
return path.join(homeDir, '.claude', 'skills', SKILL_NAME);
|
|
105
|
+
}
|
|
106
|
+
return path.join(homeDir, '.agents', 'skills', SKILL_NAME);
|
|
107
|
+
}
|
|
108
|
+
/** 读取安装清单,用于识别是否为 broker-parser 管理的目录。 */
|
|
109
|
+
function readInstallManifest(targetPath) {
|
|
110
|
+
const manifestPath = path.join(targetPath, MANIFEST_FILE);
|
|
111
|
+
if (!fs.existsSync(manifestPath)) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** 复制 Skill 目录并写入安装清单,避免 npx 临时目录软链失效。 */
|
|
122
|
+
function copySkillDirectory(sourcePath, targetPath, manifest) {
|
|
123
|
+
fs.cpSync(sourcePath, targetPath, { recursive: true });
|
|
124
|
+
fs.writeFileSync(path.join(targetPath, MANIFEST_FILE), JSON.stringify(manifest, null, 2), 'utf-8');
|
|
125
|
+
}
|
|
126
|
+
/** 以统一规则安装 parse-statement Skill。 */
|
|
127
|
+
function installSkill(options = {}) {
|
|
128
|
+
const packageRoot = options.packageRoot ?? resolvePackageRoot();
|
|
129
|
+
const packageInfo = readPackageInfo(packageRoot);
|
|
130
|
+
const manifest = {
|
|
131
|
+
...packageInfo,
|
|
132
|
+
skillName: SKILL_NAME,
|
|
133
|
+
};
|
|
134
|
+
const sourcePath = resolveSkillSourcePath(packageRoot);
|
|
135
|
+
const homeDir = options.homeDir ?? os.homedir();
|
|
136
|
+
const host = normalizeInstallHost(options.host ?? 'auto');
|
|
137
|
+
const dryRun = options.dryRun ?? false;
|
|
138
|
+
const force = options.force ?? false;
|
|
139
|
+
if (!fs.existsSync(sourcePath)) {
|
|
140
|
+
throw new Error(`Skill source not found: ${sourcePath}`);
|
|
141
|
+
}
|
|
142
|
+
const targets = host === 'auto' ? detectInstallTargets(options) : [host];
|
|
143
|
+
if (targets.length === 0) {
|
|
144
|
+
throw new Error('No supported host detected. Use --host claude or --host agents to install manually.');
|
|
145
|
+
}
|
|
146
|
+
const actions = [];
|
|
147
|
+
for (const targetHost of targets) {
|
|
148
|
+
const targetPath = resolveSkillTargetPath(targetHost, homeDir);
|
|
149
|
+
const targetDir = path.dirname(targetPath);
|
|
150
|
+
if (!dryRun) {
|
|
151
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
152
|
+
}
|
|
153
|
+
if (fs.existsSync(targetPath)) {
|
|
154
|
+
const stat = fs.lstatSync(targetPath);
|
|
155
|
+
if (stat.isSymbolicLink()) {
|
|
156
|
+
const currentLink = fs.readlinkSync(targetPath);
|
|
157
|
+
const resolvedLink = path.resolve(path.dirname(targetPath), currentLink);
|
|
158
|
+
if (resolvedLink === sourcePath) {
|
|
159
|
+
actions.push({
|
|
160
|
+
host: targetHost,
|
|
161
|
+
sourcePath,
|
|
162
|
+
targetPath,
|
|
163
|
+
status: 'skipped',
|
|
164
|
+
message: 'already installed',
|
|
165
|
+
});
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (stat.isDirectory()) {
|
|
170
|
+
const existingManifest = readInstallManifest(targetPath);
|
|
171
|
+
if (existingManifest &&
|
|
172
|
+
existingManifest.name === manifest.name &&
|
|
173
|
+
existingManifest.version === manifest.version &&
|
|
174
|
+
existingManifest.skillName === manifest.skillName) {
|
|
175
|
+
actions.push({
|
|
176
|
+
host: targetHost,
|
|
177
|
+
sourcePath,
|
|
178
|
+
targetPath,
|
|
179
|
+
status: 'skipped',
|
|
180
|
+
message: 'already installed',
|
|
181
|
+
});
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (!force) {
|
|
186
|
+
throw new Error(`Skill target already exists: ${targetPath}. Re-run with --force to replace it.`);
|
|
187
|
+
}
|
|
188
|
+
if (!dryRun) {
|
|
189
|
+
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (!dryRun) {
|
|
193
|
+
copySkillDirectory(sourcePath, targetPath, manifest);
|
|
194
|
+
}
|
|
195
|
+
actions.push({
|
|
196
|
+
host: targetHost,
|
|
197
|
+
sourcePath,
|
|
198
|
+
targetPath,
|
|
199
|
+
status: 'installed',
|
|
200
|
+
message: dryRun ? 'planned' : 'installed',
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return { sourcePath, actions };
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=install-skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-skill.js","sourceRoot":"","sources":["../../src/cli/install-skill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface SetupEnvironmentOptions {
|
|
2
|
+
dryRun?: boolean;
|
|
3
|
+
hasCommand?: (command: string) => boolean;
|
|
4
|
+
pythonHasModule?: (pythonBin: string, moduleName: string) => boolean;
|
|
5
|
+
pythonHasPip?: (pythonBin: string) => boolean;
|
|
6
|
+
runCommand?: (command: string, args: string[]) => void;
|
|
7
|
+
packageName?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SetupAction {
|
|
10
|
+
status: 'installed' | 'skipped' | 'planned' | 'manual';
|
|
11
|
+
message: string;
|
|
12
|
+
command?: string;
|
|
13
|
+
args?: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface SetupEnvironmentResult {
|
|
16
|
+
actions: SetupAction[];
|
|
17
|
+
}
|
|
18
|
+
/** 安装或检查运行时依赖。 */
|
|
19
|
+
export declare function setupEnvironment(options?: SetupEnvironmentOptions): SetupEnvironmentResult;
|
|
20
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IACrE,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;IAC9C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAwED,kBAAkB;AAClB,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B,GAAG,sBAAsB,CAgH9F"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.setupEnvironment = setupEnvironment;
|
|
37
|
+
const child_process_1 = require("child_process");
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
/** 检查命令是否存在于当前 PATH。 */
|
|
40
|
+
function commandExists(command) {
|
|
41
|
+
const pathValue = process.env.PATH;
|
|
42
|
+
if (!pathValue)
|
|
43
|
+
return false;
|
|
44
|
+
for (const dir of pathValue.split(path.delimiter)) {
|
|
45
|
+
if (!dir)
|
|
46
|
+
continue;
|
|
47
|
+
const candidate = path.join(dir, command);
|
|
48
|
+
const probe = (0, child_process_1.spawnSync)(candidate, ['--version'], { stdio: 'ignore' });
|
|
49
|
+
if (!probe.error) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
/** 检查 python 模块是否可导入。 */
|
|
56
|
+
function defaultPythonHasModule(pythonBin, moduleName) {
|
|
57
|
+
const probe = (0, child_process_1.spawnSync)(pythonBin, ['-c', `import ${moduleName}`], { stdio: 'ignore' });
|
|
58
|
+
return probe.status === 0;
|
|
59
|
+
}
|
|
60
|
+
/** 检查 python3 是否已具备 pip。 */
|
|
61
|
+
function defaultPythonHasPip(pythonBin) {
|
|
62
|
+
const probe = (0, child_process_1.spawnSync)(pythonBin, ['-m', 'pip', '--version'], { stdio: 'ignore' });
|
|
63
|
+
return probe.status === 0;
|
|
64
|
+
}
|
|
65
|
+
/** 执行外部命令,并在失败时抛出异常。 */
|
|
66
|
+
function defaultRunCommand(command, args) {
|
|
67
|
+
const result = (0, child_process_1.spawnSync)(command, args, { stdio: 'inherit' });
|
|
68
|
+
if (result.error) {
|
|
69
|
+
throw result.error;
|
|
70
|
+
}
|
|
71
|
+
if (result.status !== 0) {
|
|
72
|
+
throw new Error(`Command failed: ${command} ${args.join(' ')}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** 执行或计划一条 setup 动作。 */
|
|
76
|
+
function executeOrPlan(actions, dryRun, runCommand, message, command, args) {
|
|
77
|
+
if (dryRun) {
|
|
78
|
+
actions.push({
|
|
79
|
+
status: 'planned',
|
|
80
|
+
message,
|
|
81
|
+
command,
|
|
82
|
+
args,
|
|
83
|
+
});
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
runCommand(command, args);
|
|
87
|
+
actions.push({
|
|
88
|
+
status: 'installed',
|
|
89
|
+
message,
|
|
90
|
+
command,
|
|
91
|
+
args,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/** 安装或检查运行时依赖。 */
|
|
95
|
+
function setupEnvironment(options = {}) {
|
|
96
|
+
const dryRun = options.dryRun ?? false;
|
|
97
|
+
const hasCommand = options.hasCommand ?? commandExists;
|
|
98
|
+
const pythonHasModule = options.pythonHasModule ?? defaultPythonHasModule;
|
|
99
|
+
const pythonHasPip = options.pythonHasPip ?? defaultPythonHasPip;
|
|
100
|
+
const runCommand = options.runCommand ?? defaultRunCommand;
|
|
101
|
+
const packageName = options.packageName ?? '@tcos/broker-parser';
|
|
102
|
+
const actions = [];
|
|
103
|
+
const hasBrew = hasCommand('brew');
|
|
104
|
+
const hasApt = hasCommand('apt-get');
|
|
105
|
+
if (!hasCommand('tcos-parse')) {
|
|
106
|
+
executeOrPlan(actions, dryRun, runCommand, 'install global tcos-parse CLI', 'npm', [
|
|
107
|
+
'install',
|
|
108
|
+
'-g',
|
|
109
|
+
packageName,
|
|
110
|
+
]);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
actions.push({
|
|
114
|
+
status: 'skipped',
|
|
115
|
+
message: 'tcos-parse already available',
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
let pythonReady = hasCommand('python3');
|
|
119
|
+
if (!pythonReady) {
|
|
120
|
+
if (hasBrew) {
|
|
121
|
+
executeOrPlan(actions, dryRun, runCommand, 'install python3 via Homebrew', 'brew', [
|
|
122
|
+
'install',
|
|
123
|
+
'python3',
|
|
124
|
+
]);
|
|
125
|
+
pythonReady = true;
|
|
126
|
+
}
|
|
127
|
+
else if (hasApt) {
|
|
128
|
+
executeOrPlan(actions, dryRun, runCommand, 'install python3 and pip via apt-get', 'sudo', [
|
|
129
|
+
'apt-get',
|
|
130
|
+
'install',
|
|
131
|
+
'-y',
|
|
132
|
+
'python3',
|
|
133
|
+
'python3-pip',
|
|
134
|
+
]);
|
|
135
|
+
pythonReady = true;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
actions.push({
|
|
139
|
+
status: 'manual',
|
|
140
|
+
message: 'python3 not found; install Python 3 manually',
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
actions.push({
|
|
146
|
+
status: 'skipped',
|
|
147
|
+
message: 'python3 already available',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
if (pythonReady) {
|
|
151
|
+
if (!pythonHasPip('python3')) {
|
|
152
|
+
executeOrPlan(actions, dryRun, runCommand, 'install pip for python3', 'python3', [
|
|
153
|
+
'-m',
|
|
154
|
+
'ensurepip',
|
|
155
|
+
'--upgrade',
|
|
156
|
+
]);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
actions.push({
|
|
160
|
+
status: 'skipped',
|
|
161
|
+
message: 'python3 pip already available',
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
if (!pythonHasModule('python3', 'pdfplumber')) {
|
|
165
|
+
executeOrPlan(actions, dryRun, runCommand, 'install pdfplumber for current user', 'python3', [
|
|
166
|
+
'-m',
|
|
167
|
+
'pip',
|
|
168
|
+
'install',
|
|
169
|
+
'--user',
|
|
170
|
+
'pdfplumber',
|
|
171
|
+
]);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
actions.push({
|
|
175
|
+
status: 'skipped',
|
|
176
|
+
message: 'pdfplumber already available',
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (!hasCommand('pdftotext')) {
|
|
181
|
+
if (hasBrew) {
|
|
182
|
+
executeOrPlan(actions, dryRun, runCommand, 'install poppler via Homebrew', 'brew', [
|
|
183
|
+
'install',
|
|
184
|
+
'poppler',
|
|
185
|
+
]);
|
|
186
|
+
}
|
|
187
|
+
else if (hasApt) {
|
|
188
|
+
executeOrPlan(actions, dryRun, runCommand, 'install poppler via apt-get', 'sudo', [
|
|
189
|
+
'apt-get',
|
|
190
|
+
'install',
|
|
191
|
+
'-y',
|
|
192
|
+
'poppler-utils',
|
|
193
|
+
]);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
actions.push({
|
|
197
|
+
status: 'manual',
|
|
198
|
+
message: 'pdftotext not found; install poppler manually if your system requires it',
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
actions.push({
|
|
204
|
+
status: 'skipped',
|
|
205
|
+
message: 'pdftotext already available',
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return { actions };
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"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"}
|