Skip to content

Commit f5cb9d1

Browse files
authored
Merge pull request #1 from cablate/feat/cli-mode
新增 CLI 模式供 Claude Code 使用
2 parents 4f8dfe8 + 3728bc9 commit f5cb9d1

17 files changed

Lines changed: 805 additions & 168 deletions

.github/workflows/ci.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
branches: [master]
6+
7+
jobs:
8+
ci:
9+
runs-on: ubuntu-latest
10+
strategy:
11+
matrix:
12+
node-version: [18, 20, 22]
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- uses: actions/setup-node@v4
17+
with:
18+
node-version: ${{ matrix.node-version }}
19+
cache: npm
20+
21+
- run: npm ci
22+
- run: npx tsc --noEmit

.github/workflows/release.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
branches: [master]
6+
7+
concurrency:
8+
group: release
9+
cancel-in-progress: false
10+
11+
jobs:
12+
release:
13+
if: "!contains(github.event.head_commit.message, 'chore: release')"
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: write
17+
steps:
18+
- uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0
21+
22+
- uses: actions/setup-node@v4
23+
with:
24+
node-version: 20
25+
registry-url: https://registry.npmjs.org
26+
27+
- run: npm ci
28+
- run: npx tsc --noEmit
29+
30+
- name: Bump version
31+
run: |
32+
NPM_VERSION=$(npm view @cablate/banini-tracker version 2>/dev/null || echo "0.0.0")
33+
LOCAL_VERSION=$(node -p "require('./package.json').version")
34+
HIGHER=$(printf '%s\n' "$NPM_VERSION" "$LOCAL_VERSION" | sort -V | tail -1)
35+
node -e "
36+
const pkg = require('./package.json');
37+
pkg.version = '${HIGHER}';
38+
require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
39+
"
40+
npm version patch --no-git-tag-version
41+
42+
- name: Build
43+
run: npx tsc
44+
45+
- name: Publish to npm
46+
run: npm publish --access public
47+
env:
48+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
49+
50+
- name: Commit version bump & tag
51+
run: |
52+
VERSION=$(node -p "require('./package.json').version")
53+
git config user.name "github-actions[bot]"
54+
git config user.email "github-actions[bot]@users.noreply.github.com"
55+
git add package.json package-lock.json
56+
git commit -m "chore: release v${VERSION}"
57+
git tag "v${VERSION}"
58+
git push
59+
git push --tags
60+
61+
- name: Create GitHub Release
62+
run: |
63+
VERSION=$(node -p "require('./package.json').version")
64+
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
65+
if [ -n "$PREV_TAG" ]; then
66+
NOTES=$(git log ${PREV_TAG}..v${VERSION} --pretty=format:"- %s" --no-merges | grep -v "^- chore: release")
67+
else
68+
NOTES="Initial release"
69+
fi
70+
gh release create "v${VERSION}" --title "v${VERSION}" --notes "$NOTES"
71+
env:
72+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
node_modules/
22
dist/
3-
data/
3+
*.log
44
.env
5+
tmp-report.txt

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 cablate
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.

README.md

Lines changed: 91 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -4,102 +4,130 @@
44

55
# banini-tracker
66

7-
追蹤「反指標女神」巴逆逆(8zz)的 Threads / Facebook 貼文,用 AI 進行反指標分析,推送結果到 Telegram 頻道。
8-
9-
## 它做什麼
10-
11-
1. 透過 Apify 抓取巴逆逆的最新社群貼文(Threads + Facebook)
12-
2. 自動去重,只處理新貼文
13-
3. 用 LLM 進行「反指標 + 總經連鎖」分析
14-
4. 將分析結果推送到 Telegram 頻道
15-
5. 內建排程:盤中即時追蹤 + 盤後完整分析
16-
17-
## 反指標邏輯
18-
19-
巴逆逆被稱為「股海冥燈」——買什麼跌什麼,賣什麼漲什麼。AI 分析會:
7+
追蹤「股海冥燈」巴逆逆(8zz)的 Threads / Facebook 社群貼文,透過 Apify 抓取、AI 反指標分析、Telegram 即時推送。
208

