mozyfin-cli 0.2.6
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 +10 -0
- package/README.md +280 -0
- package/agent-skills/mozyfin-cli/SKILL.md +300 -0
- package/dist/index.js +75 -0
- package/package.json +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Copyright (c) 2024 Mozyfin. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and associated documentation files (the "Software") are proprietary
|
|
4
|
+
and confidential. Unauthorized copying, distribution, modification, sublicensing,
|
|
5
|
+
or use of this Software, in whole or in part, via any medium, is strictly
|
|
6
|
+
prohibited without the prior written permission of Mozyfin.
|
|
7
|
+
|
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
9
|
+
IMPLIED. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
10
|
+
CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM USE OF THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Mozyfin CLI
|
|
2
|
+
|
|
3
|
+
A Bun-powered command line interface for Vietnamese market data from the Mozyfin/Antofin APIs. It is designed for both humans and AI agents: short ticker-first commands, Markdown tables by default, CSV export for long datasets, and predictable plain-text errors.
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
|
|
7
|
+
- Human-readable Markdown output by default
|
|
8
|
+
- CSV export with `--csv <file>` for spreadsheets or agent pipelines
|
|
9
|
+
- Public market/entity endpoints work without an API key
|
|
10
|
+
- Authenticated commands support `MOZYFIN_API_KEY`, saved config, or `--api-key`
|
|
11
|
+
- Client-side 1 request/second rate limit for API friendliness
|
|
12
|
+
- Built-in technical indicators and risk metrics from OHLCV candles
|
|
13
|
+
- Mocked CLI test suite covering command wiring, auth, config, CSV, validation, and output shape
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- [Bun](https://bun.sh) `>= 1.1.0`
|
|
18
|
+
- A Mozyfin API key for authenticated commands such as `ask`, `doc`, and `credits`
|
|
19
|
+
|
|
20
|
+
Create an API key at: https://research.mozyfin.com/setting
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g mozyfin-cli
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or with Bun:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
bun install -g mozyfin-cli
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Save API Key
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
mozyfin login --api-key mozy_ak_xxx
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
You can also use an environment variable:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
export MOZYFIN_API_KEY=mozy_ak_xxx
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
mozyfin search --query VNM
|
|
50
|
+
mozyfin profile VNM.VN
|
|
51
|
+
mozyfin news --entities VNM.VN --topics stock,earning --limit 10
|
|
52
|
+
mozyfin ohlcv VNM.VN --timeframe 1d --limit 200
|
|
53
|
+
mozyfin financials VNM.VN --year 2024 --quarter 4
|
|
54
|
+
mozyfin doc "định giá HPG"
|
|
55
|
+
mozyfin ask "compare VNM and MSN margin trend"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Commands
|
|
59
|
+
|
|
60
|
+
| Command | Purpose | Example |
|
|
61
|
+
| --- | --- | --- |
|
|
62
|
+
| `login` | Save API key locally | `mozyfin login --api-key <key>` |
|
|
63
|
+
| `logout` | Remove saved API key | `mozyfin logout` |
|
|
64
|
+
| `search` | Search ticker/company/entity | `mozyfin search --query VNM` |
|
|
65
|
+
| `profile` | Company/entity profile | `mozyfin profile VNM.VN` |
|
|
66
|
+
| `news` | Market headlines and article search | `mozyfin news --entities VNM.VN --topics stock,earning` |
|
|
67
|
+
| `ohlcv` | Historical candles | `mozyfin ohlcv VNM.VN --timeframe 1d --limit 200` |
|
|
68
|
+
| `quote` | Historical quote stats | `mozyfin quote VNM.VN --limit 10` |
|
|
69
|
+
| `officers` | Company officers/directors | `mozyfin officers VNM.VN` |
|
|
70
|
+
| `subsidiary` | Subsidiaries | `mozyfin subsidiary VNM.VN` |
|
|
71
|
+
| `holder` | Major shareholders | `mozyfin holder VNM.VN --is-organization true` |
|
|
72
|
+
| `holder-tx` | Shareholder transactions | `mozyfin holder-tx VNM.VN --transaction-type buy --limit 100` |
|
|
73
|
+
| `financials` | Financial statements summary | `mozyfin financials VNM.VN --year 2024 --quarter 4` |
|
|
74
|
+
| `stats` | Financial statistics/ratios | `mozyfin stats VNM.VN --year 2024` |
|
|
75
|
+
| `ta` | Technical indicators | `mozyfin ta VNM.VN --sma 20,50 --rsi 14 --macd` |
|
|
76
|
+
| `risk` | Return, volatility, Sharpe, drawdown | `mozyfin risk VNM.VN --limit 252 --risk-free 0.03` |
|
|
77
|
+
| `doc` | Query analysis reports (RAG) | `mozyfin doc "định giá HPG"` |
|
|
78
|
+
| `ask` | Ask the Mozyfin agent | `mozyfin ask "analyze VNM" --timeout 300` |
|
|
79
|
+
| `credits` | Check subscription usage | `mozyfin credits` |
|
|
80
|
+
| `doctor` | Runtime/config/API health check | `mozyfin doctor` |
|
|
81
|
+
| `update` | Print upgrade hint | `mozyfin update` |
|
|
82
|
+
|
|
83
|
+
## Command Reference
|
|
84
|
+
|
|
85
|
+
### Auth
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
mozyfin login --api-key <key>
|
|
89
|
+
mozyfin logout
|
|
90
|
+
mozyfin credits
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Auth precedence is:
|
|
94
|
+
|
|
95
|
+
1. Explicit global `--api-key <key>`
|
|
96
|
+
2. `MOZYFIN_API_KEY` environment variable
|
|
97
|
+
3. Saved config from `mozyfin login`
|
|
98
|
+
|
|
99
|
+
Config is stored at:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
~/.config/mozyfin-cli/config.json
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Search and Profile
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
mozyfin search --query VNM
|
|
109
|
+
mozyfin search -q "Vinamilk"
|
|
110
|
+
mozyfin search -q "" # broad search/all, depending on API behavior
|
|
111
|
+
mozyfin profile VNM.VN
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`search` intentionally only exposes `--query` to keep the CLI simple and aligned with the current product workflow.
|
|
115
|
+
|
|
116
|
+
### News
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
mozyfin news --query "Vinamilk" --limit 10
|
|
120
|
+
mozyfin news --entities VNM.VN,MSN.VN --topics stock,earning --limit 20
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Allowed topics:
|
|
124
|
+
|
|
125
|
+
```text
|
|
126
|
+
stock, crypto, forex, tariff, economic, earning, tech, housing, mergers_and_ipo
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Market Data
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
mozyfin ohlcv VNM.VN --timeframe 1d --limit 200
|
|
133
|
+
mozyfin ohlcv VNM.VN --timeframe 1w --to 2024-12-31 --limit 52
|
|
134
|
+
mozyfin quote VNM.VN --to 2024-12-31 --limit 10
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Allowed OHLCV timeframes:
|
|
138
|
+
|
|
139
|
+
```text
|
|
140
|
+
1h, 1d, 1w, 1mo, 1y
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Entity Details
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
mozyfin officers VNM.VN
|
|
147
|
+
mozyfin subsidiary VNM.VN
|
|
148
|
+
mozyfin holder VNM.VN --is-organization true --is-foreigner false
|
|
149
|
+
mozyfin holder-tx VNM.VN --transaction-type buy --limit 100
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Note: the upstream endpoint for `officers` is named `/office`, but the returned data is officers/directors, so the CLI command uses `officers` for clarity.
|
|
153
|
+
|
|
154
|
+
### Financials
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
mozyfin financials VNM.VN --year 2024 --quarter 4
|
|
158
|
+
mozyfin financials VNM.VN --year 2024 --quarter 4 --statement-type BALANCE_SHEET
|
|
159
|
+
mozyfin stats VNM.VN --year 2024
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`financials` summarizes nested statement values into common readable columns such as `net_sales`, `gross_profit`, `profit_after_tax`, `total_assets`, `owner_equity`, and `net_operating_cash_flow`.
|
|
163
|
+
|
|
164
|
+
### Analytics
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
mozyfin ta VNM.VN --sma 20,50,200 --rsi 14 --macd
|
|
168
|
+
mozyfin risk VNM.VN --limit 252 --risk-free 0.03
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`ta` and `risk` compute over chronological candles even when the API returns latest-first data.
|
|
172
|
+
|
|
173
|
+
### Document Query
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
mozyfin doc "định giá HPG"
|
|
177
|
+
mozyfin doc "VNM Q4 2024 earnings analysis"
|
|
178
|
+
mozyfin doc "so sánh biên lợi nhuận VNM và MSN"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Queries analysis reports using natural language via RAG. Returns structured Markdown with sections:
|
|
182
|
+
|
|
183
|
+
- **Entities** — knowledge graph entities extracted from reports
|
|
184
|
+
- **Relationships** — connections between entities
|
|
185
|
+
- **Document Chunks** — retrieved report passages relevant to the query
|
|
186
|
+
- **References** — source documents mapped to chunks
|
|
187
|
+
- **Context** — grounding instructions from the RAG system
|
|
188
|
+
|
|
189
|
+
Requires an API key.
|
|
190
|
+
|
|
191
|
+
### Agent
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
mozyfin ask "summarize VNM risks and catalysts" --timeout 300
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The command creates an auto-mode chat, sends the prompt, polls until the message finishes, and prints the final text response.
|
|
198
|
+
|
|
199
|
+
## Output
|
|
200
|
+
|
|
201
|
+
Default output is Markdown table or key-value text:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
mozyfin search --query VNM
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
```text
|
|
208
|
+
| symbol | name | exchange | market_cap | id |
|
|
209
|
+
| --- | --- | --- | --- | --- |
|
|
210
|
+
| VNM | Vietnam Dairy Products Joint Stock Company | HOSE | ... | VNM.VN |
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Use CSV for long datasets:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
mozyfin ohlcv VNM.VN --timeframe 1d --limit 200 --csv vnm.csv
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Development
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
bun install
|
|
223
|
+
bun run check
|
|
224
|
+
bun test
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Useful scripts:
|
|
228
|
+
|
|
229
|
+
| Script | Description |
|
|
230
|
+
| --- | --- |
|
|
231
|
+
| `bun run dev -- <args>` | Run CLI from source |
|
|
232
|
+
| `bun test` | Run unit/CLI tests |
|
|
233
|
+
| `bun run lint` | Check formatting/linting |
|
|
234
|
+
| `bun run format` | Format files |
|
|
235
|
+
| `bun run check` | Format/lint with write fixes |
|
|
236
|
+
|
|
237
|
+
Run from source:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
bun run src/index.ts search --query VNM
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Test Coverage
|
|
244
|
+
|
|
245
|
+
The test suite uses Bun's test runner plus a mocked local HTTP server. It covers:
|
|
246
|
+
|
|
247
|
+
- API URL construction and endpoint mapping
|
|
248
|
+
- HTTP response and error parsing
|
|
249
|
+
- CLI command output shape
|
|
250
|
+
- Query parameter mapping for command options
|
|
251
|
+
- Auth precedence and config persistence
|
|
252
|
+
- CSV file output
|
|
253
|
+
- Empty data rendering
|
|
254
|
+
- Validation errors and missing API key errors
|
|
255
|
+
- `ask` polling and malformed response handling
|
|
256
|
+
- Technical indicator and risk helper behavior
|
|
257
|
+
|
|
258
|
+
## Project Structure
|
|
259
|
+
|
|
260
|
+
```text
|
|
261
|
+
src/index.ts CLI command definitions
|
|
262
|
+
src/lib/api.ts API client, auth, rate limit, URL construction
|
|
263
|
+
src/lib/config.ts Local config load/save/clear
|
|
264
|
+
src/lib/format.ts Markdown, key-value, CSV formatting
|
|
265
|
+
src/lib/analytics.ts SMA, EMA, RSI, MACD, risk metrics
|
|
266
|
+
test/*.test.ts Unit and mocked CLI tests
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Notes for AI Agents
|
|
270
|
+
|
|
271
|
+
- Prefer Markdown output for short responses and `--csv <file>` for large tables.
|
|
272
|
+
- Use `search --query <text>` to discover entity ids, then pass ids such as `VNM.VN` into detail commands.
|
|
273
|
+
- Do not use removed commands/options such as `markets`, `exchanges`, or `ask --no-wait`.
|
|
274
|
+
- `officers` returns people and roles, not physical office addresses.
|
|
275
|
+
- Public market endpoints do not require an API key; `ask`, `doc`, and `credits` do.
|
|
276
|
+
- Use `doc` for natural language queries against analysis reports (RAG); use `ask` for open-ended AI research that may call multiple data sources.
|
|
277
|
+
|
|
278
|
+
## License
|
|
279
|
+
|
|
280
|
+
Private/internal unless a license is added.
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mozyfin-cli
|
|
3
|
+
description: "Mozyfin CLI: Vietnam stock market data, quotes, financials, technical analysis, AI-powered research."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# mozyfin-cli
|
|
7
|
+
|
|
8
|
+
Use `mozyfin` when you need Vietnamese stock market data, company information, technical analysis, or AI-powered research on Vietnam equities.
|
|
9
|
+
|
|
10
|
+
## Fast Path
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
mozyfin --version
|
|
14
|
+
mozyfin --help
|
|
15
|
+
mozyfin <command> --help
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Quick data retrieval without authentication:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
mozyfin search --query VNM
|
|
22
|
+
mozyfin profile VNM.VN
|
|
23
|
+
mozyfin quote VNM.VN
|
|
24
|
+
mozyfin ohlcv VNM.VN --timeframe 1d --limit 30
|
|
25
|
+
mozyfin news VNM.VN --limit 10
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Use `--csv <file>` for large datasets that need further processing.
|
|
29
|
+
|
|
30
|
+
## Authentication
|
|
31
|
+
|
|
32
|
+
Public market data commands work without an API key. Authenticated commands (`ask`, `doc`, `credits`) require one:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Login and save credentials
|
|
36
|
+
mozyfin login --api-key <your-key>
|
|
37
|
+
|
|
38
|
+
# Or use environment variable
|
|
39
|
+
export MOZYFIN_API_KEY=<your-key>
|
|
40
|
+
|
|
41
|
+
# Or pass directly
|
|
42
|
+
mozyfin ask "Analyze VNM" --api-key <your-key>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Get your API key at: https://research.mozyfin.com/settings
|
|
46
|
+
|
|
47
|
+
Auth precedence:
|
|
48
|
+
1. Explicit `--api-key` flag
|
|
49
|
+
2. `MOZYFIN_API_KEY` environment variable
|
|
50
|
+
3. Saved config from `mozyfin login`
|
|
51
|
+
|
|
52
|
+
Config location: `~/.config/mozyfin-cli/config.json`
|
|
53
|
+
|
|
54
|
+
## Ticker Format
|
|
55
|
+
|
|
56
|
+
All commands use the format `SYMBOL.VN`:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
mozyfin profile VNM.VN
|
|
60
|
+
mozyfin quote FPT.VN VIC.VN MWG.VN # Multiple tickers
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The `search` command is the exception - it accepts partial names:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
mozyfin search --query vinamilk
|
|
67
|
+
mozyfin search --query VNM
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Commands
|
|
71
|
+
|
|
72
|
+
### Search
|
|
73
|
+
|
|
74
|
+
Find tickers by name or symbol:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
mozyfin search --query VNM
|
|
78
|
+
mozyfin search --query vinamilk
|
|
79
|
+
mozyfin search -q bank
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Company Information
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Company profile
|
|
86
|
+
mozyfin profile VNM.VN
|
|
87
|
+
|
|
88
|
+
# Officers and directors
|
|
89
|
+
mozyfin officers VNM.VN
|
|
90
|
+
|
|
91
|
+
# Corporate events
|
|
92
|
+
mozyfin events VNM.VN --limit 20
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Market Data
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Real-time quotes
|
|
99
|
+
mozyfin quote VNM.VN
|
|
100
|
+
mozyfin quote VNM.VN FPT.VN VIC.VN
|
|
101
|
+
|
|
102
|
+
# Quote at specific time (Unix timestamp)
|
|
103
|
+
mozyfin quote VNM.VN --to 1746038400
|
|
104
|
+
|
|
105
|
+
# Historical OHLCV data
|
|
106
|
+
mozyfin ohlcv VNM.VN --timeframe 1d --limit 100
|
|
107
|
+
mozyfin ohlcv VNM.VN -t 1h -l 200 --csv vnm-hourly.csv
|
|
108
|
+
|
|
109
|
+
# OHLCV with end time (Unix timestamp)
|
|
110
|
+
mozyfin ohlcv VNM.VN --timeframe 1d --to 1746038400 --limit 365
|
|
111
|
+
|
|
112
|
+
# Timeframes: 1h, 1d, 1w, 1mo, 1y
|
|
113
|
+
# Note: --to accepts Unix timestamp (seconds since epoch)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### News
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
mozyfin news VNM.VN --limit 10
|
|
120
|
+
mozyfin news FPT.VN -l 20
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Financials
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Financial statements
|
|
127
|
+
mozyfin financials VNM.VN
|
|
128
|
+
|
|
129
|
+
# Key statistics
|
|
130
|
+
mozyfin stats VNM.VN
|
|
131
|
+
|
|
132
|
+
# Export to CSV
|
|
133
|
+
mozyfin financials VNM.VN --csv financials.csv
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Technical Analysis
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Technical indicators
|
|
140
|
+
mozyfin ta VNM.VN --timeframe 1d
|
|
141
|
+
mozyfin ta VNM.VN -t 1h
|
|
142
|
+
|
|
143
|
+
# Risk metrics
|
|
144
|
+
mozyfin risk VNM.VN --timeframe 1d
|
|
145
|
+
mozyfin risk VNM.VN -t 1w
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Document Query (Requires API Key)
|
|
149
|
+
|
|
150
|
+
Query analysis reports using natural language. Returns structured Markdown with entities, relationships, retrieved report chunks, source references, and grounding context.
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
mozyfin doc "định giá HPG"
|
|
154
|
+
mozyfin doc "VNM Q4 2024 earnings analysis"
|
|
155
|
+
mozyfin doc "so sánh biên lợi nhuận VNM và MSN"
|
|
156
|
+
mozyfin doc "rủi ro ngành thép 2024"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Output sections (in order):
|
|
160
|
+
1. **Entities** — knowledge graph nodes from retrieved reports
|
|
161
|
+
2. **Relationships** — entity connections
|
|
162
|
+
3. **Document Chunks** — relevant passages from reports
|
|
163
|
+
4. **References** — source file paths for each chunk
|
|
164
|
+
5. **Context** — RAG grounding instructions
|
|
165
|
+
|
|
166
|
+
Use `doc` when you need grounded answers from actual report documents. Use `ask` for open-ended research that may synthesize multiple data sources.
|
|
167
|
+
|
|
168
|
+
### AI Research (Requires API Key)
|
|
169
|
+
|
|
170
|
+
**Recommended for agents**: Use `ask` instead of multiple individual commands. It saves tokens and provides better analysis by leveraging server-side AI with full market context.
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# Ask AI about stocks
|
|
174
|
+
mozyfin ask "Analyze VNM financial performance"
|
|
175
|
+
mozyfin ask "Compare VNM and MSN margins" --timeout 120
|
|
176
|
+
mozyfin ask "What are the risks for FPT?" -t 60
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Why agents should prefer `ask`:**
|
|
180
|
+
- Single API call vs. multiple commands
|
|
181
|
+
- Server-side AI has access to full historical data and context
|
|
182
|
+
- Returns comprehensive analysis in one response
|
|
183
|
+
- More efficient token usage for the agent
|
|
184
|
+
- Better synthesis across multiple data sources
|
|
185
|
+
|
|
186
|
+
### Account Management
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# Check remaining credits
|
|
190
|
+
mozyfin credits
|
|
191
|
+
|
|
192
|
+
# Update CLI
|
|
193
|
+
mozyfin update
|
|
194
|
+
|
|
195
|
+
# Update CLI and skills
|
|
196
|
+
mozyfin update --skill
|
|
197
|
+
mozyfin update --skill claude
|
|
198
|
+
mozyfin update --skill all
|
|
199
|
+
|
|
200
|
+
# Logout
|
|
201
|
+
mozyfin logout
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Install Skills for Agents
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# Install skill for specific agent
|
|
208
|
+
mozyfin skill claude
|
|
209
|
+
mozyfin skill cursor
|
|
210
|
+
mozyfin skill copilot
|
|
211
|
+
mozyfin skill windsurf
|
|
212
|
+
mozyfin skill codex
|
|
213
|
+
mozyfin skill gemini
|
|
214
|
+
mozyfin skill hermes
|
|
215
|
+
mozyfin skill openclaw
|
|
216
|
+
|
|
217
|
+
# Install for all agents
|
|
218
|
+
mozyfin skill all
|
|
219
|
+
|
|
220
|
+
# List installed skills
|
|
221
|
+
mozyfin skill --list
|
|
222
|
+
|
|
223
|
+
# Remove skill
|
|
224
|
+
mozyfin skill claude --remove
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Output Formats
|
|
228
|
+
|
|
229
|
+
Default output is human-readable Markdown tables. Use `--csv` for data export:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# Markdown table (default)
|
|
233
|
+
mozyfin ohlcv VNM.VN --limit 10
|
|
234
|
+
|
|
235
|
+
# CSV export
|
|
236
|
+
mozyfin ohlcv VNM.VN --limit 1000 --csv ohlcv.csv
|
|
237
|
+
mozyfin financials VNM.VN --csv financials.csv
|
|
238
|
+
mozyfin ta VNM.VN --csv technical.csv
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Common Workflows
|
|
242
|
+
|
|
243
|
+
### Research a Stock
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
mozyfin search --query vnm
|
|
247
|
+
mozyfin profile VNM.VN
|
|
248
|
+
mozyfin financials VNM.VN
|
|
249
|
+
mozyfin quote VNM.VN
|
|
250
|
+
mozyfin news VNM.VN --limit 10
|
|
251
|
+
mozyfin ta VNM.VN
|
|
252
|
+
mozyfin risk VNM.VN
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Compare Multiple Stocks
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
mozyfin quote VNM.VN FPT.VN VIC.VN MWG.VN
|
|
259
|
+
mozyfin stats VNM.VN FPT.VN
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Export Data for Analysis
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
mozyfin ohlcv VNM.VN --timeframe 1d --limit 365 --csv vnm-yearly.csv
|
|
266
|
+
mozyfin financials VNM.VN --csv vnm-financials.csv
|
|
267
|
+
mozyfin ta VNM.VN --csv vnm-technical.csv
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Document-Grounded Research
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
mozyfin doc "định giá HPG"
|
|
274
|
+
mozyfin doc "triển vọng ngành ngân hàng 2024"
|
|
275
|
+
mozyfin doc "FPT revenue growth outlook"
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### AI-Powered Analysis
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
mozyfin ask "What is VNM's competitive position in dairy?"
|
|
282
|
+
mozyfin ask "Analyze FPT's revenue growth over the last 5 years"
|
|
283
|
+
mozyfin ask "Compare banking sector stocks: TCB, VCB, BID"
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Error Handling
|
|
287
|
+
|
|
288
|
+
- Commands return clear error messages for invalid tickers
|
|
289
|
+
- Auth-required commands show helpful message if no API key is found
|
|
290
|
+
- Network errors include status codes for debugging
|
|
291
|
+
- Use `--help` on any command for usage details
|
|
292
|
+
|
|
293
|
+
## Notes
|
|
294
|
+
|
|
295
|
+
- All price data is in VND (Vietnamese Dong)
|
|
296
|
+
- Market hours: 9:00-11:30 and 13:00-15:00 ICT (UTC+7)
|
|
297
|
+
- Data sourced from HoSE and HNX exchanges
|
|
298
|
+
- Real-time quotes may have a few seconds delay
|
|
299
|
+
- `doc` accepts both Vietnamese and English queries
|
|
300
|
+
- `doc` returns RAG context for grounded answers; `ask` performs open-ended AI reasoning
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @bun
|
|
3
|
+
var O0=Object.create;var{getPrototypeOf:h0,defineProperty:z0,getOwnPropertyNames:v0}=Object;var u0=Object.prototype.hasOwnProperty;var g0=($,q,Q)=>{Q=$!=null?O0(h0($)):{};let z=q||!$||!$.__esModule?z0(Q,"default",{value:$,enumerable:!0}):Q;for(let J of v0($))if(!u0.call(z,J))z0(z,J,{get:()=>$[J],enumerable:!0});return z};var V=($,q)=>()=>(q||$((q={exports:{}}).exports,q),q.exports);var E=import.meta.require;var k=V((c0)=>{class c extends Error{constructor($,q,Q){super(Q);Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.code=q,this.exitCode=$,this.nestedError=void 0}}class J0 extends c{constructor($){super(1,"commander.invalidArgument",$);Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name}}c0.CommanderError=c;c0.InvalidArgumentError=J0});var x=V((s0)=>{var{InvalidArgumentError:d0}=k();class M0{constructor($,q){switch(this.description=q||"",this.variadic=!1,this.parseArg=void 0,this.defaultValue=void 0,this.defaultValueDescription=void 0,this.argChoices=void 0,$[0]){case"<":this.required=!0,this._name=$.slice(1,-1);break;case"[":this.required=!1,this._name=$.slice(1,-1);break;default:this.required=!0,this._name=$;break}if(this._name.length>3&&this._name.slice(-3)==="...")this.variadic=!0,this._name=this._name.slice(0,-3)}name(){return this._name}_concatValue($,q){if(q===this.defaultValue||!Array.isArray(q))return[$];return q.concat($)}default($,q){return this.defaultValue=$,this.defaultValueDescription=q,this}argParser($){return this.parseArg=$,this}choices($){return this.argChoices=$.slice(),this.parseArg=(q,Q)=>{if(!this.argChoices.includes(q))throw new d0(`Allowed choices are ${this.argChoices.join(", ")}.`);if(this.variadic)return this._concatValue(q,Q);return q},this}argRequired(){return this.required=!0,this}argOptional(){return this.required=!1,this}}function r0($){let q=$.name()+($.variadic===!0?"...":"");return $.required?"<"+q+">":"["+q+"]"}s0.Argument=M0;s0.humanReadableArgName=r0});var l=V((n0)=>{var{humanReadableArgName:t0}=x();class Y0{constructor(){this.helpWidth=void 0,this.sortSubcommands=!1,this.sortOptions=!1,this.showGlobalOptions=!1}visibleCommands($){let q=$.commands.filter((z)=>!z._hidden),Q=$._getHelpCommand();if(Q&&!Q._hidden)q.push(Q);if(this.sortSubcommands)q.sort((z,J)=>{return z.name().localeCompare(J.name())});return q}compareOptions($,q){let Q=(z)=>{return z.short?z.short.replace(/^-/,""):z.long.replace(/^--/,"")};return Q($).localeCompare(Q(q))}visibleOptions($){let q=$.options.filter((z)=>!z.hidden),Q=$._getHelpOption();if(Q&&!Q.hidden){let z=Q.short&&$._findOption(Q.short),J=Q.long&&$._findOption(Q.long);if(!z&&!J)q.push(Q);else if(Q.long&&!J)q.push($.createOption(Q.long,Q.description));else if(Q.short&&!z)q.push($.createOption(Q.short,Q.description))}if(this.sortOptions)q.sort(this.compareOptions);return q}visibleGlobalOptions($){if(!this.showGlobalOptions)return[];let q=[];for(let Q=$.parent;Q;Q=Q.parent){let z=Q.options.filter((J)=>!J.hidden);q.push(...z)}if(this.sortOptions)q.sort(this.compareOptions);return q}visibleArguments($){if($._argsDescription)$.registeredArguments.forEach((q)=>{q.description=q.description||$._argsDescription[q.name()]||""});if($.registeredArguments.find((q)=>q.description))return $.registeredArguments;return[]}subcommandTerm($){let q=$.registeredArguments.map((Q)=>t0(Q)).join(" ");return $._name+($._aliases[0]?"|"+$._aliases[0]:"")+($.options.length?" [options]":"")+(q?" "+q:"")}optionTerm($){return $.flags}argumentTerm($){return $.name()}longestSubcommandTermLength($,q){return q.visibleCommands($).reduce((Q,z)=>{return Math.max(Q,q.subcommandTerm(z).length)},0)}longestOptionTermLength($,q){return q.visibleOptions($).reduce((Q,z)=>{return Math.max(Q,q.optionTerm(z).length)},0)}longestGlobalOptionTermLength($,q){return q.visibleGlobalOptions($).reduce((Q,z)=>{return Math.max(Q,q.optionTerm(z).length)},0)}longestArgumentTermLength($,q){return q.visibleArguments($).reduce((Q,z)=>{return Math.max(Q,q.argumentTerm(z).length)},0)}commandUsage($){let q=$._name;if($._aliases[0])q=q+"|"+$._aliases[0];let Q="";for(let z=$.parent;z;z=z.parent)Q=z.name()+" "+Q;return Q+q+" "+$.usage()}commandDescription($){return $.description()}subcommandDescription($){return $.summary()||$.description()}optionDescription($){let q=[];if($.argChoices)q.push(`choices: ${$.argChoices.map((Q)=>JSON.stringify(Q)).join(", ")}`);if($.defaultValue!==void 0){if($.required||$.optional||$.isBoolean()&&typeof $.defaultValue==="boolean")q.push(`default: ${$.defaultValueDescription||JSON.stringify($.defaultValue)}`)}if($.presetArg!==void 0&&$.optional)q.push(`preset: ${JSON.stringify($.presetArg)}`);if($.envVar!==void 0)q.push(`env: ${$.envVar}`);if(q.length>0)return`${$.description} (${q.join(", ")})`;return $.description}argumentDescription($){let q=[];if($.argChoices)q.push(`choices: ${$.argChoices.map((Q)=>JSON.stringify(Q)).join(", ")}`);if($.defaultValue!==void 0)q.push(`default: ${$.defaultValueDescription||JSON.stringify($.defaultValue)}`);if(q.length>0){let Q=`(${q.join(", ")})`;if($.description)return`${$.description} ${Q}`;return Q}return $.description}formatHelp($,q){let Q=q.padWidth($,q),z=q.helpWidth||80,J=2,M=2;function X(W,N){if(N){let g=`${W.padEnd(Q+2)}${N}`;return q.wrap(g,z-2,Q+2)}return W}function Y(W){return W.join(`
|
|
4
|
+
`).replace(/^/gm," ".repeat(2))}let Z=[`Usage: ${q.commandUsage($)}`,""],_=q.commandDescription($);if(_.length>0)Z=Z.concat([q.wrap(_,z,0),""]);let U=q.visibleArguments($).map((W)=>{return X(q.argumentTerm(W),q.argumentDescription(W))});if(U.length>0)Z=Z.concat(["Arguments:",Y(U),""]);let G=q.visibleOptions($).map((W)=>{return X(q.optionTerm(W),q.optionDescription(W))});if(G.length>0)Z=Z.concat(["Options:",Y(G),""]);if(this.showGlobalOptions){let W=q.visibleGlobalOptions($).map((N)=>{return X(q.optionTerm(N),q.optionDescription(N))});if(W.length>0)Z=Z.concat(["Global Options:",Y(W),""])}let L=q.visibleCommands($).map((W)=>{return X(q.subcommandTerm(W),q.subcommandDescription(W))});if(L.length>0)Z=Z.concat(["Commands:",Y(L),""]);return Z.join(`
|
|
5
|
+
`)}padWidth($,q){return Math.max(q.longestOptionTermLength($,q),q.longestGlobalOptionTermLength($,q),q.longestSubcommandTermLength($,q),q.longestArgumentTermLength($,q))}wrap($,q,Q,z=40){let M=new RegExp(`[\\n][${" \\f\\t\\v\xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF"}]+`);if($.match(M))return $;let X=q-Q;if(X<z)return $;let Y=$.slice(0,Q),Z=$.slice(Q).replace(`\r
|
|
6
|
+
`,`
|
|
7
|
+
`),_=" ".repeat(Q),G=`\\s${"\u200B"}`,L=new RegExp(`
|
|
8
|
+
|.{1,${X-1}}([${G}]|$)|[^${G}]+?([${G}]|$)`,"g"),W=Z.match(L)||[];return Y+W.map((N,g)=>{if(N===`
|
|
9
|
+
`)return"";return(g>0?_:"")+N.trimEnd()}).join(`
|
|
10
|
+
`)}}n0.Help=Y0});var m=V((q1)=>{var{InvalidArgumentError:e0}=k();class X0{constructor($,q){this.flags=$,this.description=q||"",this.required=$.includes("<"),this.optional=$.includes("["),this.variadic=/\w\.\.\.[>\]]$/.test($),this.mandatory=!1;let Q=$1($);if(this.short=Q.shortFlag,this.long=Q.longFlag,this.negate=!1,this.long)this.negate=this.long.startsWith("--no-");this.defaultValue=void 0,this.defaultValueDescription=void 0,this.presetArg=void 0,this.envVar=void 0,this.parseArg=void 0,this.hidden=!1,this.argChoices=void 0,this.conflictsWith=[],this.implied=void 0}default($,q){return this.defaultValue=$,this.defaultValueDescription=q,this}preset($){return this.presetArg=$,this}conflicts($){return this.conflictsWith=this.conflictsWith.concat($),this}implies($){let q=$;if(typeof $==="string")q={[$]:!0};return this.implied=Object.assign(this.implied||{},q),this}env($){return this.envVar=$,this}argParser($){return this.parseArg=$,this}makeOptionMandatory($=!0){return this.mandatory=!!$,this}hideHelp($=!0){return this.hidden=!!$,this}_concatValue($,q){if(q===this.defaultValue||!Array.isArray(q))return[$];return q.concat($)}choices($){return this.argChoices=$.slice(),this.parseArg=(q,Q)=>{if(!this.argChoices.includes(q))throw new e0(`Allowed choices are ${this.argChoices.join(", ")}.`);if(this.variadic)return this._concatValue(q,Q);return q},this}name(){if(this.long)return this.long.replace(/^--/,"");return this.short.replace(/^-/,"")}attributeName(){return o0(this.name().replace(/^no-/,""))}is($){return this.short===$||this.long===$}isBoolean(){return!this.required&&!this.optional&&!this.negate}}class Z0{constructor($){this.positiveOptions=new Map,this.negativeOptions=new Map,this.dualOptions=new Set,$.forEach((q)=>{if(q.negate)this.negativeOptions.set(q.attributeName(),q);else this.positiveOptions.set(q.attributeName(),q)}),this.negativeOptions.forEach((q,Q)=>{if(this.positiveOptions.has(Q))this.dualOptions.add(Q)})}valueFromOption($,q){let Q=q.attributeName();if(!this.dualOptions.has(Q))return!0;let z=this.negativeOptions.get(Q).presetArg,J=z!==void 0?z:!1;return q.negate===(J===$)}}function o0($){return $.split("-").reduce((q,Q)=>{return q+Q[0].toUpperCase()+Q.slice(1)})}function $1($){let q,Q,z=$.split(/[ |,]+/);if(z.length>1&&!/^[[<]/.test(z[1]))q=z.shift();if(Q=z.shift(),!q&&/^-[^-]$/.test(Q))q=Q,Q=void 0;return{shortFlag:q,longFlag:Q}}q1.Option=X0;q1.DualOptions=Z0});var _0=V((Y1)=>{function J1($,q){if(Math.abs($.length-q.length)>3)return Math.max($.length,q.length);let Q=[];for(let z=0;z<=$.length;z++)Q[z]=[z];for(let z=0;z<=q.length;z++)Q[0][z]=z;for(let z=1;z<=q.length;z++)for(let J=1;J<=$.length;J++){let M=1;if($[J-1]===q[z-1])M=0;else M=1;if(Q[J][z]=Math.min(Q[J-1][z]+1,Q[J][z-1]+1,Q[J-1][z-1]+M),J>1&&z>1&&$[J-1]===q[z-2]&&$[J-2]===q[z-1])Q[J][z]=Math.min(Q[J][z],Q[J-2][z-2]+1)}return Q[$.length][q.length]}function M1($,q){if(!q||q.length===0)return"";q=Array.from(new Set(q));let Q=$.startsWith("--");if(Q)$=$.slice(2),q=q.map((X)=>X.slice(2));let z=[],J=3,M=0.4;if(q.forEach((X)=>{if(X.length<=1)return;let Y=J1($,X),Z=Math.max($.length,X.length);if((Z-Y)/Z>M){if(Y<J)J=Y,z=[X];else if(Y===J)z.push(X)}}),z.sort((X,Y)=>X.localeCompare(Y)),Q)z=z.map((X)=>`--${X}`);if(z.length>1)return`
|
|
11
|
+
(Did you mean one of ${z.join(", ")}?)`;if(z.length===1)return`
|
|
12
|
+
(Did you mean ${z[0]}?)`;return""}Y1.suggestSimilar=M1});var W0=V((W1)=>{var Z1=E("events").EventEmitter,d=E("child_process"),j=E("path"),r=E("fs"),H=E("process"),{Argument:_1,humanReadableArgName:U1}=x(),{CommanderError:s}=k(),{Help:B1}=l(),{Option:U0,DualOptions:K1}=m(),{suggestSimilar:B0}=_0();class i extends Z1{constructor($){super();this.commands=[],this.options=[],this.parent=null,this._allowUnknownOption=!1,this._allowExcessArguments=!0,this.registeredArguments=[],this._args=this.registeredArguments,this.args=[],this.rawArgs=[],this.processedArgs=[],this._scriptPath=null,this._name=$||"",this._optionValues={},this._optionValueSources={},this._storeOptionsAsProperties=!1,this._actionHandler=null,this._executableHandler=!1,this._executableFile=null,this._executableDir=null,this._defaultCommandName=null,this._exitCallback=null,this._aliases=[],this._combineFlagAndOptionalValue=!0,this._description="",this._summary="",this._argsDescription=void 0,this._enablePositionalOptions=!1,this._passThroughOptions=!1,this._lifeCycleHooks={},this._showHelpAfterError=!1,this._showSuggestionAfterError=!0,this._outputConfiguration={writeOut:(q)=>H.stdout.write(q),writeErr:(q)=>H.stderr.write(q),getOutHelpWidth:()=>H.stdout.isTTY?H.stdout.columns:void 0,getErrHelpWidth:()=>H.stderr.isTTY?H.stderr.columns:void 0,outputError:(q,Q)=>Q(q)},this._hidden=!1,this._helpOption=void 0,this._addImplicitHelpCommand=void 0,this._helpCommand=void 0,this._helpConfiguration={}}copyInheritedSettings($){return this._outputConfiguration=$._outputConfiguration,this._helpOption=$._helpOption,this._helpCommand=$._helpCommand,this._helpConfiguration=$._helpConfiguration,this._exitCallback=$._exitCallback,this._storeOptionsAsProperties=$._storeOptionsAsProperties,this._combineFlagAndOptionalValue=$._combineFlagAndOptionalValue,this._allowExcessArguments=$._allowExcessArguments,this._enablePositionalOptions=$._enablePositionalOptions,this._showHelpAfterError=$._showHelpAfterError,this._showSuggestionAfterError=$._showSuggestionAfterError,this}_getCommandAndAncestors(){let $=[];for(let q=this;q;q=q.parent)$.push(q);return $}command($,q,Q){let z=q,J=Q;if(typeof z==="object"&&z!==null)J=z,z=null;J=J||{};let[,M,X]=$.match(/([^ ]+) *(.*)/),Y=this.createCommand(M);if(z)Y.description(z),Y._executableHandler=!0;if(J.isDefault)this._defaultCommandName=Y._name;if(Y._hidden=!!(J.noHelp||J.hidden),Y._executableFile=J.executableFile||null,X)Y.arguments(X);if(this._registerCommand(Y),Y.parent=this,Y.copyInheritedSettings(this),z)return this;return Y}createCommand($){return new i($)}createHelp(){return Object.assign(new B1,this.configureHelp())}configureHelp($){if($===void 0)return this._helpConfiguration;return this._helpConfiguration=$,this}configureOutput($){if($===void 0)return this._outputConfiguration;return Object.assign(this._outputConfiguration,$),this}showHelpAfterError($=!0){if(typeof $!=="string")$=!!$;return this._showHelpAfterError=$,this}showSuggestionAfterError($=!0){return this._showSuggestionAfterError=!!$,this}addCommand($,q){if(!$._name)throw Error(`Command passed to .addCommand() must have a name
|
|
13
|
+
- specify the name in Command constructor or using .name()`);if(q=q||{},q.isDefault)this._defaultCommandName=$._name;if(q.noHelp||q.hidden)$._hidden=!0;return this._registerCommand($),$.parent=this,$._checkForBrokenPassThrough(),this}createArgument($,q){return new _1($,q)}argument($,q,Q,z){let J=this.createArgument($,q);if(typeof Q==="function")J.default(z).argParser(Q);else J.default(Q);return this.addArgument(J),this}arguments($){return $.trim().split(/ +/).forEach((q)=>{this.argument(q)}),this}addArgument($){let q=this.registeredArguments.slice(-1)[0];if(q&&q.variadic)throw Error(`only the last argument can be variadic '${q.name()}'`);if($.required&&$.defaultValue!==void 0&&$.parseArg===void 0)throw Error(`a default value for a required argument is never used: '${$.name()}'`);return this.registeredArguments.push($),this}helpCommand($,q){if(typeof $==="boolean")return this._addImplicitHelpCommand=$,this;$=$??"help [command]";let[,Q,z]=$.match(/([^ ]+) *(.*)/),J=q??"display help for command",M=this.createCommand(Q);if(M.helpOption(!1),z)M.arguments(z);if(J)M.description(J);return this._addImplicitHelpCommand=!0,this._helpCommand=M,this}addHelpCommand($,q){if(typeof $!=="object")return this.helpCommand($,q),this;return this._addImplicitHelpCommand=!0,this._helpCommand=$,this}_getHelpCommand(){if(this._addImplicitHelpCommand??(this.commands.length&&!this._actionHandler&&!this._findCommand("help"))){if(this._helpCommand===void 0)this.helpCommand(void 0,void 0);return this._helpCommand}return null}hook($,q){let Q=["preSubcommand","preAction","postAction"];if(!Q.includes($))throw Error(`Unexpected value for event passed to hook : '${$}'.
|
|
14
|
+
Expecting one of '${Q.join("', '")}'`);if(this._lifeCycleHooks[$])this._lifeCycleHooks[$].push(q);else this._lifeCycleHooks[$]=[q];return this}exitOverride($){if($)this._exitCallback=$;else this._exitCallback=(q)=>{if(q.code!=="commander.executeSubCommandAsync")throw q};return this}_exit($,q,Q){if(this._exitCallback)this._exitCallback(new s($,q,Q));H.exit($)}action($){let q=(Q)=>{let z=this.registeredArguments.length,J=Q.slice(0,z);if(this._storeOptionsAsProperties)J[z]=this;else J[z]=this.opts();return J.push(this),$.apply(this,J)};return this._actionHandler=q,this}createOption($,q){return new U0($,q)}_callParseArg($,q,Q,z){try{return $.parseArg(q,Q)}catch(J){if(J.code==="commander.invalidArgument"){let M=`${z} ${J.message}`;this.error(M,{exitCode:J.exitCode,code:J.code})}throw J}}_registerOption($){let q=$.short&&this._findOption($.short)||$.long&&this._findOption($.long);if(q){let Q=$.long&&this._findOption($.long)?$.long:$.short;throw Error(`Cannot add option '${$.flags}'${this._name&&` to command '${this._name}'`} due to conflicting flag '${Q}'
|
|
15
|
+
- already used by option '${q.flags}'`)}this.options.push($)}_registerCommand($){let q=(z)=>{return[z.name()].concat(z.aliases())},Q=q($).find((z)=>this._findCommand(z));if(Q){let z=q(this._findCommand(Q)).join("|"),J=q($).join("|");throw Error(`cannot add command '${J}' as already have command '${z}'`)}this.commands.push($)}addOption($){this._registerOption($);let q=$.name(),Q=$.attributeName();if($.negate){let J=$.long.replace(/^--no-/,"--");if(!this._findOption(J))this.setOptionValueWithSource(Q,$.defaultValue===void 0?!0:$.defaultValue,"default")}else if($.defaultValue!==void 0)this.setOptionValueWithSource(Q,$.defaultValue,"default");let z=(J,M,X)=>{if(J==null&&$.presetArg!==void 0)J=$.presetArg;let Y=this.getOptionValue(Q);if(J!==null&&$.parseArg)J=this._callParseArg($,J,Y,M);else if(J!==null&&$.variadic)J=$._concatValue(J,Y);if(J==null)if($.negate)J=!1;else if($.isBoolean()||$.optional)J=!0;else J="";this.setOptionValueWithSource(Q,J,X)};if(this.on("option:"+q,(J)=>{let M=`error: option '${$.flags}' argument '${J}' is invalid.`;z(J,M,"cli")}),$.envVar)this.on("optionEnv:"+q,(J)=>{let M=`error: option '${$.flags}' value '${J}' from env '${$.envVar}' is invalid.`;z(J,M,"env")});return this}_optionEx($,q,Q,z,J){if(typeof q==="object"&&q instanceof U0)throw Error("To add an Option object use addOption() instead of option() or requiredOption()");let M=this.createOption(q,Q);if(M.makeOptionMandatory(!!$.mandatory),typeof z==="function")M.default(J).argParser(z);else if(z instanceof RegExp){let X=z;z=(Y,Z)=>{let _=X.exec(Y);return _?_[0]:Z},M.default(J).argParser(z)}else M.default(z);return this.addOption(M)}option($,q,Q,z){return this._optionEx({},$,q,Q,z)}requiredOption($,q,Q,z){return this._optionEx({mandatory:!0},$,q,Q,z)}combineFlagAndOptionalValue($=!0){return this._combineFlagAndOptionalValue=!!$,this}allowUnknownOption($=!0){return this._allowUnknownOption=!!$,this}allowExcessArguments($=!0){return this._allowExcessArguments=!!$,this}enablePositionalOptions($=!0){return this._enablePositionalOptions=!!$,this}passThroughOptions($=!0){return this._passThroughOptions=!!$,this._checkForBrokenPassThrough(),this}_checkForBrokenPassThrough(){if(this.parent&&this._passThroughOptions&&!this.parent._enablePositionalOptions)throw Error(`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`)}storeOptionsAsProperties($=!0){if(this.options.length)throw Error("call .storeOptionsAsProperties() before adding options");if(Object.keys(this._optionValues).length)throw Error("call .storeOptionsAsProperties() before setting option values");return this._storeOptionsAsProperties=!!$,this}getOptionValue($){if(this._storeOptionsAsProperties)return this[$];return this._optionValues[$]}setOptionValue($,q){return this.setOptionValueWithSource($,q,void 0)}setOptionValueWithSource($,q,Q){if(this._storeOptionsAsProperties)this[$]=q;else this._optionValues[$]=q;return this._optionValueSources[$]=Q,this}getOptionValueSource($){return this._optionValueSources[$]}getOptionValueSourceWithGlobals($){let q;return this._getCommandAndAncestors().forEach((Q)=>{if(Q.getOptionValueSource($)!==void 0)q=Q.getOptionValueSource($)}),q}_prepareUserArgs($,q){if($!==void 0&&!Array.isArray($))throw Error("first parameter to parse must be array or undefined");if(q=q||{},$===void 0&&q.from===void 0){if(H.versions?.electron)q.from="electron";let z=H.execArgv??[];if(z.includes("-e")||z.includes("--eval")||z.includes("-p")||z.includes("--print"))q.from="eval"}if($===void 0)$=H.argv;this.rawArgs=$.slice();let Q;switch(q.from){case void 0:case"node":this._scriptPath=$[1],Q=$.slice(2);break;case"electron":if(H.defaultApp)this._scriptPath=$[1],Q=$.slice(2);else Q=$.slice(1);break;case"user":Q=$.slice(0);break;case"eval":Q=$.slice(1);break;default:throw Error(`unexpected parse option { from: '${q.from}' }`)}if(!this._name&&this._scriptPath)this.nameFromFilename(this._scriptPath);return this._name=this._name||"program",Q}parse($,q){let Q=this._prepareUserArgs($,q);return this._parseCommand([],Q),this}async parseAsync($,q){let Q=this._prepareUserArgs($,q);return await this._parseCommand([],Q),this}_executeSubCommand($,q){q=q.slice();let Q=!1,z=[".js",".ts",".tsx",".mjs",".cjs"];function J(_,U){let G=j.resolve(_,U);if(r.existsSync(G))return G;if(z.includes(j.extname(U)))return;let L=z.find((W)=>r.existsSync(`${G}${W}`));if(L)return`${G}${L}`;return}this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let M=$._executableFile||`${this._name}-${$._name}`,X=this._executableDir||"";if(this._scriptPath){let _;try{_=r.realpathSync(this._scriptPath)}catch(U){_=this._scriptPath}X=j.resolve(j.dirname(_),X)}if(X){let _=J(X,M);if(!_&&!$._executableFile&&this._scriptPath){let U=j.basename(this._scriptPath,j.extname(this._scriptPath));if(U!==this._name)_=J(X,`${U}-${$._name}`)}M=_||M}Q=z.includes(j.extname(M));let Y;if(H.platform!=="win32")if(Q)q.unshift(M),q=K0(H.execArgv).concat(q),Y=d.spawn(H.argv[0],q,{stdio:"inherit"});else Y=d.spawn(M,q,{stdio:"inherit"});else q.unshift(M),q=K0(H.execArgv).concat(q),Y=d.spawn(H.execPath,q,{stdio:"inherit"});if(!Y.killed)["SIGUSR1","SIGUSR2","SIGTERM","SIGINT","SIGHUP"].forEach((U)=>{H.on(U,()=>{if(Y.killed===!1&&Y.exitCode===null)Y.kill(U)})});let Z=this._exitCallback;Y.on("close",(_)=>{if(_=_??1,!Z)H.exit(_);else Z(new s(_,"commander.executeSubCommandAsync","(close)"))}),Y.on("error",(_)=>{if(_.code==="ENOENT"){let U=X?`searched for local subcommand relative to directory '${X}'`:"no directory for search for local subcommand, use .executableDir() to supply a custom directory",G=`'${M}' does not exist
|
|
16
|
+
- if '${$._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
17
|
+
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
|
|
18
|
+
- ${U}`;throw Error(G)}else if(_.code==="EACCES")throw Error(`'${M}' not executable`);if(!Z)H.exit(1);else{let U=new s(1,"commander.executeSubCommandAsync","(error)");U.nestedError=_,Z(U)}}),this.runningCommand=Y}_dispatchSubcommand($,q,Q){let z=this._findCommand($);if(!z)this.help({error:!0});let J;return J=this._chainOrCallSubCommandHook(J,z,"preSubcommand"),J=this._chainOrCall(J,()=>{if(z._executableHandler)this._executeSubCommand(z,q.concat(Q));else return z._parseCommand(q,Q)}),J}_dispatchHelpCommand($){if(!$)this.help();let q=this._findCommand($);if(q&&!q._executableHandler)q.help();return this._dispatchSubcommand($,[],[this._getHelpOption()?.long??this._getHelpOption()?.short??"--help"])}_checkNumberOfArguments(){if(this.registeredArguments.forEach(($,q)=>{if($.required&&this.args[q]==null)this.missingArgument($.name())}),this.registeredArguments.length>0&&this.registeredArguments[this.registeredArguments.length-1].variadic)return;if(this.args.length>this.registeredArguments.length)this._excessArguments(this.args)}_processArguments(){let $=(Q,z,J)=>{let M=z;if(z!==null&&Q.parseArg){let X=`error: command-argument value '${z}' is invalid for argument '${Q.name()}'.`;M=this._callParseArg(Q,z,J,X)}return M};this._checkNumberOfArguments();let q=[];this.registeredArguments.forEach((Q,z)=>{let J=Q.defaultValue;if(Q.variadic){if(z<this.args.length){if(J=this.args.slice(z),Q.parseArg)J=J.reduce((M,X)=>{return $(Q,X,M)},Q.defaultValue)}else if(J===void 0)J=[]}else if(z<this.args.length){if(J=this.args[z],Q.parseArg)J=$(Q,J,Q.defaultValue)}q[z]=J}),this.processedArgs=q}_chainOrCall($,q){if($&&$.then&&typeof $.then==="function")return $.then(()=>q());return q()}_chainOrCallHooks($,q){let Q=$,z=[];if(this._getCommandAndAncestors().reverse().filter((J)=>J._lifeCycleHooks[q]!==void 0).forEach((J)=>{J._lifeCycleHooks[q].forEach((M)=>{z.push({hookedCommand:J,callback:M})})}),q==="postAction")z.reverse();return z.forEach((J)=>{Q=this._chainOrCall(Q,()=>{return J.callback(J.hookedCommand,this)})}),Q}_chainOrCallSubCommandHook($,q,Q){let z=$;if(this._lifeCycleHooks[Q]!==void 0)this._lifeCycleHooks[Q].forEach((J)=>{z=this._chainOrCall(z,()=>{return J(this,q)})});return z}_parseCommand($,q){let Q=this.parseOptions(q);if(this._parseOptionsEnv(),this._parseOptionsImplied(),$=$.concat(Q.operands),q=Q.unknown,this.args=$.concat(q),$&&this._findCommand($[0]))return this._dispatchSubcommand($[0],$.slice(1),q);if(this._getHelpCommand()&&$[0]===this._getHelpCommand().name())return this._dispatchHelpCommand($[1]);if(this._defaultCommandName)return this._outputHelpIfRequested(q),this._dispatchSubcommand(this._defaultCommandName,$,q);if(this.commands.length&&this.args.length===0&&!this._actionHandler&&!this._defaultCommandName)this.help({error:!0});this._outputHelpIfRequested(Q.unknown),this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let z=()=>{if(Q.unknown.length>0)this.unknownOption(Q.unknown[0])},J=`command:${this.name()}`;if(this._actionHandler){z(),this._processArguments();let M;if(M=this._chainOrCallHooks(M,"preAction"),M=this._chainOrCall(M,()=>this._actionHandler(this.processedArgs)),this.parent)M=this._chainOrCall(M,()=>{this.parent.emit(J,$,q)});return M=this._chainOrCallHooks(M,"postAction"),M}if(this.parent&&this.parent.listenerCount(J))z(),this._processArguments(),this.parent.emit(J,$,q);else if($.length){if(this._findCommand("*"))return this._dispatchSubcommand("*",$,q);if(this.listenerCount("command:*"))this.emit("command:*",$,q);else if(this.commands.length)this.unknownCommand();else z(),this._processArguments()}else if(this.commands.length)z(),this.help({error:!0});else z(),this._processArguments()}_findCommand($){if(!$)return;return this.commands.find((q)=>q._name===$||q._aliases.includes($))}_findOption($){return this.options.find((q)=>q.is($))}_checkForMissingMandatoryOptions(){this._getCommandAndAncestors().forEach(($)=>{$.options.forEach((q)=>{if(q.mandatory&&$.getOptionValue(q.attributeName())===void 0)$.missingMandatoryOptionValue(q)})})}_checkForConflictingLocalOptions(){let $=this.options.filter((Q)=>{let z=Q.attributeName();if(this.getOptionValue(z)===void 0)return!1;return this.getOptionValueSource(z)!=="default"});$.filter((Q)=>Q.conflictsWith.length>0).forEach((Q)=>{let z=$.find((J)=>Q.conflictsWith.includes(J.attributeName()));if(z)this._conflictingOption(Q,z)})}_checkForConflictingOptions(){this._getCommandAndAncestors().forEach(($)=>{$._checkForConflictingLocalOptions()})}parseOptions($){let q=[],Q=[],z=q,J=$.slice();function M(Y){return Y.length>1&&Y[0]==="-"}let X=null;while(J.length){let Y=J.shift();if(Y==="--"){if(z===Q)z.push(Y);z.push(...J);break}if(X&&!M(Y)){this.emit(`option:${X.name()}`,Y);continue}if(X=null,M(Y)){let Z=this._findOption(Y);if(Z){if(Z.required){let _=J.shift();if(_===void 0)this.optionMissingArgument(Z);this.emit(`option:${Z.name()}`,_)}else if(Z.optional){let _=null;if(J.length>0&&!M(J[0]))_=J.shift();this.emit(`option:${Z.name()}`,_)}else this.emit(`option:${Z.name()}`);X=Z.variadic?Z:null;continue}}if(Y.length>2&&Y[0]==="-"&&Y[1]!=="-"){let Z=this._findOption(`-${Y[1]}`);if(Z){if(Z.required||Z.optional&&this._combineFlagAndOptionalValue)this.emit(`option:${Z.name()}`,Y.slice(2));else this.emit(`option:${Z.name()}`),J.unshift(`-${Y.slice(2)}`);continue}}if(/^--[^=]+=/.test(Y)){let Z=Y.indexOf("="),_=this._findOption(Y.slice(0,Z));if(_&&(_.required||_.optional)){this.emit(`option:${_.name()}`,Y.slice(Z+1));continue}}if(M(Y))z=Q;if((this._enablePositionalOptions||this._passThroughOptions)&&q.length===0&&Q.length===0){if(this._findCommand(Y)){if(q.push(Y),J.length>0)Q.push(...J);break}else if(this._getHelpCommand()&&Y===this._getHelpCommand().name()){if(q.push(Y),J.length>0)q.push(...J);break}else if(this._defaultCommandName){if(Q.push(Y),J.length>0)Q.push(...J);break}}if(this._passThroughOptions){if(z.push(Y),J.length>0)z.push(...J);break}z.push(Y)}return{operands:q,unknown:Q}}opts(){if(this._storeOptionsAsProperties){let $={},q=this.options.length;for(let Q=0;Q<q;Q++){let z=this.options[Q].attributeName();$[z]=z===this._versionOptionName?this._version:this[z]}return $}return this._optionValues}optsWithGlobals(){return this._getCommandAndAncestors().reduce(($,q)=>Object.assign($,q.opts()),{})}error($,q){if(this._outputConfiguration.outputError(`${$}
|
|
19
|
+
`,this._outputConfiguration.writeErr),typeof this._showHelpAfterError==="string")this._outputConfiguration.writeErr(`${this._showHelpAfterError}
|
|
20
|
+
`);else if(this._showHelpAfterError)this._outputConfiguration.writeErr(`
|
|
21
|
+
`),this.outputHelp({error:!0});let Q=q||{},z=Q.exitCode||1,J=Q.code||"commander.error";this._exit(z,J,$)}_parseOptionsEnv(){this.options.forEach(($)=>{if($.envVar&&$.envVar in H.env){let q=$.attributeName();if(this.getOptionValue(q)===void 0||["default","config","env"].includes(this.getOptionValueSource(q)))if($.required||$.optional)this.emit(`optionEnv:${$.name()}`,H.env[$.envVar]);else this.emit(`optionEnv:${$.name()}`)}})}_parseOptionsImplied(){let $=new K1(this.options),q=(Q)=>{return this.getOptionValue(Q)!==void 0&&!["default","implied"].includes(this.getOptionValueSource(Q))};this.options.filter((Q)=>Q.implied!==void 0&&q(Q.attributeName())&&$.valueFromOption(this.getOptionValue(Q.attributeName()),Q)).forEach((Q)=>{Object.keys(Q.implied).filter((z)=>!q(z)).forEach((z)=>{this.setOptionValueWithSource(z,Q.implied[z],"implied")})})}missingArgument($){let q=`error: missing required argument '${$}'`;this.error(q,{code:"commander.missingArgument"})}optionMissingArgument($){let q=`error: option '${$.flags}' argument missing`;this.error(q,{code:"commander.optionMissingArgument"})}missingMandatoryOptionValue($){let q=`error: required option '${$.flags}' not specified`;this.error(q,{code:"commander.missingMandatoryOptionValue"})}_conflictingOption($,q){let Q=(M)=>{let X=M.attributeName(),Y=this.getOptionValue(X),Z=this.options.find((U)=>U.negate&&X===U.attributeName()),_=this.options.find((U)=>!U.negate&&X===U.attributeName());if(Z&&(Z.presetArg===void 0&&Y===!1||Z.presetArg!==void 0&&Y===Z.presetArg))return Z;return _||M},z=(M)=>{let X=Q(M),Y=X.attributeName();if(this.getOptionValueSource(Y)==="env")return`environment variable '${X.envVar}'`;return`option '${X.flags}'`},J=`error: ${z($)} cannot be used with ${z(q)}`;this.error(J,{code:"commander.conflictingOption"})}unknownOption($){if(this._allowUnknownOption)return;let q="";if($.startsWith("--")&&this._showSuggestionAfterError){let z=[],J=this;do{let M=J.createHelp().visibleOptions(J).filter((X)=>X.long).map((X)=>X.long);z=z.concat(M),J=J.parent}while(J&&!J._enablePositionalOptions);q=B0($,z)}let Q=`error: unknown option '${$}'${q}`;this.error(Q,{code:"commander.unknownOption"})}_excessArguments($){if(this._allowExcessArguments)return;let q=this.registeredArguments.length,Q=q===1?"":"s",J=`error: too many arguments${this.parent?` for '${this.name()}'`:""}. Expected ${q} argument${Q} but got ${$.length}.`;this.error(J,{code:"commander.excessArguments"})}unknownCommand(){let $=this.args[0],q="";if(this._showSuggestionAfterError){let z=[];this.createHelp().visibleCommands(this).forEach((J)=>{if(z.push(J.name()),J.alias())z.push(J.alias())}),q=B0($,z)}let Q=`error: unknown command '${$}'${q}`;this.error(Q,{code:"commander.unknownCommand"})}version($,q,Q){if($===void 0)return this._version;this._version=$,q=q||"-V, --version",Q=Q||"output the version number";let z=this.createOption(q,Q);return this._versionOptionName=z.attributeName(),this._registerOption(z),this.on("option:"+z.name(),()=>{this._outputConfiguration.writeOut(`${$}
|
|
22
|
+
`),this._exit(0,"commander.version",$)}),this}description($,q){if($===void 0&&q===void 0)return this._description;if(this._description=$,q)this._argsDescription=q;return this}summary($){if($===void 0)return this._summary;return this._summary=$,this}alias($){if($===void 0)return this._aliases[0];let q=this;if(this.commands.length!==0&&this.commands[this.commands.length-1]._executableHandler)q=this.commands[this.commands.length-1];if($===q._name)throw Error("Command alias can't be the same as its name");let Q=this.parent?._findCommand($);if(Q){let z=[Q.name()].concat(Q.aliases()).join("|");throw Error(`cannot add alias '${$}' to command '${this.name()}' as already have command '${z}'`)}return q._aliases.push($),this}aliases($){if($===void 0)return this._aliases;return $.forEach((q)=>this.alias(q)),this}usage($){if($===void 0){if(this._usage)return this._usage;let q=this.registeredArguments.map((Q)=>{return U1(Q)});return[].concat(this.options.length||this._helpOption!==null?"[options]":[],this.commands.length?"[command]":[],this.registeredArguments.length?q:[]).join(" ")}return this._usage=$,this}name($){if($===void 0)return this._name;return this._name=$,this}nameFromFilename($){return this._name=j.basename($,j.extname($)),this}executableDir($){if($===void 0)return this._executableDir;return this._executableDir=$,this}helpInformation($){let q=this.createHelp();if(q.helpWidth===void 0)q.helpWidth=$&&$.error?this._outputConfiguration.getErrHelpWidth():this._outputConfiguration.getOutHelpWidth();return q.formatHelp(this,q)}_getHelpContext($){$=$||{};let q={error:!!$.error},Q;if(q.error)Q=(z)=>this._outputConfiguration.writeErr(z);else Q=(z)=>this._outputConfiguration.writeOut(z);return q.write=$.write||Q,q.command=this,q}outputHelp($){let q;if(typeof $==="function")q=$,$=void 0;let Q=this._getHelpContext($);this._getCommandAndAncestors().reverse().forEach((J)=>J.emit("beforeAllHelp",Q)),this.emit("beforeHelp",Q);let z=this.helpInformation(Q);if(q){if(z=q(z),typeof z!=="string"&&!Buffer.isBuffer(z))throw Error("outputHelp callback must return a string or a Buffer")}if(Q.write(z),this._getHelpOption()?.long)this.emit(this._getHelpOption().long);this.emit("afterHelp",Q),this._getCommandAndAncestors().forEach((J)=>J.emit("afterAllHelp",Q))}helpOption($,q){if(typeof $==="boolean"){if($)this._helpOption=this._helpOption??void 0;else this._helpOption=null;return this}return $=$??"-h, --help",q=q??"display help for command",this._helpOption=this.createOption($,q),this}_getHelpOption(){if(this._helpOption===void 0)this.helpOption(void 0,void 0);return this._helpOption}addHelpOption($){return this._helpOption=$,this}help($){this.outputHelp($);let q=H.exitCode||0;if(q===0&&$&&typeof $!=="function"&&$.error)q=1;this._exit(q,"commander.help","(outputHelp)")}addHelpText($,q){let Q=["beforeAll","before","after","afterAll"];if(!Q.includes($))throw Error(`Unexpected value for position to addHelpText.
|
|
23
|
+
Expecting one of '${Q.join("', '")}'`);let z=`${$}Help`;return this.on(z,(J)=>{let M;if(typeof q==="function")M=q({error:J.error,command:J.command});else M=q;if(M)J.write(`${M}
|
|
24
|
+
`)}),this}_outputHelpIfRequested($){let q=this._getHelpOption();if(q&&$.find((z)=>q.is(z)))this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)")}}function K0($){return $.map((q)=>{if(!q.startsWith("--inspect"))return q;let Q,z="127.0.0.1",J="9229",M;if((M=q.match(/^(--inspect(-brk)?)$/))!==null)Q=M[1];else if((M=q.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))!==null)if(Q=M[1],/^\d+$/.test(M[3]))J=M[3];else z=M[3];else if((M=q.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null)Q=M[1],z=M[3],J=M[4];if(Q&&J!=="0")return`${Q}=${z}:${parseInt(J)+1}`;return q})}W1.Command=i});var L0=V((L1)=>{var{Argument:G0}=x(),{Command:p}=W0(),{CommanderError:H1,InvalidArgumentError:H0}=k(),{Help:R1}=l(),{Option:R0}=m();L1.program=new p;L1.createCommand=($)=>new p($);L1.createOption=($,q)=>new R0($,q);L1.createArgument=($,q)=>new G0($,q);L1.Command=p;L1.Option=R0;L1.Argument=G0;L1.Help=R1;L1.CommanderError=H1;L1.InvalidArgumentError=H0;L1.InvalidOptionArgumentError=H0});import{spawnSync as C0}from"child_process";import{cpSync as u,existsSync as T,mkdirSync as A,readFileSync as h,rmSync as v}from"fs";import{homedir as F}from"os";import{dirname as $0,join as K}from"path";import{fileURLToPath as m1}from"url";var T0=g0(L0(),1),{program:q$,createCommand:Q$,createArgument:z$,createOption:J$,CommanderError:M$,InvalidArgumentError:Y$,InvalidOptionArgumentError:X$,Command:E0,Argument:Z$,Option:_$,Help:U$}=T0.default;function n($){return $.map((q)=>Number(q.close??q.c)).filter(Number.isFinite)}function y0($,q){return $.map((Q,z)=>{if(z+1<q)return null;let J=$.slice(z+1-q,z+1);return w(J)})}function t($,q){let Q=2/(q+1),z=null;return $.map((J,M)=>{return z=M===0||z===null?J:J*Q+z*(1-Q),z})}function I0($,q=14){return $.map((Q,z)=>{if(z<q)return null;let J=$.slice(z+1-q,z+1).map((Z,_,U)=>_===0?0:Z-U[_-1]),M=J.filter((Z)=>Z>0),X=J.filter((Z)=>Z<0).map(Math.abs);return 100-100/(1+w(M)/(w(X)||0.000000001))})}function P0($){let q=t($,12),Q=t($,26),z=q.map((M,X)=>M-Q[X]),J=t(z,9);return z.map((M,X)=>({macd:M,signal:J[X],histogram:M-J[X]}))}function j0($,q=0){let Q=$.slice(1).map((Y,Z)=>Y/$[Z]-1).filter(Number.isFinite),z=w(Q),J=w1(Q)*Math.sqrt(252),M=z*252,X=J===0?null:(M-q)/J;return{count:$.length,annualReturn:M,volatility:J,sharpe:X,maxDrawdown:f1($)}}function w($){return $.length?$.reduce((q,Q)=>q+Q,0)/$.length:0}function w1($){let q=w($);return Math.sqrt(w($.map((Q)=>(Q-q)**2)))}function f1($){let q=$[0]??0,Q=0;for(let z of $)q=Math.max(q,z),Q=Math.min(Q,z/q-1);return Q}import{mkdir as A1,readFile as b1,rm as k1,writeFile as C1}from"fs/promises";import{dirname as x1,join as O1}from"path";var h1=process.env.HOME??process.cwd(),D=O1(h1,".config","mozyfin-cli","config.json"),C="https://api.mozyfin.com";async function a(){try{return JSON.parse(await b1(D,"utf8"))}catch{return{}}}async function F0($){await A1(x1(D),{recursive:!0}),await C1(D,`${JSON.stringify($,null,2)}
|
|
25
|
+
`,{mode:384})}async function N0(){await k1(D,{force:!0})}async function V0($){let q=await a();return $??process.env.MOZYFIN_API_KEY??q.apiKey}function D0(){return"Missing API key. Run `mozyfin login --api-key <key>` or create one at https://research.mozyfin.com/settings"}var S0=0;async function v1($=Date.now()){let q=Math.max(0,1000-($-S0));if(q>0)await new Promise((Q)=>setTimeout(Q,q));S0=Date.now()}function u1($,q,Q={}){let z=new URL(q,$);for(let[J,M]of Object.entries(Q)){if(M===void 0||M==="")continue;if(Array.isArray(M))for(let X of M)z.searchParams.append(J,X);else z.searchParams.set(J,String(M))}return z}class O{baseUrl;apiKey;constructor($={}){this.baseUrl=$.baseUrl??C,this.apiKey=$.apiKey}static async fromConfig($){let q=await a();return new O({baseUrl:q.baseUrl??C,apiKey:await V0($)})}async request($,q={}){if(q.auth!==!1&&!this.apiKey)throw Error(D0());await v1();let Q=await fetch(u1(this.baseUrl,$,q.query),{method:q.method??"GET",headers:{"content-type":"application/json",...this.apiKey?{"X-API-Key":this.apiKey,authorization:`Bearer ${this.apiKey}`}:{}},body:q.body?JSON.stringify(q.body):void 0}),z=await Q.text(),J=z?JSON.parse(z):null;if(!Q.ok)throw Error(J?.message??J?.detail??`HTTP ${Q.status}`);return J}entities($){return this.request("/api/v1/market/exchange/entity",{query:$,auth:!1})}entity($){return this.request(`/api/v1/market/exchange/entity/${$}`,{auth:!1})}news($){return this.request("/api/v1/news",{query:$,auth:!1})}ohlcv($,q){return this.request(`/api/v1/market/exchange/entity/${$}/ohlcv`,{query:q,auth:!1})}historicalQuote($,q){return this.request(`/api/v1/market/exchange/entity/${$}/historical-quote`,{query:q,auth:!1})}offices($){return this.request(`/api/v1/market/exchange/entity/${$}/office`,{auth:!1})}subsidiaries($){return this.request(`/api/v1/market/exchange/entity/${$}/subsidiary`,{auth:!1})}holders($,q){return this.request(`/api/v1/market/exchange/entity/${$}/holder`,{query:q,auth:!1})}holderTransactions($,q){return this.request(`/api/v1/market/exchange/entity/${$}/holder-transaction`,{query:q,auth:!1})}financialStatements($,q){return this.request(`/api/v1/market/exchange/entity/${$}/financial-statement`,{query:q,auth:!1})}financialStatistics($,q){return this.request(`/api/v1/market/exchange/entity/${$}/financial-statistic`,{query:q,auth:!1})}usage(){return this.request("/api/v1/subscription/usage")}createChat(){return this.request("/api/v1/chat",{method:"POST",body:{title:"mozyfin-cli",mode:"auto"}})}sendMessage($,q){return this.request(`/api/v1/chat/${$}/message`,{method:"POST",body:{content:q}})}getMessage($){return this.request(`/api/v1/chat/messages/${$}`)}queryReport($){return this.request("/api/v1/document/query-report",{method:"POST",body:{query:$}})}}import{writeFile as g1}from"fs/promises";function e($){return $?.data??$?.result??$}function P($){let q=e($);if(Array.isArray(q))return q;if(Array.isArray(q?.items))return q.items;if(Array.isArray(q?.results))return q.results;if(Array.isArray(q?.data))return q.data;return q?[q]:[]}function S($){let q=P($);if(q.length===0)return"_No data_";return o(q,Object.keys(q[0]).slice(0,8))}function o($,q){let Q=P($);if(Q.length===0)return"_No data_";let z=q.filter((Y)=>Q.some((Z)=>Z?.[Y]!==void 0));if(z.length===0)return S($);let J=`| ${z.join(" | ")} |`,M=`| ${z.map(()=>"---").join(" | ")} |`,X=Q.map((Y)=>`| ${z.map((Z)=>A0(Y?.[Z])).join(" | ")} |`).join(`
|
|
26
|
+
`);return`${J}
|
|
27
|
+
${M}
|
|
28
|
+
${X}`}function w0($,q){let[Q]=P($);if(!Q)return"_No data_";return(q?.filter((J)=>Q[J]!==void 0)??Object.keys(Q)).map((J)=>`- ${J}: ${A0(Q[J])}`).join(`
|
|
29
|
+
`)}function f0($,q="content"){let Q=P($)[0]??e($);return Q?.[q]??Q?.message?.[q]??Q?.data?.[q]??"_No content_"}function A0($){if($===null||$===void 0)return"";if(typeof $==="object"){let q=$,Q=q.symbol??q.id??q.name??q.title;if(Q!==void 0)return String(Q).replaceAll("|","\\|");return JSON.stringify($).replaceAll("|","\\|").slice(0,120)}return String($).replaceAll("|","\\|")}function c1($){let q=P($);if(q.length===0)return"";let Q=Array.from(new Set(q.flatMap((z)=>Object.keys(z))));return[Q.join(","),...q.map((z)=>Q.map((J)=>l1(z[J])).join(","))].join(`
|
|
30
|
+
`)}function l1($){let q=$===null||$===void 0?"":typeof $==="object"?JSON.stringify($):String($);return/[",\n]/.test(q)?`"${q.replaceAll('"','""')}"`:q}function b0($){let q=e($),Q=[],z=q?.entities??[];if(z.length>0)Q.push(`### Entities (${z.length})
|
|
31
|
+
|
|
32
|
+
${S(z)}`);let J=q?.relationships??[];if(J.length>0)Q.push(`
|
|
33
|
+
### Relationships (${J.length})
|
|
34
|
+
|
|
35
|
+
${S(J)}`);let M=q?.chunks??[];if(M.length>0)Q.push(`
|
|
36
|
+
### Document Chunks (${M.length})
|
|
37
|
+
|
|
38
|
+
${S(M)}`);let X=q?.references??[];if(X.length>0)Q.push(`
|
|
39
|
+
### References (${X.length})
|
|
40
|
+
|
|
41
|
+
${S(X)}`);if(q?.instructions)Q.push(`
|
|
42
|
+
### Context
|
|
43
|
+
|
|
44
|
+
${q.instructions}`);return Q.length>0?Q.join(`
|
|
45
|
+
`):"_No data_"}async function f($,q){if(q.csv){await g1(q.csv,`${c1($)}
|
|
46
|
+
`),console.log(S([{ok:!0,file:q.csv,rows:P($).length}]));return}console.log(S($))}var q0=$0(m1(import.meta.url)),d1=JSON.parse(h(K(q0,"..","package.json"),"utf8")),B=new E0;B.name("mozyfin").description("Vietnam stock market CLI for humans and AI agents").version(d1.version).showHelpAfterError().addHelpText("after",`
|
|
47
|
+
|
|
48
|
+
Examples:
|
|
49
|
+
$ mozyfin login --api-key <key>
|
|
50
|
+
$ mozyfin search --query VNM --md
|
|
51
|
+
$ mozyfin quote VNM.VN --md
|
|
52
|
+
$ mozyfin ohlcv VNM.VN --timeframe 1d --limit 200 --csv vnm.csv
|
|
53
|
+
$ mozyfin ta VNM.VN --sma 20,50 --rsi 14 --macd --csv vnm-ta.csv
|
|
54
|
+
$ mozyfin doc "VNM Q4 2024 earnings analysis"
|
|
55
|
+
$ mozyfin ask "compare VNM and MSN margin trend"
|
|
56
|
+
`).option("--api-key <key>","API key, or set MOZYFIN_API_KEY").option("--base-url <url>","API base URL",C).option("--no-color","reserved for scripts/agents; output stays plain text");function y($){return $.option("-m, --md","print Markdown table (default)").option("--csv <file>","write rows to CSV file")}async function R(){let $=B.opts(),q=await O.fromConfig($.apiKey);return q.baseUrl=$.baseUrl,q}function k0($){if(!$)return;let q=$.split(",").map((Q)=>Q.trim()).filter(Boolean);return q.length?q:void 0}function x0($,q,Q){if(!q.includes($))throw Error(`${Q} must be one of: ${q.join(", ")}`);return $}async function I($,q,Q){if(q.csv)return f($,q);console.log(o($,Q))}async function Q0($,q,Q){if(q.csv)return f($,q);console.log(w0($,Q))}function r1($){return P($).map((q)=>{let Q=q.values??{};return{year:q.year,quarter:q.quarter,type:q.type,net_sales:Q["Net sales"]??Q.Sales,gross_profit:Q["Gross Profit"],profit_after_tax:Q["Net profit/(loss) after tax"],total_assets:Q["Total Assets"],owner_equity:Q["Owner's Equity"],net_operating_cash_flow:Q["Net cash inflows/(outflows) from operating activities"],public_at:q.public_at}})}B.command("login").description("Save API key locally").option("--api-key <key>").action(async($)=>{let q=$.apiKey??B.opts().apiKey;if(!q)throw Error("Missing --api-key <key>");await F0({apiKey:q,baseUrl:B.opts().baseUrl}),await f([{ok:!0,configPath:D}],{})});B.command("logout").description("Remove saved API key").action(async()=>{await N0(),await f([{ok:!0}],{})});y(B.command("search").description("Search companies/entities by ticker, name or text")).option("-q, --query [text]","search query; empty means all","").action(async($)=>I(await(await R()).entities({search:$.query}),$,["symbol","ticker","name","exchange","market","price","market_cap","id"]));y(B.command("profile").argument("<tickerOrEntityId>").description("Company profile/entity details")).action(async($,q)=>Q0(await(await R()).entity($),q,["symbol","ticker","name","exchange","market","sector","industry","website","description","entity_id","id"]));y(B.command("news").description("Market headlines and article search")).option("--query <text>","search query; empty means all","").option("--entities <ids>","comma-separated entity ids; OR semantics").option("--topics <topics>","comma-separated topics: stock,crypto,forex,tariff,economic,earning,tech,housing,mergers_and_ipo; OR semantics").option("--limit <n>","max rows","20").option("--page <n>","page hint for APIs that support it","1").action(async($)=>I(await(await R()).news(s1($)),$,["published_at","created_at","title","source","topics","entities","url","id"]));function s1($){let q=["stock","crypto","forex","tariff","economic","earning","tech","housing","mergers_and_ipo"],Q=k0($.topics);for(let z of Q??[])x0(z,q,"topic");return{search:$.query,entities:k0($.entities),topics:Q,limit:$.limit,page:$.page}}y(B.command("ohlcv").argument("<entity>").description("Historical OHLCV candles")).option("--timeframe <value>","1h, 1d, 1w, 1mo, 1y","1d").option("--to <timestamp>","end timestamp").option("--limit <n>","max rows").action(async($,q)=>{return x0(q.timeframe,["1h","1d","1w","1mo","1y"],"timeframe"),I(await(await R()).ohlcv($,q),q,["timestamp","time","date","open","high","low","close","volume"])});y(B.command("quote").argument("<entity>").description("Latest daily quote snapshot")).option("--to <timestamp>","end timestamp").option("--limit <n>","max rows","1").action(async($,q)=>I(await(await R()).historicalQuote($,{to:q.to,limit:q.limit}),q,["timestamp","total_volume","deal_volume","total_value","buy_foreign_quantity","sell_foreign_quantity","current_foreign_room"]));y(B.command("officers").argument("<entity>").description("Company officers/directors")).action(async($,q)=>I(await(await R()).offices($),q,["name","position","is_foreigner","sort_order"]));y(B.command("subsidiary").argument("<entity>").description("Company subsidiaries")).action(async($,q)=>I(await(await R()).subsidiaries($),q,["name","symbol","ownership_rate","charter_capital","business_area","id"]));y(B.command("holder").argument("<entity>").description("Major shareholders")).option("--is-organization <true|false>","filter organization holders").option("--is-foreigner <true|false>","filter foreign holders").action(async($,q)=>I(await(await R()).holders($,{is_organization:q.isOrganization,is_foreigner:q.isForeigner}),q,["name","holder_name","ownership_rate","shares","is_organization","is_foreigner"]));y(B.command("holder-tx").argument("<entity>").description("Shareholder transactions")).option("--cursor <cursor>","pagination cursor").option("--limit <n>","max rows","100").option("--transaction-type <type>","transaction type filter").action(async($,q)=>I(await(await R()).holderTransactions($,{cursor:q.cursor,limit:q.limit,transaction_type:q.transactionType}),q,["name","type","registered_volume","execution_volume","start_at","end_at","position"]));y(B.command("financials").argument("<entity>").description("Financial statements")).option("--year <year>","report year").option("--quarter <quarter>","report quarter").option("--statement-type <type>","statement type filter").action(async($,q)=>I(r1(await(await R()).financialStatements($,{year:q.year,quarter:q.quarter,statement_type:q.statementType})),q,["year","quarter","type","net_sales","gross_profit","profit_after_tax","total_assets","owner_equity","net_operating_cash_flow"]));y(B.command("stats").argument("<entity>").description("Financial statistics/ratios")).option("--year <year>","report year").option("--quarter <quarter>","report quarter").action(async($,q)=>I(await(await R()).financialStatistics($,{year:q.year,quarter:q.quarter}),q,["year","quarter","pe","pb","roe","roa","gross_margin","market_cap"]));y(B.command("ta").argument("<tickerOrEntityId>").description("Technical indicators over OHLCV close prices")).option("--sma <list>","comma-separated SMA periods","20").option("--rsi <n>","RSI period").option("--macd","include MACD").option("--limit <n>","max candles","300").action(async($,q)=>{let Q=await(await R()).ohlcv($,{timeframe:"1d",limit:q.limit}),J=[...P(Q)].reverse(),M=n(J),X=String(q.sma).split(",").map(Number).filter(Number.isFinite),Y=Object.fromEntries(X.map((G)=>[G,y0(M,G)])),Z=q.rsi?I0(M,Number(q.rsi)):[],_=q.macd?P0(M):[],U=J.map((G,L)=>({...G,...Object.fromEntries(X.map((W)=>[`sma_${W}`,Y[W][L]])),...q.rsi?{[`rsi_${q.rsi}`]:Z[L]}:{},...q.macd?_[L]:{}})).reverse();await I(U,q,["timestamp","time","date","close",...X.map((G)=>`sma_${G}`),...q.rsi?[`rsi_${q.rsi}`]:[],...q.macd?["macd","signal","histogram"]:[]])});B.command("risk").argument("<tickerOrEntityId>").description("Risk/performance metrics: return, volatility, Sharpe, max drawdown").option("--limit <n>","max candles","252").option("--risk-free <n>","annual risk-free rate","0").action(async($,q)=>{let Q=await(await R()).ohlcv($,{timeframe:"1d",limit:q.limit});await Q0([j0(n([...P(Q)].reverse()),Number(q.riskFree))],{},["count","annualReturn","volatility","sharpe","maxDrawdown"])});B.command("doc").argument("<query...>").description("Query analysis reports using natural language").action(async($)=>{let q=await(await R()).queryReport($.join(" "));console.log(b0(q))});B.command("ask").argument("<prompt...>").description("Ask Mozyfin agent in auto mode, no workspace needed").option("--timeout <seconds>","max wait time","300").action(async($,q)=>{let Q=await R(),z=await Q.createChat(),J=z?.data?.id??z?.id;if(!J)throw Error("Could not create chat");let X=await Q.sendMessage(J,$.join(" ")),Y=X?.data?.id??X?.id,Z=Date.now()+Number(q.timeout)*1000;while(Y&&Date.now()<Z){let _=X?.data?.status??X?.status;if(_&&_!=="thinking"&&_!=="streaming")break;await new Promise((U)=>setTimeout(U,2000)),X=await Q.getMessage(Y)}console.log(f0(X))});B.command("credits").description("Check subscription usage/credits").action(async()=>Q0(await(await R()).usage(),{},["credits_used","credits_cap","remaining","plan"]));B.command("doctor").description("Check runtime, config and API health").action(async()=>{let $=C0("bun",["--version"],{encoding:"utf8"}).stdout.trim(),q=await R(),Q=await q.request("/health",{auth:!1});await f([{bun:$,configPath:D,baseUrl:q.baseUrl,health:Q}],{})});B.command("update").description("Upgrade CLI to latest version; auto-updates skills for any agents that already have it installed").option("--skill [agent]","Force update skill for specific agent (claude, cursor, copilot, windsurf, codex, gemini, hermes, openclaw, or 'all')").action(async($)=>{let q=B.version(),Q=await fetch("https://registry.npmjs.org/mozyfin-cli/latest").then((X)=>X.json()).then((X)=>X.version).catch(()=>null);if(console.log(`Current version: ${q}`),Q)if(console.log(`Latest version: ${Q}`),q===Q)console.log(`
|
|
57
|
+
You're already on the latest version!`);else if(console.log(`
|
|
58
|
+
Updating CLI...`),C0("npm",["install","-g","mozyfin-cli@latest"],{encoding:"utf8",stdio:"inherit"}).status===0)console.log(`
|
|
59
|
+
\u2713 CLI updated successfully!`);else console.log(`
|
|
60
|
+
\u2717 CLI update failed. Try running manually:`),console.log(" npm install -g mozyfin-cli@latest");let z=K(q0,"..","agent-skills","mozyfin-cli"),J="mozyfin-cli",M=[];if($.skill){let X=$.skill===!0?"all":$.skill;M=X==="all"?Object.keys(b):[X]}else for(let[X,Y]of Object.entries(b)){let Z=!1;if(Y.format==="directory")Z=T(K(Y.path,J,"SKILL.md"));else if(Y.format==="file")Z=T(K(Y.path,`${J}.md`));else if(Y.format==="append"){if(T(Y.path))Z=h(Y.path,"utf8").includes(`<!-- ${J} -->`)}if(Z)M.push(X)}if(M.length===0)return;if(!T(z)){console.log(`
|
|
61
|
+
\u2717 Skill source not found in package`);return}console.log(`
|
|
62
|
+
Updating skills for: ${M.join(", ")}`);for(let X of M){let Y=b[X];if(!Y){console.log(`\u2717 Unknown agent: ${X}`);continue}let{path:Z,format:_}=Y;try{if(_==="append"){A($0(Z),{recursive:!0});let U=h(K(z,"SKILL.md"),"utf8"),W=`${(T(Z)?h(Z,"utf8"):"").replace(new RegExp(`<!-- ${J} -->[\\s\\S]*<!-- /${J} -->`,"g"),"").trim()}
|
|
63
|
+
|
|
64
|
+
<!-- ${J} -->
|
|
65
|
+
${U}
|
|
66
|
+
<!-- /${J} -->
|
|
67
|
+
`;E("fs").writeFileSync(Z,W),console.log(`\u2713 Updated skill for ${X}`)}else if(_==="file"){A(Z,{recursive:!0});let U=K(Z,`${J}.md`);u(K(z,"SKILL.md"),U),console.log(`\u2713 Updated skill for ${X}`)}else if(_==="directory"){let U=K(Z,J);v(U,{recursive:!0,force:!0}),A(Z,{recursive:!0}),u(z,U,{recursive:!0}),console.log(`\u2713 Updated skill for ${X}`)}}catch(U){console.log(`\u2717 Failed to update skill for ${X}: ${U}`)}}});var b={claude:{path:K(F(),".claude","skills"),format:"directory"},cursor:{path:K(F(),".cursor","commands"),format:"file"},copilot:{path:K(F(),".github","copilot-instructions.md"),format:"append"},windsurf:{path:K(F(),".windsurf","workflows"),format:"file"},codex:{path:K(F(),".agents","skills"),format:"directory"},gemini:{path:K(F(),".gemini","instructions"),format:"file"},hermes:{path:K(F(),".hermes","skills"),format:"directory"},openclaw:{path:K(F(),".openclaw","skills"),format:"directory"},antigravity:{path:K(F(),".gemini","antigravity","skills"),format:"directory"}};B.command("skill").description("Install mozyfin-cli skill into AI agents (claude, cursor, copilot, windsurf, codex, gemini, hermes, openclaw, antigravity)").argument("[agent]","Target agent (claude, cursor, copilot, windsurf, codex, gemini, hermes, openclaw, antigravity) or 'all'").option("--list","List available agents").option("--remove","Remove skill from agent").action(($,q)=>{let Q=K(q0,"..","agent-skills","mozyfin-cli"),z="mozyfin-cli";if(q.list){console.log(`Available agents:
|
|
68
|
+
`);for(let[M,X]of Object.entries(b)){let Y=!1;if(X.format==="directory")Y=T(K(X.path,"mozyfin-cli","SKILL.md"));else if(X.format==="file")Y=T(K(X.path,"mozyfin-cli.md"));else if(X.format==="append"){if(T(X.path))Y=E("fs").readFileSync(X.path,"utf8").includes("<!-- mozyfin-cli -->")}console.log(` ${M.padEnd(10)} ${Y?"\u2713 installed":"\u25CB not installed"}`),console.log(` ${X.path}`)}return}if(!$){console.log("Usage: mozyfin skill <agent>"),console.log(`
|
|
69
|
+
Available agents: claude, cursor, copilot, windsurf, codex, gemini, hermes, openclaw, all`),console.log(`
|
|
70
|
+
Options:`),console.log(" --list List available agents"),console.log(" --remove Remove skill from agent");return}let J=$==="all"?Object.keys(b):[$];for(let M of J){let X=b[M];if(!X){console.log(`Unknown agent: ${M}`),console.log("Available: claude, cursor, copilot, windsurf, codex, gemini, hermes, openclaw");continue}let{path:Y,format:Z}=X;if(q.remove){if(Z==="append")if(T(Y)){let U=E("fs").readFileSync(Y,"utf8").replace(new RegExp("<!-- mozyfin-cli -->[\\s\\S]*<!-- /mozyfin-cli -->","g"),"").trim();E("fs").writeFileSync(Y,U),console.log(`\u2713 Removed skill from ${M}`)}else console.log(`Skill not installed in ${M}`);else if(Z==="file"){let _=K(Y,"mozyfin-cli.md");if(T(_))v(_),console.log(`\u2713 Removed skill from ${M}`);else console.log(`Skill not installed in ${M}`)}else if(Z==="directory"){let _=K(Y,"mozyfin-cli");if(T(_))v(_,{recursive:!0,force:!0}),console.log(`\u2713 Removed skill from ${M}`);else console.log(`Skill not installed in ${M}`)}continue}if(!T(Q)){console.log(`Skill directory not found: ${Q}`);continue}if(Z==="append"){A($0(Y),{recursive:!0});let _=E("fs").readFileSync(K(Q,"SKILL.md"),"utf8"),L=`${(T(Y)?E("fs").readFileSync(Y,"utf8"):"").replace(new RegExp("<!-- mozyfin-cli -->[\\s\\S]*<!-- /mozyfin-cli -->","g"),"").trim()}
|
|
71
|
+
|
|
72
|
+
<!-- mozyfin-cli -->
|
|
73
|
+
${_}
|
|
74
|
+
<!-- /mozyfin-cli -->
|
|
75
|
+
`;E("fs").writeFileSync(Y,L),console.log(`\u2713 Installed skill to ${M}`)}else if(Z==="file"){A(Y,{recursive:!0});let _=K(Y,"mozyfin-cli.md");u(K(Q,"SKILL.md"),_),console.log(`\u2713 Installed skill to ${M}`)}else if(Z==="directory"){let _=K(Y,"mozyfin-cli");v(_,{recursive:!0,force:!0}),A(Y,{recursive:!0}),u(Q,_,{recursive:!0}),console.log(`\u2713 Installed skill to ${M}`)}}});B.parseAsync().catch(($)=>{console.error(`Error: ${$.message}`),process.exit(1)});
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mozyfin-cli",
|
|
3
|
+
"version": "0.2.6",
|
|
4
|
+
"description": "Human- and agent-friendly CLI for Vietnamese market data via Mozyfin/Antofin APIs.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mozyfin": "./dist/index.js",
|
|
8
|
+
"mozyfin-cli": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": ["dist", "agent-skills", "package.json", "README.md"],
|
|
11
|
+
"keywords": ["mozyfin", "antofin", "vietnam", "stocks", "market-data", "cli"],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"dev": "bun run src/index.ts",
|
|
14
|
+
"build": "bun build ./src/index.ts --target bun --minify --outfile dist/index.js && chmod +x dist/index.js",
|
|
15
|
+
"test": "bun test",
|
|
16
|
+
"lint": "biome check .",
|
|
17
|
+
"format": "biome format --write .",
|
|
18
|
+
"check": "biome check --write .",
|
|
19
|
+
"prepublishOnly": "bun run build && bun test"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"commander": "^12.1.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@biomejs/biome": "^1.9.4",
|
|
26
|
+
"@types/bun": "latest",
|
|
27
|
+
"typescript": "^5.7.2"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"bun": ">=1.1.0"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/onlyai-team/mozyfin-cli.git"
|
|
35
|
+
},
|
|
36
|
+
"author": "Mozyfin",
|
|
37
|
+
"license": "UNLICENSED",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/onlyai-team/mozyfin-cli/issues"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/onlyai-team/mozyfin-cli#readme"
|
|
42
|
+
}
|