leek-box-cli 0.1.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/LICENSE +21 -0
- package/README.md +213 -0
- package/dist/cli.mjs +161 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
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
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
<p align="right">
|
|
2
|
+
<strong>English</strong> | <a href="README-zh.md">中文</a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# leek-box-cli(韭菜盒子)
|
|
6
|
+
|
|
7
|
+
> An interactive terminal stock watchlist dashboard built with [Ink](https://github.com/vadimdemedes/ink).
|
|
8
|
+
|
|
9
|
+
## Screenshots
|
|
10
|
+
|
|
11
|
+
### Stock Watchlist
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<img src="scrennshots/stock-list.png" alt="Stock watchlist dashboard" width="100%">
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
### Menu & Settings
|
|
18
|
+
|
|
19
|
+
<table>
|
|
20
|
+
<tr>
|
|
21
|
+
<td align="center" width="50%"><strong>Menu</strong></td>
|
|
22
|
+
<td align="center" width="50%"><strong>Settings</strong></td>
|
|
23
|
+
</tr>
|
|
24
|
+
<tr>
|
|
25
|
+
<td><img src="scrennshots/dialog-menu.png" alt="Menu dialog"></td>
|
|
26
|
+
<td><img src="scrennshots/settings.png" alt="Settings screen"></td>
|
|
27
|
+
</tr>
|
|
28
|
+
</table>
|
|
29
|
+
|
|
30
|
+
### Manage Watchlist
|
|
31
|
+
|
|
32
|
+
<table>
|
|
33
|
+
<tr>
|
|
34
|
+
<td align="center" width="50%"><strong>Add Stock</strong></td>
|
|
35
|
+
<td align="center" width="50%"><strong>Remove Stock</strong></td>
|
|
36
|
+
</tr>
|
|
37
|
+
<tr>
|
|
38
|
+
<td><img src="scrennshots/stock-add.png" alt="Add a stock to the watchlist"></td>
|
|
39
|
+
<td><img src="scrennshots/stock-remove.png" alt="Remove a stock from the watchlist"></td>
|
|
40
|
+
</tr>
|
|
41
|
+
</table>
|
|
42
|
+
|
|
43
|
+
### Stock Details
|
|
44
|
+
|
|
45
|
+
<table>
|
|
46
|
+
<tr>
|
|
47
|
+
<td align="center" width="50%"><strong>Intraday</strong></td>
|
|
48
|
+
<td align="center" width="50%"><strong>Five-day</strong></td>
|
|
49
|
+
</tr>
|
|
50
|
+
<tr>
|
|
51
|
+
<td><img src="scrennshots/dialog-stock-detail-intraday.png" alt="Intraday stock chart"></td>
|
|
52
|
+
<td><img src="scrennshots/dialog-stock-detail-five-day.png" alt="Five-day stock chart"></td>
|
|
53
|
+
</tr>
|
|
54
|
+
<tr>
|
|
55
|
+
<td align="center" width="50%"><strong>Daily</strong></td>
|
|
56
|
+
<td align="center" width="50%"><strong>Weekly</strong></td>
|
|
57
|
+
</tr>
|
|
58
|
+
<tr>
|
|
59
|
+
<td><img src="scrennshots/dialog-stock-detail-day.png" alt="Daily stock chart"></td>
|
|
60
|
+
<td><img src="scrennshots/dialog-stock-detail-week.png" alt="Weekly stock chart"></td>
|
|
61
|
+
</tr>
|
|
62
|
+
<tr>
|
|
63
|
+
<td align="center" width="50%"><strong>Monthly</strong></td>
|
|
64
|
+
<td align="center" width="50%"><strong>Yearly</strong></td>
|
|
65
|
+
</tr>
|
|
66
|
+
<tr>
|
|
67
|
+
<td><img src="scrennshots/dialog-stock-detail-month.png" alt="Monthly stock chart"></td>
|
|
68
|
+
<td><img src="scrennshots/dialog-stock-detail-year.png" alt="Yearly stock chart"></td>
|
|
69
|
+
</tr>
|
|
70
|
+
</table>
|
|
71
|
+
|
|
72
|
+
## Features
|
|
73
|
+
|
|
74
|
+
- **Real-time dashboard**: Displays the latest price, percentage change, price change, open, high, low, volume, turnover, turnover rate, and total market capitalization for every stock in your watchlist. Refreshes every 5 seconds by default.
|
|
75
|
+
- **Row selection and details**: Use `↑`/`↓` to select a stock and `enter` to open its quote details and trend chart. Press `1`-`6` to switch between intraday, five-day, daily, weekly, monthly, and yearly views.
|
|
76
|
+
- **Multiple time frames**: Intraday and five-day minute charts refresh every 30 seconds. Daily, weekly, monthly, and yearly charts refresh every 5 minutes.
|
|
77
|
+
- **Refresh controls**: Press `r` to refresh immediately. Configure the automatic refresh interval in Settings in 500 ms increments, from 1 to 60 seconds.
|
|
78
|
+
- **Watchlist management**: Add or remove Shanghai, Shenzhen, and Beijing A-shares and ETFs. Stock codes can be entered as `600000`, `sh600000`, `600000.SH`, and other common formats.
|
|
79
|
+
- **Resilient display**: Suspended stocks, incomplete quotes, and refresh failures each have a dedicated state. The display recovers automatically after a later poll succeeds.
|
|
80
|
+
|
|
81
|
+
## Controls
|
|
82
|
+
|
|
83
|
+
- `esc`: Open the menu. If stock details are open, close them first; if the menu is open, close it.
|
|
84
|
+
- In the menu, use `↑`/`↓`, `enter`, or a number key to select a page.
|
|
85
|
+
- In the dashboard, use `↑`/`↓`, `enter`, and `r`.
|
|
86
|
+
- In Settings, use `↑`/`↓` to select an item and `←`/`→` or `enter` to adjust it.
|
|
87
|
+
- In stock details, press `1`-`6` to switch between `Intraday`, `Five-day`, `Daily`, `Weekly`, `Monthly`, and `Yearly`.
|
|
88
|
+
- `q`: Exit when no menu or stock details overlay is open. It does nothing while an overlay is open to prevent accidental exits.
|
|
89
|
+
- The right side of the status bar displays `YYYY-MM-DD HH:MM:SS` in the Asia/Shanghai time zone.
|
|
90
|
+
|
|
91
|
+
## Requirements
|
|
92
|
+
|
|
93
|
+
- [Node.js](https://nodejs.org/) >= 22.19.0 (or >= 24)
|
|
94
|
+
- [pnpm](https://pnpm.io/) >= 11.0.0
|
|
95
|
+
|
|
96
|
+
Market data is retrieved with the native Node.js `fetch` API, with no external runtime dependency such as curl.
|
|
97
|
+
|
|
98
|
+
## Market Data Sources
|
|
99
|
+
|
|
100
|
+
- Real-time quotes: Tencent quote API at `https://qt.gtimg.cn/q=...`; GBK-encoded and requires no authentication.
|
|
101
|
+
- Intraday data: Tencent minute API at `https://web.ifzq.gtimg.cn/appstock/app/minute/query?code=...`.
|
|
102
|
+
- Five-day data: Tencent multi-day minute API at `https://web.ifzq.gtimg.cn/appstock/app/day/query?code=...`.
|
|
103
|
+
- Daily, weekly, and monthly data: Tencent forward-adjusted K-line API at `https://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param=...`.
|
|
104
|
+
- Yearly data: Aggregated locally by year from backward-adjusted monthly data returned by the same API.
|
|
105
|
+
- Data timeliness and availability depend on the upstream APIs. This project is intended for personal display purposes only.
|
|
106
|
+
|
|
107
|
+
## Installation and Usage
|
|
108
|
+
|
|
109
|
+
### Install globally (recommended)
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npm install -g leek-box-cli
|
|
113
|
+
# or
|
|
114
|
+
pnpm add -g leek-box-cli
|
|
115
|
+
# or
|
|
116
|
+
yarn global add leek-box-cli
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Then run it from anywhere:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
leek-box-cli
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
> Requires Node.js 22.19+ (or 24+) on the machine that runs the command.
|
|
126
|
+
|
|
127
|
+
Alternatively, run it once without installing:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npx leek-box-cli
|
|
131
|
+
# or
|
|
132
|
+
pnpm dlx leek-box-cli
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Run from source
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
pnpm install
|
|
139
|
+
|
|
140
|
+
# Development mode
|
|
141
|
+
pnpm dev
|
|
142
|
+
|
|
143
|
+
# Build and run
|
|
144
|
+
pnpm build
|
|
145
|
+
pnpm preview
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
You can also select the initial page with a subcommand:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
leek-box-cli # Stock watchlist dashboard
|
|
152
|
+
leek-box-cli stock-list # Same as above
|
|
153
|
+
leek-box-cli stock-add # Add a stock to the watchlist
|
|
154
|
+
leek-box-cli stock-remove # Remove a stock from the watchlist
|
|
155
|
+
leek-box-cli -v # Show version information
|
|
156
|
+
leek-box-cli -h # Show help
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Settings and Watchlist Storage
|
|
160
|
+
|
|
161
|
+
Settings and the watchlist are stored together at `$XDG_CONFIG_HOME/leek-box-cli/settings.json`. If `XDG_CONFIG_HOME` is not set, `~/.config/leek-box-cli/settings.json` is used.
|
|
162
|
+
|
|
163
|
+
File structure:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"theme": {
|
|
168
|
+
"preset": "classic",
|
|
169
|
+
"trendColorMode": "red-up",
|
|
170
|
+
"borderStyle": "round"
|
|
171
|
+
},
|
|
172
|
+
"request": {
|
|
173
|
+
"timeoutMs": 8000,
|
|
174
|
+
"minimumDurationMs": 0,
|
|
175
|
+
"quotePollIntervalMs": 5000,
|
|
176
|
+
"minuteChartPollIntervalMs": 30000,
|
|
177
|
+
"klinePollIntervalMs": 300000
|
|
178
|
+
},
|
|
179
|
+
"stocks": [
|
|
180
|
+
{
|
|
181
|
+
"code": "sh600000",
|
|
182
|
+
"name": "浦发银行",
|
|
183
|
+
"addedAt": "2026-08-20T00:00:00.000Z"
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The application reloads the file every time it refreshes the dashboard, so valid external edits take effect on the next refresh. It validates the `theme` and `request` fields, as well as each stock's `code`, `name`, `addedAt`, and duplicate codes when reading. Writes use an inter-process lock and atomic temporary-file replacement to prevent lost concurrent updates and partial JSON files.
|
|
190
|
+
|
|
191
|
+
## Development Scripts
|
|
192
|
+
|
|
193
|
+
| Command | Description |
|
|
194
|
+
| ----------------- | ---------------------------------------- |
|
|
195
|
+
| `pnpm dev` | Run the source code with tsx |
|
|
196
|
+
| `pnpm build` | Build `dist/cli.mjs` with Vite |
|
|
197
|
+
| `pnpm preview` | Run the build output |
|
|
198
|
+
| `pnpm test` | Run tests with Vitest |
|
|
199
|
+
| `pnpm typecheck` | Run TypeScript type checking |
|
|
200
|
+
| `pnpm lint` | Run the linter and apply automatic fixes |
|
|
201
|
+
| `pnpm lint:check` | Run the linter without modifying files |
|
|
202
|
+
| `pnpm fmt` | Format the code |
|
|
203
|
+
| `pnpm fmt:check` | Check code formatting |
|
|
204
|
+
|
|
205
|
+
## Tech Stack
|
|
206
|
+
|
|
207
|
+
- TypeScript / ESM
|
|
208
|
+
- Ink 7 + React 19
|
|
209
|
+
- Zustand 5
|
|
210
|
+
- meow
|
|
211
|
+
- Vite
|
|
212
|
+
- oxlint / oxfmt
|
|
213
|
+
- Vitest
|