219
- 辨識她提到的標的(個股、ETF、原物料)
2210
- 判斷她的操作(買入 / 被套 / 停損)
2311
- 反轉推導(她停損 → 可能反彈、她買入 → 可能下跌)
2412
- 推導連鎖效應(油價跌 → 製造業利多 → 電子股受惠)
2513

26-
## 環境需求
14+
> **Claude Code 使用者?** 直接把 [`skill/SKILL.md`](skill/SKILL.md) 加到你的 `.claude/skills/` 就能用。Claude 自己當分析引擎,不需要額外 LLM。
2715
28-
- Node.js 20+
29-
- [Apify](https://apify.com/) 帳號(免費額度即可)
30-
- 任何 OpenAI 相容的 LLM API(預設 DeepInfra)
31-
- Telegram Bot + 頻道(選用)
16+
支援兩種使用模式:
17+
- **常駐排程**:Docker 部署,自動盤中/盤後排程 + LLM 分析 + Telegram 推送
18+
- **CLI 工具**`npx @cablate/banini-tracker`,搭配 Claude Code 等 AI 手動執行分析
3219

33-
## 安裝
20+
## 快速開始(常駐排程)
3421

3522
```bash
36-
git clone https://github.com/CabLate/banini-tracker.git
37-
cd banini-tracker
38-
npm install
23+
# 1. 複製設定
3924
cp .env.example .env
25+
# 填入 APIFY_TOKEN, LLM_BASE_URL, LLM_API_KEY, LLM_MODEL, TG_BOT_TOKEN, TG_CHANNEL_ID
26+
27+
# 2. Docker 部署
28+
docker build -t banini-tracker .
29+
docker run -d --name banini --env-file .env banini-tracker
30+
31+
# 3. 或本地直接跑
32+
npm install && npm run start
4033
```
4134

42-
編輯 `.env` 填入你的 API keys:
35+
### 排程規則
36+
37+
- **盤中**(週一~五 09:00-13:30):每 30 分鐘,FB only 抓 1 篇
38+
- **盤後**(每天 23:00):Threads + FB 各 3 篇
4339

44-
```env
45-
APIFY_TOKEN=your_apify_token
40+
### npm scripts
41+
42+
| 指令 | 說明 |
43+
|------|------|
44+
| `npm run start` | 常駐排程模式(盤中 + 盤後自動跑) |
45+
| `npm run dev` | 單次執行(Threads + FB 各 3 篇) |
46+
| `npm run dry` | 只抓取,不呼叫 LLM |
47+
| `npm run market` | 盤中模式(FB only, 1 篇) |
48+
| `npm run evening` | 盤後模式(各 3 篇) |
49+
50+
### .env 設定
51+
52+
```
53+
APIFY_TOKEN=apify_api_...
4654
LLM_BASE_URL=https://api.deepinfra.com/v1/openai
47-
LLM_API_KEY=your_api_key
55+
LLM_API_KEY=...
4856
LLM_MODEL=MiniMaxAI/MiniMax-M2.5
49-
TG_BOT_TOKEN=your_telegram_bot_token
50-
TG_CHANNEL_ID=your_telegram_channel_id
57+
TG_BOT_TOKEN=...
58+
TG_CHANNEL_ID=-100...
5159
```
5260

53-
## 使用
61+
## CLI 工具模式
5462

55-
### 手動執行
63+
不需 clone repo,任何環境直接用:
5664

5765
```bash
58-
npm run dev # Threads + FB 各 3 篇,AI 分析 + 通知
59-
npm run dry # 只抓取,不呼叫 LLM(測試用)
60-
npm run market # 盤中模式:FB only, 1 篇
61-
npm run evening # 盤後模式:Threads + FB, 各 3 篇
62-
```
66+
# 初始化設定
67+
npx @cablate/banini-tracker init \
68+
--apify-token YOUR_APIFY_TOKEN \
69+
--tg-bot-token YOUR_TG_BOT_TOKEN \
70+
--tg-channel-id YOUR_TG_CHANNEL_ID
6371

64-
### 常駐排程(部署用)
72+
# 抓取 Facebook 最新 3 篇
73+
npx @cablate/banini-tracker fetch -s fb -n 3 --mark-seen
6574

66-
```bash
67-
npm run build # TypeScript 編譯
68-
npm run start # 啟動常駐排程
75+
# 推送結果到 Telegram
76+
npx @cablate/banini-tracker push -m "分析結果..."
6977
```
7078

71-
排程時間(台北時間):
79+
### CLI 指令
7280

73-
| 排程 | 時間 | 來源 | 篇數 |
74-
|------|------|------|------|
75-
| 盤中 | 週一~五 09:07-13:07 每 30 分 | Facebook | 1 篇 |
76-
| 盤後 | 每天 23:03 | Threads + Facebook | 各 3 篇 |
81+
| 指令 | 說明 |
82+
|------|------|
83+
| `init` | 初始化設定檔(`~/.banini-tracker.json`|
84+
| `config` | 顯示目前設定 |
85+
| `fetch` | 抓取貼文,輸出 JSON 到 stdout |
86+
| `push` | 推送訊息到 Telegram |
87+
| `seen list` | 列出已讀貼文 ID |
88+
| `seen mark <id...>` | 標記貼文為已讀 |
89+
| `seen clear` | 清空已讀紀錄 |
7790

78-
盤中只用 Facebook($0.02/次),盤後加 Threads(~$0.15/次),日成本約 $0.37。
91+
### fetch 選項
7992

80-
## 費用估算
81-
82-
| 服務 | 單次費用 | 月估算 |
83-
|------|---------|--------|
84-
| Apify FB Scraper | $0.02/次 | ~$6(盤中 10 次/天 × 30 天) |
85-
| Apify Threads Scraper | ~$0.15/次 | ~$4.5(盤後 1 次/天 × 30 天) |
86-
| DeepInfra LLM | ~$0.001/次 | < $1 |
87-
| **合計** | | **~$11/月** |
93+
```
94+
-s, --source <source> 來源:threads / fb / both(預設 fb)
95+
-n, --limit <n> 每個來源抓幾篇(預設 3)
96+
--no-dedup 不去重
97+
--mark-seen 輸出後自動標記已讀
98+
```
8899

89-
## 專案結構
100+
### push 選項
90101

91102
```
92-
src/
93-
index.ts # 主程式 + 排程邏輯
94-
threads.ts # Apify Threads Scraper 封裝
95-
facebook.ts # Apify Facebook Scraper 封裝
96-
analyze.ts # LLM 反指標分析(prompt + 呼叫)
97-
telegram.ts # Telegram Bot 通知
98-
data/ # 執行資料(gitignore)
99-
seen.json # 已處理貼文 ID(去重用)
100-
report-*.json # 每次分析結果存檔
103+
-m, --message <text> 直接帶訊息
104+
-f, --file <path> 從檔案讀取
105+
--parse-mode <mode> HTML / Markdown / none(預設 HTML)
101106
```
102107

108+
不帶 `-m``-f` 時從 stdin 讀取。
109+
110+
### 搭配 Claude Code 使用
111+
112+
在 Claude Code 的 skill 中,Claude 自己就是分析引擎:
113+
114+
1. `fetch` 抓貼文 → Claude 讀 JSON
115+
2. Claude 分析 + WebSearch 查最新走勢
116+
3. Claude 組報告 → `push` 推送 Telegram
117+
118+
詳見 [`skill/SKILL.md`](skill/SKILL.md)
119+
120+
## 費用
121+
122+
| 來源 | 每次費用 | 說明 |
123+
|------|---------|------|
124+
| Facebook | ~$0.02 | CU 計費,便宜 |
125+
| Threads | ~$0.15 | Pay-per-event,較貴 |
126+
103127
## 免責聲明
104128

105129
本專案僅供娛樂參考,不構成任何投資建議。
130+
131+
## License
132+
133+
MIT

package-lock.json

Lines changed: 20 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)