@drico2008/fincli 0.1.9 → 0.2.2
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 +909 -718
- package/fincli/__init__.py +3 -3
- package/fincli/app/agents/__init__.py +5 -0
- package/fincli/app/agents/registry.py +76 -0
- package/fincli/app/analysis/ai_prompts.py +23 -16
- package/fincli/app/analysis/analyzer.py +107 -100
- package/fincli/app/analysis/assistant_context.py +187 -186
- package/fincli/app/analysis/backtest.py +179 -0
- package/fincli/app/analysis/gameplay_plan.py +79 -0
- package/fincli/app/analysis/multi_timeframe.py +180 -0
- package/fincli/app/analysis/trading_methods.py +144 -0
- package/fincli/app/cli/commands.py +105 -83
- package/fincli/app/cli/router.py +2123 -1294
- package/fincli/app/connectors/__init__.py +5 -0
- package/fincli/app/connectors/catalog.py +148 -0
- package/fincli/app/connectors/news_connectors.py +412 -0
- package/fincli/app/modules/alerts.py +80 -0
- package/fincli/app/modules/economic_calendar.py +374 -1
- package/fincli/app/modules/reports.py +151 -0
- package/fincli/app/modules/scanner.py +111 -93
- package/fincli/app/modules/transactions.py +84 -84
- package/fincli/app/modules/user_profile.py +84 -0
- package/fincli/app/plugins/loader.py +72 -0
- package/fincli/app/providers/ai/manager.py +60 -60
- package/fincli/app/providers/market/alphavantage_provider.py +194 -0
- package/fincli/app/providers/market/base.py +98 -77
- package/fincli/app/providers/market/custom_provider.py +186 -169
- package/fincli/app/providers/market/manager.py +84 -1
- package/fincli/app/providers/market/symbols.py +143 -0
- package/fincli/app/providers/market/twelvedata_provider.py +167 -167
- package/fincli/app/research/__init__.py +7 -0
- package/fincli/app/research/engine.py +75 -0
- package/fincli/app/research/formatter.py +22 -0
- package/fincli/app/research/models.py +18 -0
- package/fincli/app/research/prompt_builder.py +47 -0
- package/fincli/app/services/macro_data.py +50 -0
- package/fincli/app/services/market_data.py +203 -203
- package/fincli/app/services/news_aggregator.py +90 -0
- package/fincli/app/services/web_research.py +267 -267
- package/fincli/app/storage/config.py +122 -88
- package/fincli/app/storage/database.py +200 -101
- package/fincli/app/storage/secrets.py +8 -2
- package/fincli/app/tui/components.py +68 -50
- package/fincli/app/tui/layout.py +269 -258
- package/fincli/app/tui/market_provider_selector.py +3 -1
- package/fincli/app/tui/theme.py +134 -74
- package/fincli/app/utils/formatting.py +123 -60
- package/package.json +23 -23
- package/pyproject.toml +35 -35
|
@@ -39,14 +39,16 @@ PROVIDER_LABELS = {
|
|
|
39
39
|
"custom": "Custom API",
|
|
40
40
|
"finnhub": "Finnhub",
|
|
41
41
|
"twelvedata": "Twelve Data",
|
|
42
|
+
"alphavantage": "Alpha Vantage",
|
|
42
43
|
}
|
|
43
44
|
PROVIDER_ENV_KEYS = {
|
|
44
45
|
"yfinance": (),
|
|
45
46
|
"custom": ("MARKET_DATA_API_KEY", "MARKET_DATA_BASE_URL"),
|
|
46
47
|
"finnhub": ("FINNHUB_API_KEY",),
|
|
47
48
|
"twelvedata": ("TWELVE_DATA_API_KEY",),
|
|
49
|
+
"alphavantage": ("ALPHA_VANTAGE_API_KEY",),
|
|
48
50
|
}
|
|
49
|
-
DEFAULT_FALLBACK_ORDER = ("twelvedata", "finnhub", "custom", "yfinance")
|
|
51
|
+
DEFAULT_FALLBACK_ORDER = ("twelvedata", "finnhub", "alphavantage", "custom", "yfinance")
|
|
50
52
|
|
|
51
53
|
|
|
52
54
|
def market_provider_choices() -> tuple[MarketProviderChoice, ...]:
|
package/fincli/app/tui/theme.py
CHANGED
|
@@ -1,157 +1,217 @@
|
|
|
1
|
-
"""Theme constants for the Textual UI."""
|
|
2
|
-
|
|
3
|
-
APP_CSS = """
|
|
1
|
+
"""Theme constants for the Textual UI."""
|
|
2
|
+
|
|
3
|
+
APP_CSS = """
|
|
4
4
|
Screen {
|
|
5
|
-
background: #
|
|
6
|
-
color: #
|
|
5
|
+
background: #00110b;
|
|
6
|
+
color: #d9f99d;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
Header {
|
|
10
|
-
background: #
|
|
11
|
-
color: #
|
|
10
|
+
background: #000805;
|
|
11
|
+
color: #22c55e;
|
|
12
12
|
text-style: bold;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
#workspace {
|
|
14
|
+
|
|
15
|
+
#workspace {
|
|
16
|
+
height: 1fr;
|
|
17
|
+
width: 100%;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#main {
|
|
21
|
+
width: 1fr;
|
|
16
22
|
height: 1fr;
|
|
17
|
-
|
|
23
|
+
padding: 1 4 0 4;
|
|
24
|
+
background: #00110b;
|
|
18
25
|
}
|
|
19
26
|
|
|
20
|
-
#
|
|
21
|
-
|
|
27
|
+
#top_strip {
|
|
28
|
+
height: 3;
|
|
29
|
+
content-align: center middle;
|
|
30
|
+
background: #031b10;
|
|
31
|
+
color: #86efac;
|
|
32
|
+
border: heavy #15803d;
|
|
33
|
+
text-style: bold;
|
|
34
|
+
margin: 0 0 1 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#market_ribbon {
|
|
38
|
+
height: 1;
|
|
39
|
+
content-align: center middle;
|
|
40
|
+
background: #020d08;
|
|
41
|
+
color: #22c55e;
|
|
42
|
+
text-style: bold;
|
|
43
|
+
margin: 0 0 1 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#output_header {
|
|
47
|
+
height: 1;
|
|
48
|
+
background: #052e16;
|
|
49
|
+
color: #bbf7d0;
|
|
50
|
+
text-style: bold;
|
|
51
|
+
padding: 0 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#output_frame {
|
|
22
55
|
height: 1fr;
|
|
23
|
-
|
|
24
|
-
|
|
56
|
+
background: #000805;
|
|
57
|
+
border: heavy #166534;
|
|
58
|
+
padding: 1 2;
|
|
25
59
|
}
|
|
26
60
|
|
|
27
61
|
#output {
|
|
28
|
-
background: #
|
|
62
|
+
background: #000805;
|
|
29
63
|
color: #e5e7eb;
|
|
30
64
|
border: none;
|
|
65
|
+
scrollbar-size: 1 1;
|
|
66
|
+
scrollbar-background: #000805;
|
|
67
|
+
scrollbar-color: #22c55e;
|
|
31
68
|
}
|
|
32
69
|
|
|
33
70
|
#command_area {
|
|
34
71
|
dock: bottom;
|
|
35
72
|
height: auto;
|
|
36
|
-
background: #
|
|
37
|
-
padding: 0
|
|
73
|
+
background: #00110b;
|
|
74
|
+
padding: 0 4 1 4;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
#command_hint {
|
|
78
|
+
height: 1;
|
|
79
|
+
background: #020d08;
|
|
80
|
+
color: #84cc16;
|
|
81
|
+
padding: 0 1;
|
|
38
82
|
}
|
|
39
83
|
|
|
40
84
|
#command_line {
|
|
41
85
|
height: 3;
|
|
42
86
|
margin: 0 0 1 0;
|
|
43
|
-
border:
|
|
44
|
-
background: #
|
|
87
|
+
border: heavy #15803d;
|
|
88
|
+
background: #031b10;
|
|
45
89
|
color: #f8fafc;
|
|
46
90
|
}
|
|
47
91
|
|
|
48
92
|
#command_prompt {
|
|
49
|
-
width:
|
|
50
|
-
height:
|
|
51
|
-
background: #
|
|
52
|
-
color: #
|
|
93
|
+
width: 4;
|
|
94
|
+
height: 1;
|
|
95
|
+
background: #031b10;
|
|
96
|
+
color: #22c55e;
|
|
53
97
|
text-style: bold;
|
|
54
|
-
padding: 0 0 0
|
|
98
|
+
padding: 0 0 0 1;
|
|
55
99
|
}
|
|
56
100
|
|
|
57
101
|
#command_input {
|
|
58
102
|
width: 1fr;
|
|
59
|
-
height:
|
|
103
|
+
height: 1;
|
|
60
104
|
border: none;
|
|
61
|
-
background: #
|
|
105
|
+
background: #031b10;
|
|
62
106
|
color: #f8fafc;
|
|
63
|
-
padding: 0
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
#command_input:focus {
|
|
67
|
-
border: none;
|
|
107
|
+
padding: 0 1 0 0;
|
|
68
108
|
}
|
|
69
|
-
|
|
109
|
+
|
|
110
|
+
#command_input:focus {
|
|
111
|
+
border: none;
|
|
112
|
+
}
|
|
113
|
+
|
|
70
114
|
#command_palette_scroll {
|
|
71
115
|
height: 9;
|
|
72
116
|
margin: 0 0 0 0;
|
|
73
|
-
background: #
|
|
117
|
+
background: #00110b;
|
|
74
118
|
color: #f8fafc;
|
|
75
119
|
scrollbar-size: 1 1;
|
|
76
|
-
scrollbar-background: #
|
|
77
|
-
scrollbar-color: #
|
|
120
|
+
scrollbar-background: #00110b;
|
|
121
|
+
scrollbar-color: #22c55e;
|
|
78
122
|
}
|
|
79
|
-
|
|
80
|
-
#command_palette {
|
|
123
|
+
|
|
124
|
+
#command_palette {
|
|
81
125
|
height: auto;
|
|
82
126
|
margin: 0 0 0 0;
|
|
83
|
-
background: #
|
|
127
|
+
background: #00110b;
|
|
84
128
|
color: #f8fafc;
|
|
85
129
|
}
|
|
86
130
|
|
|
87
131
|
#status_bar {
|
|
88
132
|
dock: bottom;
|
|
89
133
|
height: 1;
|
|
90
|
-
background: #
|
|
91
|
-
color: #
|
|
92
|
-
padding: 0
|
|
134
|
+
background: #000805;
|
|
135
|
+
color: #86efac;
|
|
136
|
+
padding: 0 4;
|
|
93
137
|
}
|
|
94
138
|
|
|
95
139
|
.section-title {
|
|
96
|
-
color: #
|
|
140
|
+
color: #86efac;
|
|
97
141
|
text-style: bold;
|
|
98
142
|
}
|
|
99
143
|
|
|
100
144
|
.muted {
|
|
101
|
-
color: #
|
|
145
|
+
color: #64748b;
|
|
102
146
|
}
|
|
103
147
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
background: #252525;
|
|
108
|
-
color: #f8fafc;
|
|
109
|
-
padding: 1;
|
|
148
|
+
.semantic-positive {
|
|
149
|
+
color: #22c55e;
|
|
150
|
+
text-style: bold;
|
|
110
151
|
}
|
|
111
152
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
color: #f8fafc;
|
|
153
|
+
.semantic-negative {
|
|
154
|
+
color: #ef4444;
|
|
115
155
|
text-style: bold;
|
|
116
156
|
}
|
|
117
157
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
padding: 0 2;
|
|
158
|
+
.semantic-caution {
|
|
159
|
+
color: #facc15;
|
|
160
|
+
text-style: bold;
|
|
122
161
|
}
|
|
123
|
-
|
|
162
|
+
|
|
163
|
+
#ai_selector_card {
|
|
164
|
+
width: 78;
|
|
165
|
+
height: 30;
|
|
166
|
+
background: #031b10;
|
|
167
|
+
color: #f8fafc;
|
|
168
|
+
padding: 1;
|
|
169
|
+
border: heavy #15803d;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
#ai_selector_title {
|
|
173
|
+
height: 2;
|
|
174
|
+
color: #f8fafc;
|
|
175
|
+
text-style: bold;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
#ai_selector_provider {
|
|
179
|
+
height: 2;
|
|
180
|
+
color: #f8fafc;
|
|
181
|
+
padding: 0 2;
|
|
182
|
+
}
|
|
183
|
+
|
|
124
184
|
#ai_selector_search {
|
|
125
185
|
height: 3;
|
|
126
186
|
margin: 0 1 1 1;
|
|
127
|
-
border: solid #
|
|
128
|
-
background: #
|
|
187
|
+
border: solid #22c55e;
|
|
188
|
+
background: #020d08;
|
|
129
189
|
color: #f8fafc;
|
|
130
190
|
padding: 0 1;
|
|
131
191
|
}
|
|
132
|
-
|
|
192
|
+
|
|
133
193
|
#ai_selector_search:focus {
|
|
134
|
-
border: solid #
|
|
194
|
+
border: solid #86efac;
|
|
135
195
|
}
|
|
136
|
-
|
|
137
|
-
#ai_selector_scroll {
|
|
196
|
+
|
|
197
|
+
#ai_selector_scroll {
|
|
138
198
|
height: 1fr;
|
|
139
199
|
margin: 0 1;
|
|
140
|
-
background: #
|
|
200
|
+
background: #031b10;
|
|
141
201
|
scrollbar-size: 1 1;
|
|
142
|
-
scrollbar-background: #
|
|
143
|
-
scrollbar-color: #
|
|
202
|
+
scrollbar-background: #031b10;
|
|
203
|
+
scrollbar-color: #22c55e;
|
|
144
204
|
}
|
|
145
205
|
|
|
146
206
|
#ai_selector_list {
|
|
147
207
|
height: auto;
|
|
148
|
-
background: #
|
|
208
|
+
background: #031b10;
|
|
149
209
|
color: #f8fafc;
|
|
150
210
|
}
|
|
151
|
-
|
|
152
|
-
#ai_selector_help {
|
|
153
|
-
height: 3;
|
|
154
|
-
color: #9ca3af;
|
|
155
|
-
padding: 1 0 0 0;
|
|
156
|
-
}
|
|
157
|
-
"""
|
|
211
|
+
|
|
212
|
+
#ai_selector_help {
|
|
213
|
+
height: 3;
|
|
214
|
+
color: #9ca3af;
|
|
215
|
+
padding: 1 0 0 0;
|
|
216
|
+
}
|
|
217
|
+
"""
|
|
@@ -1,67 +1,130 @@
|
|
|
1
|
-
"""Small formatting helpers."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from rich.console import Console, ConsoleOptions, RenderResult
|
|
6
|
-
from rich.markdown import Markdown
|
|
7
|
-
from rich.text import Text
|
|
8
|
-
|
|
9
|
-
from fincli.app.providers.ai.base import AIResponse
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def mask_secret(value: str | None) -> str:
|
|
13
|
-
"""Mask API keys and tokens before displaying them."""
|
|
14
|
-
if not value:
|
|
15
|
-
return "not set"
|
|
16
|
-
if len(value) <= 8:
|
|
17
|
-
return "set"
|
|
18
|
-
return f"{value[:4]}...{value[-4:]}"
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
"""Small formatting helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from rich.console import Console, ConsoleOptions, RenderResult
|
|
6
|
+
from rich.markdown import Markdown
|
|
7
|
+
from rich.text import Text
|
|
8
|
+
|
|
9
|
+
from fincli.app.providers.ai.base import AIResponse
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def mask_secret(value: str | None) -> str:
|
|
13
|
+
"""Mask API keys and tokens before displaying them."""
|
|
14
|
+
if not value:
|
|
15
|
+
return "not set"
|
|
16
|
+
if len(value) <= 8:
|
|
17
|
+
return "set"
|
|
18
|
+
return f"{value[:4]}...{value[-4:]}"
|
|
19
|
+
|
|
20
|
+
|
|
21
21
|
def normalize_symbol(symbol: str) -> str:
|
|
22
22
|
"""Normalize user-entered market symbols."""
|
|
23
23
|
return symbol.strip().upper()
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
""
|
|
26
|
+
POSITIVE_TERMS = (
|
|
27
|
+
"bullish",
|
|
28
|
+
"best to buy",
|
|
29
|
+
"buy",
|
|
30
|
+
"breakout",
|
|
31
|
+
"positive",
|
|
32
|
+
"gain",
|
|
33
|
+
"upside",
|
|
34
|
+
"higher",
|
|
35
|
+
"profit",
|
|
36
|
+
"win",
|
|
37
|
+
"triggered above",
|
|
38
|
+
"confirmed",
|
|
39
|
+
)
|
|
40
|
+
NEGATIVE_TERMS = (
|
|
41
|
+
"bearish",
|
|
42
|
+
"best to sell",
|
|
43
|
+
"sell",
|
|
44
|
+
"breakdown",
|
|
45
|
+
"negative",
|
|
46
|
+
"loss",
|
|
47
|
+
"drawdown",
|
|
48
|
+
"downside",
|
|
49
|
+
"lower",
|
|
50
|
+
"decline",
|
|
51
|
+
"drop",
|
|
52
|
+
"failed",
|
|
53
|
+
"unavailable",
|
|
54
|
+
)
|
|
55
|
+
CAUTION_TERMS = (
|
|
56
|
+
"caution",
|
|
57
|
+
"hold",
|
|
58
|
+
"wait",
|
|
59
|
+
"neutral",
|
|
60
|
+
"sideways",
|
|
61
|
+
"mixed",
|
|
62
|
+
"risk",
|
|
63
|
+
"warning",
|
|
64
|
+
"delayed",
|
|
65
|
+
"fallback",
|
|
66
|
+
"not confirmed",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def semantic_style(value: object) -> str:
|
|
71
|
+
"""Map financial meaning to a consistent terminal style."""
|
|
72
|
+
text = str(value).strip().lower()
|
|
73
|
+
if not text:
|
|
74
|
+
return "white"
|
|
75
|
+
if any(term in text for term in CAUTION_TERMS):
|
|
76
|
+
return "bold yellow"
|
|
77
|
+
if any(term in text for term in NEGATIVE_TERMS):
|
|
78
|
+
return "bold red"
|
|
79
|
+
if any(term in text for term in POSITIVE_TERMS):
|
|
80
|
+
return "bold green"
|
|
81
|
+
return "white"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def semantic_text(value: object) -> Text:
|
|
85
|
+
"""Return Rich Text styled by financial semantics."""
|
|
86
|
+
return Text(str(value), style=semantic_style(value))
|
|
28
87
|
|
|
29
|
-
def __init__(self, response: AIResponse) -> None:
|
|
30
|
-
self.response = response
|
|
31
88
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
89
|
+
class AIResponseView:
|
|
90
|
+
"""Renderable AI response that preserves Markdown formatting in Rich/Textual."""
|
|
91
|
+
|
|
92
|
+
def __init__(self, response: AIResponse) -> None:
|
|
93
|
+
self.response = response
|
|
94
|
+
|
|
95
|
+
def __str__(self) -> str:
|
|
96
|
+
return (
|
|
97
|
+
f"Provider: {self.response.provider}\n"
|
|
98
|
+
f"Model: {self.response.model}\n"
|
|
99
|
+
f"Response:\n{self.response.content}"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
|
|
103
|
+
header = Text()
|
|
104
|
+
header.append("Provider: ", style="bold cyan")
|
|
105
|
+
header.append(self.response.provider, style="white")
|
|
106
|
+
header.append(" Model: ", style="bold cyan")
|
|
107
|
+
header.append(self.response.model, style="white")
|
|
108
|
+
yield header
|
|
109
|
+
yield Markdown(self.response.content)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class MarkdownBlock:
|
|
113
|
+
"""Small renderable block for titled Markdown content."""
|
|
114
|
+
|
|
115
|
+
def __init__(self, title: str, body: object, footer: str | None = None) -> None:
|
|
116
|
+
self.title = title
|
|
117
|
+
self.body = body
|
|
118
|
+
self.footer = footer
|
|
119
|
+
|
|
120
|
+
def __str__(self) -> str:
|
|
121
|
+
parts = [self.title, str(self.body)]
|
|
122
|
+
if self.footer:
|
|
123
|
+
parts.append(self.footer)
|
|
124
|
+
return "\n".join(parts)
|
|
125
|
+
|
|
126
|
+
def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
|
|
127
|
+
yield Text(self.title, style="bold cyan")
|
|
128
|
+
yield self.body
|
|
129
|
+
if self.footer:
|
|
130
|
+
yield Text(self.footer, style="dim")
|
package/package.json
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@drico2008/fincli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Modern financial CLI/TUI terminal for market monitoring and analysis.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"bin": {
|
|
7
|
-
"fincli": "npm/bin/fincli.js"
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"postinstall": "node npm/postinstall.js",
|
|
11
|
-
"check": "node --check npm/bin/fincli.js && node --check npm/postinstall.js"
|
|
12
|
-
},
|
|
13
|
-
"files": [
|
|
14
|
-
"fincli/**/*.py",
|
|
15
|
-
"npm",
|
|
16
|
-
"pyproject.toml",
|
|
17
|
-
"README.md",
|
|
18
|
-
"requirements.txt"
|
|
19
|
-
],
|
|
20
|
-
"engines": {
|
|
21
|
-
"node": ">=18"
|
|
22
|
-
}
|
|
23
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@drico2008/fincli",
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "Modern financial CLI/TUI terminal for market monitoring and analysis.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"bin": {
|
|
7
|
+
"fincli": "npm/bin/fincli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"postinstall": "node npm/postinstall.js",
|
|
11
|
+
"check": "node --check npm/bin/fincli.js && node --check npm/postinstall.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"fincli/**/*.py",
|
|
15
|
+
"npm",
|
|
16
|
+
"pyproject.toml",
|
|
17
|
+
"README.md",
|
|
18
|
+
"requirements.txt"
|
|
19
|
+
],
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/pyproject.toml
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=68", "wheel"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "fincli"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "Modern financial CLI/TUI terminal for market monitoring and analysis."
|
|
9
|
-
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.11"
|
|
11
|
-
dependencies = [
|
|
12
|
-
"textual>=0.86.0",
|
|
13
|
-
"rich>=13.9.0",
|
|
14
|
-
"python-dotenv>=1.0.1",
|
|
15
|
-
"httpx>=0.27.2",
|
|
16
|
-
"pydantic>=2.9.2",
|
|
17
|
-
"yfinance>=0.2.50",
|
|
18
|
-
"pandas>=2.2.3",
|
|
19
|
-
"numpy>=2.1.0",
|
|
20
|
-
]
|
|
21
|
-
|
|
22
|
-
[project.optional-dependencies]
|
|
23
|
-
dev = ["pytest>=8.3.3"]
|
|
24
|
-
market = ["yfinance>=0.2.50", "pandas>=2.2.3", "numpy>=2.1.0"]
|
|
25
|
-
|
|
26
|
-
[project.scripts]
|
|
27
|
-
fincli = "fincli.app.main:main"
|
|
28
|
-
|
|
29
|
-
[tool.setuptools.packages.find]
|
|
30
|
-
include = ["fincli*"]
|
|
31
|
-
exclude = ["npm*", "tests*"]
|
|
32
|
-
|
|
33
|
-
[tool.pytest.ini_options]
|
|
34
|
-
testpaths = ["tests"]
|
|
35
|
-
pythonpath = ["."]
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "fincli"
|
|
7
|
+
version = "0.2.2"
|
|
8
|
+
description = "Modern financial CLI/TUI terminal for market monitoring and analysis."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"textual>=0.86.0",
|
|
13
|
+
"rich>=13.9.0",
|
|
14
|
+
"python-dotenv>=1.0.1",
|
|
15
|
+
"httpx>=0.27.2",
|
|
16
|
+
"pydantic>=2.9.2",
|
|
17
|
+
"yfinance>=0.2.50",
|
|
18
|
+
"pandas>=2.2.3",
|
|
19
|
+
"numpy>=2.1.0",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
dev = ["pytest>=8.3.3"]
|
|
24
|
+
market = ["yfinance>=0.2.50", "pandas>=2.2.3", "numpy>=2.1.0"]
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
fincli = "fincli.app.main:main"
|
|
28
|
+
|
|
29
|
+
[tool.setuptools.packages.find]
|
|
30
|
+
include = ["fincli*"]
|
|
31
|
+
exclude = ["npm*", "tests*"]
|
|
32
|
+
|
|
33
|
+
[tool.pytest.ini_options]
|
|
34
|
+
testpaths = ["tests"]
|
|
35
|
+
pythonpath = ["."]
|