opencandle 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -87
- package/dist/analysts/orchestrator.js +1 -2
- package/dist/analysts/orchestrator.js.map +1 -1
- package/dist/config.d.ts +25 -5
- package/dist/config.js +16 -8
- package/dist/config.js.map +1 -1
- package/dist/infra/cache.d.ts +4 -0
- package/dist/infra/cache.js +4 -0
- package/dist/infra/cache.js.map +1 -1
- package/dist/infra/rate-limiter.js +6 -0
- package/dist/infra/rate-limiter.js.map +1 -1
- package/dist/onboarding/connect.d.ts +23 -0
- package/dist/onboarding/connect.js +107 -0
- package/dist/onboarding/connect.js.map +1 -0
- package/dist/onboarding/credential-interceptor.d.ts +44 -0
- package/dist/onboarding/credential-interceptor.js +72 -0
- package/dist/onboarding/credential-interceptor.js.map +1 -0
- package/dist/onboarding/degradation-accumulator.d.ts +21 -0
- package/dist/onboarding/degradation-accumulator.js +55 -0
- package/dist/onboarding/degradation-accumulator.js.map +1 -0
- package/dist/onboarding/prompt-user.d.ts +23 -0
- package/dist/onboarding/prompt-user.js +61 -0
- package/dist/onboarding/prompt-user.js.map +1 -0
- package/dist/onboarding/providers.d.ts +109 -0
- package/dist/onboarding/providers.js +236 -0
- package/dist/onboarding/providers.js.map +1 -0
- package/dist/onboarding/state.d.ts +31 -2
- package/dist/onboarding/state.js +141 -13
- package/dist/onboarding/state.js.map +1 -1
- package/dist/onboarding/tool-helpers.d.ts +34 -0
- package/dist/onboarding/tool-helpers.js +80 -0
- package/dist/onboarding/tool-helpers.js.map +1 -0
- package/dist/onboarding/tool-tags.d.ts +37 -0
- package/dist/onboarding/tool-tags.js +149 -0
- package/dist/onboarding/tool-tags.js.map +1 -0
- package/dist/onboarding/validation.d.ts +19 -0
- package/dist/onboarding/validation.js +117 -0
- package/dist/onboarding/validation.js.map +1 -0
- package/dist/pi/opencandle-extension.js +303 -4
- package/dist/pi/opencandle-extension.js.map +1 -1
- package/dist/pi/setup.d.ts +0 -1
- package/dist/pi/setup.js +66 -119
- package/dist/pi/setup.js.map +1 -1
- package/dist/prompts/context-builder.js +2 -1
- package/dist/prompts/context-builder.js.map +1 -1
- package/dist/providers/alpha-vantage.js +20 -1
- package/dist/providers/alpha-vantage.js.map +1 -1
- package/dist/providers/exa-search.d.ts +39 -0
- package/dist/providers/exa-search.js +276 -0
- package/dist/providers/exa-search.js.map +1 -0
- package/dist/providers/finnhub.d.ts +17 -0
- package/dist/providers/finnhub.js +94 -0
- package/dist/providers/finnhub.js.map +1 -0
- package/dist/providers/fred.js +13 -1
- package/dist/providers/fred.js.map +1 -1
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.js +1 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/provider-credential-error.d.ts +8 -0
- package/dist/providers/provider-credential-error.js +22 -0
- package/dist/providers/provider-credential-error.js.map +1 -0
- package/dist/providers/reddit.d.ts +8 -0
- package/dist/providers/reddit.js +36 -9
- package/dist/providers/reddit.js.map +1 -1
- package/dist/providers/twitter.js +2 -8
- package/dist/providers/twitter.js.map +1 -1
- package/dist/providers/web-search.d.ts +17 -0
- package/dist/providers/web-search.js +224 -0
- package/dist/providers/web-search.js.map +1 -0
- package/dist/providers/wrap-provider.d.ts +7 -0
- package/dist/providers/wrap-provider.js +15 -0
- package/dist/providers/wrap-provider.js.map +1 -1
- package/dist/routing/classify-intent.js +22 -0
- package/dist/routing/classify-intent.js.map +1 -1
- package/dist/runtime/session-coordinator.d.ts +0 -1
- package/dist/runtime/session-coordinator.js.map +1 -1
- package/dist/sentiment/adapters/finnhub.d.ts +7 -0
- package/dist/sentiment/adapters/finnhub.js +39 -0
- package/dist/sentiment/adapters/finnhub.js.map +1 -0
- package/dist/sentiment/adapters/reddit.d.ts +11 -0
- package/dist/sentiment/adapters/reddit.js +54 -0
- package/dist/sentiment/adapters/reddit.js.map +1 -0
- package/dist/sentiment/adapters/twitter.d.ts +9 -0
- package/dist/sentiment/adapters/twitter.js +32 -0
- package/dist/sentiment/adapters/twitter.js.map +1 -0
- package/dist/sentiment/adapters/web.d.ts +9 -0
- package/dist/sentiment/adapters/web.js +40 -0
- package/dist/sentiment/adapters/web.js.map +1 -0
- package/dist/sentiment/index.d.ts +16 -0
- package/dist/sentiment/index.js +44 -0
- package/dist/sentiment/index.js.map +1 -0
- package/dist/sentiment/keywords.d.ts +2 -0
- package/dist/sentiment/keywords.js +9 -0
- package/dist/sentiment/keywords.js.map +1 -0
- package/dist/sentiment/pipeline.d.ts +9 -0
- package/dist/sentiment/pipeline.js +57 -0
- package/dist/sentiment/pipeline.js.map +1 -0
- package/dist/sentiment/scorer.d.ts +9 -0
- package/dist/sentiment/scorer.js +64 -0
- package/dist/sentiment/scorer.js.map +1 -0
- package/dist/sentiment/store.d.ts +24 -0
- package/dist/sentiment/store.js +177 -0
- package/dist/sentiment/store.js.map +1 -0
- package/dist/sentiment/trends.d.ts +13 -0
- package/dist/sentiment/trends.js +73 -0
- package/dist/sentiment/trends.js.map +1 -0
- package/dist/sentiment/types.d.ts +66 -0
- package/dist/sentiment/types.js +54 -0
- package/dist/sentiment/types.js.map +1 -0
- package/dist/system-prompt.js +9 -1
- package/dist/system-prompt.js.map +1 -1
- package/dist/tools/fundamentals/company-overview.d.ts +3 -1
- package/dist/tools/fundamentals/company-overview.js +27 -27
- package/dist/tools/fundamentals/company-overview.js.map +1 -1
- package/dist/tools/fundamentals/comps.js +45 -45
- package/dist/tools/fundamentals/comps.js.map +1 -1
- package/dist/tools/fundamentals/dcf.js +82 -82
- package/dist/tools/fundamentals/dcf.js.map +1 -1
- package/dist/tools/fundamentals/earnings.d.ts +3 -1
- package/dist/tools/fundamentals/earnings.js +25 -25
- package/dist/tools/fundamentals/earnings.js.map +1 -1
- package/dist/tools/fundamentals/financials.d.ts +3 -1
- package/dist/tools/fundamentals/financials.js +23 -23
- package/dist/tools/fundamentals/financials.js.map +1 -1
- package/dist/tools/index.js +8 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/interaction/ask-user.js +28 -64
- package/dist/tools/interaction/ask-user.js.map +1 -1
- package/dist/tools/macro/fred-data.d.ts +3 -1
- package/dist/tools/macro/fred-data.js +26 -26
- package/dist/tools/macro/fred-data.js.map +1 -1
- package/dist/tools/sentiment/reddit-sentiment.d.ts +3 -1
- package/dist/tools/sentiment/reddit-sentiment.js +107 -22
- package/dist/tools/sentiment/reddit-sentiment.js.map +1 -1
- package/dist/tools/sentiment/sentiment-summary.d.ts +7 -0
- package/dist/tools/sentiment/sentiment-summary.js +230 -0
- package/dist/tools/sentiment/sentiment-summary.js.map +1 -0
- package/dist/tools/sentiment/sentiment-trend.d.ts +22 -0
- package/dist/tools/sentiment/sentiment-trend.js +39 -0
- package/dist/tools/sentiment/sentiment-trend.js.map +1 -0
- package/dist/tools/sentiment/twitter-sentiment.js +17 -0
- package/dist/tools/sentiment/twitter-sentiment.js.map +1 -1
- package/dist/tools/sentiment/web-search.d.ts +11 -0
- package/dist/tools/sentiment/web-search.js +115 -0
- package/dist/tools/sentiment/web-search.js.map +1 -0
- package/dist/tools/sentiment/web-sentiment.d.ts +8 -0
- package/dist/tools/sentiment/web-sentiment.js +66 -0
- package/dist/tools/sentiment/web-sentiment.js.map +1 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/sentiment.d.ts +21 -0
- package/package.json +19 -3
- package/dist/tools/sentiment/news-sentiment.d.ts +0 -7
- package/dist/tools/sentiment/news-sentiment.js +0 -55
- package/dist/tools/sentiment/news-sentiment.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,63 +1,65 @@
|
|
|
1
1
|
# OpenCandle
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
OpenCandle is a terminal-first financial data agent built with TypeScript and Pi. It fetches market, macro, options, fundamentals, sentiment, and portfolio data from real providers, then lets the model synthesize that data into an answer.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This repository is useful in two ways:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- Run `opencandle` as an interactive CLI for market research
|
|
8
|
+
- Extend OpenCandle with new tools, providers, or Pi-compatible add-on packages
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
## What You Can Use It For
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
- Quote and history lookups for stocks and crypto
|
|
13
|
+
- Options chains with locally computed Greeks
|
|
14
|
+
- Company fundamentals, earnings, and SEC filings
|
|
15
|
+
- FRED macro series and Fear & Greed data
|
|
16
|
+
- Reddit-based sentiment and discussion lookups
|
|
17
|
+
- Portfolio tracking, watchlists, correlation, and risk analysis
|
|
18
|
+
- Multi-step workflows such as `/analyze NVDA`
|
|
12
19
|
|
|
13
|
-
|
|
20
|
+
OpenCandle is designed to fetch and format data. The model handles synthesis. Tool code should not invent financial conclusions or hardcode market numbers.
|
|
14
21
|
|
|
15
|
-
|
|
22
|
+
## Install And Run
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
Requires Node.js 20+.
|
|
25
|
+
|
|
26
|
+
### CLI
|
|
18
27
|
|
|
19
28
|
```bash
|
|
20
29
|
npm install -g opencandle
|
|
21
30
|
opencandle
|
|
22
31
|
|
|
23
|
-
# or
|
|
32
|
+
# or without installing globally
|
|
24
33
|
npx opencandle@latest
|
|
25
34
|
```
|
|
26
35
|
|
|
27
|
-
On first run, OpenCandle walks you through setup:
|
|
28
|
-
|
|
29
|
-
1. **Connect an AI provider** — sign in with OAuth (Google, OpenAI, Anthropic) or paste an API key
|
|
30
|
-
2. **Pick a model** — choose from the available models on your connected provider
|
|
31
|
-
3. **Optional: add market-data keys** — Alpha Vantage and FRED for fundamentals and macro data (can skip)
|
|
32
|
-
|
|
33
|
-
To rerun setup later, use `/setup`.
|
|
34
|
-
|
|
35
36
|
### From Source
|
|
36
37
|
|
|
37
38
|
```bash
|
|
38
39
|
npm install
|
|
39
40
|
cp .env.example .env
|
|
40
|
-
# Add any LLM env vars you want to use locally (for example GEMINI_API_KEY)
|
|
41
41
|
npm start
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
On first run, OpenCandle walks you through model setup. You can rerun that flow later with `/setup`.
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
Model access comes from Pi. Market data providers are optional and additive.
|
|
45
49
|
|
|
46
|
-
| Key | Required |
|
|
47
|
-
|
|
48
|
-
| `GEMINI_API_KEY` | No |
|
|
49
|
-
| `OPENAI_API_KEY` | No |
|
|
50
|
-
| `ANTHROPIC_API_KEY` | No |
|
|
51
|
-
| `ALPHA_VANTAGE_API_KEY` | No |
|
|
52
|
-
| `FRED_API_KEY` | No |
|
|
50
|
+
| Key | Required | Used For |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| `GEMINI_API_KEY` | No | Google models through Pi |
|
|
53
|
+
| `OPENAI_API_KEY` | No | OpenAI models through Pi |
|
|
54
|
+
| `ANTHROPIC_API_KEY` | No | Anthropic models through Pi |
|
|
55
|
+
| `ALPHA_VANTAGE_API_KEY` | No | Fundamentals, earnings, financial statements |
|
|
56
|
+
| `FRED_API_KEY` | No | Macro series such as rates, CPI, GDP, unemployment |
|
|
53
57
|
|
|
54
|
-
Yahoo Finance, CoinGecko, Reddit, and Fear & Greed
|
|
55
|
-
Pi also supports OAuth-backed and custom providers through `~/.pi/agent/auth.json`, `/login`, `/model`, and `~/.pi/agent/models.json`.
|
|
58
|
+
Yahoo Finance, CoinGecko, Reddit, SEC EDGAR, and Fear & Greed data do not require keys.
|
|
56
59
|
|
|
57
|
-
|
|
60
|
+
OpenCandle stores its own user state in `~/.opencandle/` by default. Pi configuration stays in `.pi/` and `~/.pi/agent/`. The CLI should not depend on repo-local `.pi/extensions/`.
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
- OpenCandle finance-provider config lives in `~/.opencandle/config.json`:
|
|
62
|
+
Provider keys can also be stored in `~/.opencandle/config.json`:
|
|
61
63
|
|
|
62
64
|
```json
|
|
63
65
|
{
|
|
@@ -72,88 +74,109 @@ Pi also supports OAuth-backed and custom providers through `~/.pi/agent/auth.jso
|
|
|
72
74
|
}
|
|
73
75
|
```
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
- Set `OPENCANDLE_HOME` to override the default `~/.opencandle/` data directory.
|
|
77
|
-
- OpenCandle user data lives in `~/.opencandle/` (or `$OPENCANDLE_HOME`):
|
|
78
|
-
- `~/.opencandle/watchlist.json`
|
|
79
|
-
- `~/.opencandle/portfolio.json`
|
|
80
|
-
- `~/.opencandle/predictions.json`
|
|
81
|
-
- `~/.opencandle/state.db`
|
|
82
|
-
- `~/.opencandle/logs/...`
|
|
83
|
-
- The published CLI should work from any directory without depending on a repo-local `.pi/extensions/...` file. Project `.pi/` remains optional for user overrides.
|
|
77
|
+
Environment variables override values from `~/.opencandle/config.json`. Set `OPENCANDLE_HOME` if you want OpenCandle state somewhere other than `~/.opencandle/`.
|
|
84
78
|
|
|
85
|
-
## Usage
|
|
79
|
+
## Basic Usage
|
|
86
80
|
|
|
87
|
-
OpenCandle runs inside Pi's interactive
|
|
81
|
+
OpenCandle runs inside Pi's interactive terminal UI.
|
|
82
|
+
|
|
83
|
+
Useful commands:
|
|
88
84
|
|
|
89
85
|
```text
|
|
90
|
-
/
|
|
91
|
-
/login
|
|
92
|
-
/
|
|
93
|
-
/analyze
|
|
86
|
+
/setup
|
|
87
|
+
/login
|
|
88
|
+
/model
|
|
89
|
+
/analyze AAPL
|
|
94
90
|
```
|
|
95
91
|
|
|
96
|
-
|
|
92
|
+
Example prompts:
|
|
97
93
|
|
|
98
94
|
```text
|
|
99
|
-
What
|
|
95
|
+
What is AAPL trading at?
|
|
100
96
|
Get the options chain for TSLA expiring April 24
|
|
101
97
|
Show me MSFT puts with Greeks
|
|
102
|
-
What's the Fear and Greed index?
|
|
103
98
|
Get the fed funds rate from FRED
|
|
104
99
|
Add 100 shares of NVDA at 120 to my portfolio, then show my portfolio
|
|
105
100
|
Run risk analysis on SPY
|
|
106
|
-
analyze AAPL
|
|
107
101
|
```
|
|
108
102
|
|
|
109
|
-
##
|
|
103
|
+
## Data Sources And Tool Coverage
|
|
110
104
|
|
|
111
|
-
|
|
|
112
|
-
|
|
113
|
-
|
|
|
114
|
-
|
|
|
115
|
-
|
|
|
116
|
-
|
|
|
117
|
-
|
|
|
118
|
-
|
|
|
119
|
-
|
|
|
105
|
+
| Area | Examples | Source |
|
|
106
|
+
| --- | --- | --- |
|
|
107
|
+
| Market data | quotes, history, ticker search, crypto price/history | Yahoo Finance, CoinGecko |
|
|
108
|
+
| Options | chains, open interest, IV, Greeks | Yahoo Finance plus local calculations |
|
|
109
|
+
| Fundamentals | overview, financials, earnings, DCF, company comparison | Alpha Vantage |
|
|
110
|
+
| Macro | economic series, Fear & Greed | FRED, alternative.me |
|
|
111
|
+
| Sentiment | Reddit, Twitter/X, and web sentiment with cross-source pipeline | Reddit JSON API, Twitter/X, DuckDuckGo, Brave |
|
|
112
|
+
| Filings | SEC filing search | SEC EDGAR |
|
|
113
|
+
| Portfolio | watchlist, prediction tracking, correlation, risk | Local state plus market data |
|
|
120
114
|
|
|
121
|
-
##
|
|
115
|
+
## Engineering Notes
|
|
122
116
|
|
|
123
|
-
|
|
117
|
+
### Project Shape
|
|
124
118
|
|
|
119
|
+
```text
|
|
120
|
+
src/
|
|
121
|
+
├── providers/ API clients
|
|
122
|
+
├── tools/ Tool implementations by domain
|
|
123
|
+
├── infra/ Cache, rate limiter, HTTP, browser, paths
|
|
124
|
+
├── routing/ Intent classification and slot resolution
|
|
125
|
+
├── workflows/ Multi-step workflow builders
|
|
126
|
+
├── memory/ SQLite-backed state and retrieval
|
|
127
|
+
├── analysts/ Multi-analyst orchestration
|
|
128
|
+
├── pi/ Pi integration and session wiring
|
|
129
|
+
└── index.ts Public exports
|
|
125
130
|
```
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
131
|
+
|
|
132
|
+
### Development Commands
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
npm start
|
|
136
|
+
npm test
|
|
137
|
+
npm run test:watch
|
|
138
|
+
npm run test:e2e
|
|
139
|
+
npm run test:e2e:cli
|
|
140
|
+
npm run test:e2e:providers
|
|
129
141
|
```
|
|
130
142
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
-
|
|
136
|
-
-
|
|
137
|
-
-
|
|
143
|
+
`npm test` is the required baseline check after changes.
|
|
144
|
+
|
|
145
|
+
### Repository Rules That Matter
|
|
146
|
+
|
|
147
|
+
- TDD is mandatory for behavior changes
|
|
148
|
+
- Unit tests mock `globalThis.fetch` and use JSON fixtures
|
|
149
|
+
- Use `cache` and `rateLimiter` for external calls
|
|
150
|
+
- Tools fetch and format data; analysts and prompts synthesize
|
|
151
|
+
- Keep typing strict and use `.js` extensions on relative imports
|
|
152
|
+
|
|
153
|
+
### Public Package Exports
|
|
154
|
+
|
|
155
|
+
Besides the CLI, the package exposes pieces for engineers building on top of OpenCandle:
|
|
156
|
+
|
|
157
|
+
- `opencandle`
|
|
158
|
+
- `opencandle/tool-kit`
|
|
159
|
+
- `opencandle/infra`
|
|
160
|
+
- `opencandle/types`
|
|
161
|
+
- `opencandle/providers`
|
|
138
162
|
|
|
139
|
-
|
|
163
|
+
If you want to add a new tool or publish an add-on package, start with [docs/build-a-tool.md](./docs/build-a-tool.md).
|
|
164
|
+
|
|
165
|
+
## Testing The Agent
|
|
166
|
+
|
|
167
|
+
For end-to-end agent driving with file-based IPC:
|
|
140
168
|
|
|
141
169
|
```bash
|
|
142
|
-
|
|
143
|
-
npm run test:watch # watch mode
|
|
170
|
+
npx tsx tests/harness/manual-run.ts /tmp/opencandle-ipc "What is AAPL trading at?"
|
|
144
171
|
```
|
|
145
172
|
|
|
146
|
-
|
|
173
|
+
The harness writes status and trace files into the IPC directory. See [tests/harness/README.md](./tests/harness/README.md) for the full flow.
|
|
147
174
|
|
|
148
|
-
|
|
149
|
-
- Contributor guide: [CONTRIBUTING.md](https://github.com/Kahtaf/OpenCandle/blob/main/CONTRIBUTING.md)
|
|
150
|
-
- Security policy: [SECURITY.md](https://github.com/Kahtaf/OpenCandle/blob/main/SECURITY.md)
|
|
151
|
-
- Release history: [CHANGELOG.md](https://github.com/Kahtaf/OpenCandle/blob/main/CHANGELOG.md)
|
|
152
|
-
|
|
153
|
-
## Tech Stack
|
|
175
|
+
## Project Docs
|
|
154
176
|
|
|
155
|
-
-
|
|
156
|
-
-
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
-
|
|
177
|
+
- [CONTRIBUTING.md](./CONTRIBUTING.md)
|
|
178
|
+
- [docs/build-a-tool.md](./docs/build-a-tool.md)
|
|
179
|
+
- [tests/harness/README.md](./tests/harness/README.md)
|
|
180
|
+
- [CHANGELOG.md](./CHANGELOG.md)
|
|
181
|
+
- [SECURITY.md](./SECURITY.md)
|
|
182
|
+
- [LICENSE](./LICENSE)
|
|
@@ -35,8 +35,7 @@ What is the options market pricing in that the stock price alone doesn't show?${
|
|
|
35
35
|
contrarian: (symbol) => `**[Contrarian Analyst]** You are a Burry-style contrarian. Your job is to find what the crowd is missing. Be terse and data-driven — cite concrete numbers like "FCF yield 14.7%" or "P/E 8.3x vs sector 22x." Analyze ${symbol}:
|
|
36
36
|
1. Use get_fear_greed for overall market mood — extreme readings signal opportunity.
|
|
37
37
|
2. Use get_reddit_sentiment on wallstreetbets and stocks — check the sentiment score. Extreme bullishness from retail is a warning; extreme bearishness may be opportunity.
|
|
38
|
-
3.
|
|
39
|
-
4. Cross-reference: Is sentiment overly bullish while fundamentals (revenue, margins, FCF) are deteriorating? Is everyone bearish while the numbers quietly improve?
|
|
38
|
+
3. Cross-reference: Is sentiment overly bullish while fundamentals (revenue, margins, FCF) are deteriorating? Is everyone bearish while the numbers quietly improve?
|
|
40
39
|
5. Reuse get_company_overview or other fundamentals already fetched earlier in the session if available. If fundamentals are unavailable, say so and base the contrarian view on sentiment and price only.
|
|
41
40
|
Where is the consensus wrong? What is the market over-pricing or under-pricing?${EXECUTION_GUARDRAILS}${VOTING_INSTRUCTION}`,
|
|
42
41
|
risk: (symbol) => `**[Risk Manager]** You are the final check before capital is deployed. Your job is to quantify downside, not to have an opinion on direction. Analyze ${symbol}:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/analysts/orchestrator.ts"],"names":[],"mappings":"AAOA,MAAM,cAAc,GAAG,4CAA4C,CAAC;AACpE,MAAM,yBAAyB,GAAG,kCAAkC,CAAC;AAErE,MAAM,kBAAkB,GAAG;;;;;gDAKqB,CAAC;AAEjD,MAAM,oBAAoB,GAAG;;;;kEAIqC,CAAC;AAEnE,MAAM,eAAe,GAAoD;IACvE,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE,CACpB,yKAAyK,MAAM;;;;;uPAKoE,oBAAoB,GAAG,kBAAkB,EAAE;IAEhS,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CACnB,gIAAgI,MAAM;;;;;;mJAMS,oBAAoB,GAAG,kBAAkB,EAAE;IAE5L,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAClB,wFAAwF,MAAM;;;;;;gFAMlB,oBAAoB,GAAG,kBAAkB,EAAE;IAEzH,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,CACrB,0NAA0N,MAAM
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/analysts/orchestrator.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
+
export interface SentimentConfig {
|
|
2
|
+
retentionDays: number;
|
|
3
|
+
defaultSubreddits: string[];
|
|
4
|
+
commentsPerPost: number;
|
|
5
|
+
divergenceThreshold: number;
|
|
6
|
+
}
|
|
1
7
|
export interface Config {
|
|
2
8
|
alphaVantageApiKey?: string;
|
|
3
9
|
fredApiKey?: string;
|
|
10
|
+
braveApiKey?: string;
|
|
11
|
+
exaApiKey?: string;
|
|
12
|
+
finnhubApiKey?: string;
|
|
4
13
|
/** Enable adversarial bull/bear debate in comprehensive analysis. Default: true. */
|
|
5
14
|
debate?: boolean;
|
|
15
|
+
sentiment?: SentimentConfig;
|
|
6
16
|
}
|
|
7
17
|
export interface OpenCandleFileConfig {
|
|
8
18
|
providers?: {
|
|
@@ -12,17 +22,27 @@ export interface OpenCandleFileConfig {
|
|
|
12
22
|
fred?: {
|
|
13
23
|
apiKey?: string;
|
|
14
24
|
};
|
|
25
|
+
brave?: {
|
|
26
|
+
apiKey?: string;
|
|
27
|
+
};
|
|
28
|
+
exa?: {
|
|
29
|
+
apiKey?: string;
|
|
30
|
+
};
|
|
31
|
+
finnhub?: {
|
|
32
|
+
apiKey?: string;
|
|
33
|
+
};
|
|
15
34
|
};
|
|
16
35
|
/** Enable adversarial bull/bear debate in comprehensive analysis. Default: true. */
|
|
17
36
|
debate?: boolean;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
37
|
+
sentiment?: {
|
|
38
|
+
retentionDays?: number;
|
|
39
|
+
defaultSubreddits?: string[];
|
|
40
|
+
commentsPerPost?: number;
|
|
41
|
+
divergenceThreshold?: number;
|
|
42
|
+
};
|
|
22
43
|
}
|
|
23
44
|
export declare function loadEnv(path?: string): void;
|
|
24
45
|
export declare function loadFileConfig(path?: string): OpenCandleFileConfig;
|
|
25
46
|
export declare function saveFileConfig(config: OpenCandleFileConfig, path?: string): void;
|
|
26
|
-
export declare function getFinanceProviderReadiness(path?: string): FinanceProviderReadiness;
|
|
27
47
|
export declare function loadConfig(): Config;
|
|
28
48
|
export declare function getConfig(): Config;
|
package/dist/config.js
CHANGED
|
@@ -23,12 +23,28 @@ export function loadEnv(path = ".env") {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
let cachedConfig = null;
|
|
26
|
+
const SENTIMENT_DEFAULTS = {
|
|
27
|
+
retentionDays: 30,
|
|
28
|
+
defaultSubreddits: ["wallstreetbets", "stocks", "investing", "options"],
|
|
29
|
+
commentsPerPost: 5,
|
|
30
|
+
divergenceThreshold: 0.4,
|
|
31
|
+
};
|
|
26
32
|
function resolveConfig(fileConfig) {
|
|
27
33
|
const debateEnv = process.env.OPENCANDLE_DEBATE;
|
|
34
|
+
const fileSentiment = fileConfig.sentiment;
|
|
28
35
|
return {
|
|
29
36
|
alphaVantageApiKey: process.env.ALPHA_VANTAGE_API_KEY ?? fileConfig.providers?.alphaVantage?.apiKey,
|
|
30
37
|
fredApiKey: process.env.FRED_API_KEY ?? fileConfig.providers?.fred?.apiKey,
|
|
38
|
+
braveApiKey: process.env.BRAVE_API_KEY ?? fileConfig.providers?.brave?.apiKey,
|
|
39
|
+
exaApiKey: process.env.EXA_API_KEY ?? fileConfig.providers?.exa?.apiKey,
|
|
40
|
+
finnhubApiKey: process.env.FINNHUB_API_KEY ?? fileConfig.providers?.finnhub?.apiKey,
|
|
31
41
|
debate: debateEnv !== undefined ? debateEnv !== "false" && debateEnv !== "0" : fileConfig.debate ?? true,
|
|
42
|
+
sentiment: {
|
|
43
|
+
retentionDays: fileSentiment?.retentionDays ?? SENTIMENT_DEFAULTS.retentionDays,
|
|
44
|
+
defaultSubreddits: fileSentiment?.defaultSubreddits ?? SENTIMENT_DEFAULTS.defaultSubreddits,
|
|
45
|
+
commentsPerPost: fileSentiment?.commentsPerPost ?? SENTIMENT_DEFAULTS.commentsPerPost,
|
|
46
|
+
divergenceThreshold: fileSentiment?.divergenceThreshold ?? SENTIMENT_DEFAULTS.divergenceThreshold,
|
|
47
|
+
},
|
|
32
48
|
};
|
|
33
49
|
}
|
|
34
50
|
export function loadFileConfig(path = getConfigPath()) {
|
|
@@ -56,14 +72,6 @@ export function saveFileConfig(config, path = getConfigPath()) {
|
|
|
56
72
|
ensureParentDir(path);
|
|
57
73
|
writeFileSync(path, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
|
|
58
74
|
}
|
|
59
|
-
export function getFinanceProviderReadiness(path = getConfigPath()) {
|
|
60
|
-
loadEnv();
|
|
61
|
-
const config = resolveConfig(loadFileConfig(path));
|
|
62
|
-
return {
|
|
63
|
-
hasAlphaVantage: Boolean(config.alphaVantageApiKey),
|
|
64
|
-
hasFred: Boolean(config.fredApiKey),
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
75
|
export function loadConfig() {
|
|
68
76
|
loadEnv();
|
|
69
77
|
cachedConfig = resolveConfig(loadFileConfig());
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/infra/cache.d.ts
CHANGED
|
@@ -37,6 +37,8 @@ export declare const TTL: {
|
|
|
37
37
|
readonly SENTIMENT: 300000;
|
|
38
38
|
readonly OPTIONS_CHAIN: 120000;
|
|
39
39
|
readonly CRUMB: 900000;
|
|
40
|
+
readonly WEB_SEARCH: 300000;
|
|
41
|
+
readonly FINNHUB_NEWS: 300000;
|
|
40
42
|
};
|
|
41
43
|
export declare const STALE_LIMIT: {
|
|
42
44
|
readonly QUOTE: number;
|
|
@@ -45,4 +47,6 @@ export declare const STALE_LIMIT: {
|
|
|
45
47
|
readonly MACRO: number;
|
|
46
48
|
readonly SENTIMENT: 3600000;
|
|
47
49
|
readonly OPTIONS_CHAIN: number;
|
|
50
|
+
readonly WEB_SEARCH: 3600000;
|
|
51
|
+
readonly FINNHUB_NEWS: 3600000;
|
|
48
52
|
};
|
package/dist/infra/cache.js
CHANGED
|
@@ -66,6 +66,8 @@ export const TTL = {
|
|
|
66
66
|
SENTIMENT: 300_000, // 5 minutes
|
|
67
67
|
OPTIONS_CHAIN: 120_000, // 2 minutes
|
|
68
68
|
CRUMB: 900_000, // 15 minutes
|
|
69
|
+
WEB_SEARCH: 300_000, // 5 minutes
|
|
70
|
+
FINNHUB_NEWS: 300_000, // 5 minutes
|
|
69
71
|
};
|
|
70
72
|
// Stale limits — how long past TTL expiry a cached value is still useful as fallback
|
|
71
73
|
export const STALE_LIMIT = {
|
|
@@ -75,5 +77,7 @@ export const STALE_LIMIT = {
|
|
|
75
77
|
MACRO: 24 * 3_600_000, // 24 hours
|
|
76
78
|
SENTIMENT: 3_600_000, // 1 hour
|
|
77
79
|
OPTIONS_CHAIN: 30 * 60_000, // 30 minutes
|
|
80
|
+
WEB_SEARCH: 3_600_000, // 1 hour
|
|
81
|
+
FINNHUB_NEWS: 3_600_000, // 1 hour
|
|
78
82
|
};
|
|
79
83
|
//# sourceMappingURL=cache.js.map
|
package/dist/infra/cache.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/infra/cache.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,KAAK;IACR,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAC;IAC/C,YAAY,GAAG,KAAK,CAAC;IACrB,iBAAiB,GAAG,CAAC,CAAC;IAE9B,GAAG,CAAI,GAAW;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS;YAAE,OAAO,SAAS,CAAC;QACnD,OAAO,KAAK,CAAC,KAAU,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAI,GAAW,EAAE,YAAoB;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAE7B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,QAAQ,GAAG,YAAY,EAAE,CAAC;YAC/C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC,QAAQ,CAAC;QACxC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAU,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC5E,CAAC;IAED;;;;OAIG;IACH,gBAAgB;QACd,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC9E,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;QAC3B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,GAAG,CAAI,GAAW,EAAE,KAAQ,EAAE,KAAa;QACzC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,UAAU,CAAC,OAAe;QACxB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YACpC,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC1B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF;AAED,wBAAwB;AACxB,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;AAEjC,eAAe;AACf,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,KAAK,EAAE,MAAM,EAAU,WAAW;IAClC,OAAO,EAAE,SAAS,EAAK,SAAS;IAChC,YAAY,EAAE,UAAU,EAAE,WAAW;IACrC,KAAK,EAAE,SAAS,EAAO,SAAS;IAChC,SAAS,EAAE,OAAO,EAAK,YAAY;IACnC,aAAa,EAAE,OAAO,EAAE,YAAY;IACpC,KAAK,EAAE,OAAO,EAAS,aAAa;
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/infra/cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,4 +36,10 @@ rateLimiter.configure("coingecko", 10, 0.167); // 10 req/min
|
|
|
36
36
|
rateLimiter.configure("alphavantage", 5, 0.083); // 5 req/min (free tier)
|
|
37
37
|
rateLimiter.configure("fred", 120, 2); // 120 req/min
|
|
38
38
|
rateLimiter.configure("twitter", 5, 0.167); // 5 req, ~10 req/min
|
|
39
|
+
rateLimiter.configure("reddit", 5, 0.167); // 5 req, ~10 req/min
|
|
40
|
+
rateLimiter.configure("reddit_comments", 10, 0.5); // 10 req, ~30 req/min
|
|
41
|
+
rateLimiter.configure("ddg", 3, 0.1); // 3 req, ~6 req/min
|
|
42
|
+
rateLimiter.configure("brave_search", 5, 0.083); // 5 req, ~5 req/min
|
|
43
|
+
rateLimiter.configure("exa", 5, 0.1); // 5 req, ~6 req/min
|
|
44
|
+
rateLimiter.configure("finnhub", 60, 1); // 60 req/min (free tier)
|
|
39
45
|
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/infra/rate-limiter.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,WAAW;IACd,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE5C,SAAS,CAAC,QAAgB,EAAE,SAAiB,EAAE,UAAkB;QAC/D,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE;YACzB,MAAM,EAAE,SAAS;YACjB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;YACtB,MAAM,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE;SAClC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,QAAgB;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,sBAAsB;QAE3C,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAEpB,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;YACnB,OAAO;QACT,CAAC;QAED,kCAAkC;QAClC,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;QACvE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACpB,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IACrB,CAAC;IAEO,MAAM,CAAC,MAAc;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;QACjD,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CACtB,MAAM,CAAC,MAAM,CAAC,SAAS,EACvB,MAAM,CAAC,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CACnD,CAAC;QACF,MAAM,CAAC,UAAU,GAAG,GAAG,CAAC;IAC1B,CAAC;CACF;AAED,+CAA+C;AAC/C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;AAC7C,WAAW,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAW,UAAU;AAC1D,WAAW,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,CAAE,aAAa;AAC7D,WAAW,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,wBAAwB;AACzE,WAAW,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAW,cAAc;AAC/D,WAAW,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAM,qBAAqB"}
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/infra/rate-limiter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import { type ProviderId } from "./providers.js";
|
|
3
|
+
export type ConnectResult = {
|
|
4
|
+
status: "connected";
|
|
5
|
+
} | {
|
|
6
|
+
status: "cancelled";
|
|
7
|
+
} | {
|
|
8
|
+
status: "blocked_by_env";
|
|
9
|
+
} | {
|
|
10
|
+
status: "invalid_key";
|
|
11
|
+
httpStatus?: number;
|
|
12
|
+
message?: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Run the connect flow for a single provider.
|
|
16
|
+
*
|
|
17
|
+
* Env-precedence short-circuit: if the provider's configured credential
|
|
18
|
+
* already comes from an environment variable, the file-config write would
|
|
19
|
+
* be invisible to the next tool call (env vars win in `resolveConfig`).
|
|
20
|
+
* Notify the user explicitly and return `blocked_by_env` — do not open
|
|
21
|
+
* the browser or collect a pasted value.
|
|
22
|
+
*/
|
|
23
|
+
export declare function runProviderConnect(ctx: ExtensionContext, providerId: ProviderId): Promise<ConnectResult>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Shared `runProviderConnect` function — the actual side-effectful flow that
|
|
2
|
+
// opens a browser, collects a pasted API key, validates it against the
|
|
3
|
+
// provider's API, persists it to `~/.opencandle/config.json`, and refreshes
|
|
4
|
+
// the cached Config so the next tool call sees the new credential.
|
|
5
|
+
//
|
|
6
|
+
// Called from two places:
|
|
7
|
+
// 1. The Pi `tool_result` extension handler when the user picks "Connect now"
|
|
8
|
+
// in the just-in-time prompt (Task Group 10).
|
|
9
|
+
// 2. The `/connect` Pi command (Task Group 13).
|
|
10
|
+
//
|
|
11
|
+
// Validation (Task Group 8 final pass): before persisting, the pasted key is
|
|
12
|
+
// validated via `validateCredential`, which makes a single cheap request to
|
|
13
|
+
// the provider's canonical API and classifies the response. A hard
|
|
14
|
+
// auth failure (401/403 or a provider-specific error-in-200-body) is
|
|
15
|
+
// returned as `invalid_key` WITHOUT persisting the bad value; a transient
|
|
16
|
+
// failure (timeout, 5xx, network error) warns the user but still persists
|
|
17
|
+
// the key so they aren't blocked on a provider outage — the next real tool
|
|
18
|
+
// call will surface any lingering issue via the credential-required tag.
|
|
19
|
+
import { openInBrowser } from "../infra/open-url.js";
|
|
20
|
+
import { loadFileConfig, saveFileConfig, loadConfig, } from "../config.js";
|
|
21
|
+
import { getProvider, getCredentialSource, } from "./providers.js";
|
|
22
|
+
import { loadOnboardingState, markProviderCompleted, saveOnboardingState, } from "./state.js";
|
|
23
|
+
import { validateCredential } from "./validation.js";
|
|
24
|
+
function writeNested(obj, path, value) {
|
|
25
|
+
if (path.length === 0)
|
|
26
|
+
return obj;
|
|
27
|
+
const [head, ...rest] = path;
|
|
28
|
+
const next = { ...obj };
|
|
29
|
+
if (rest.length === 0) {
|
|
30
|
+
next[head] = value;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
const child = next[head] && typeof next[head] === "object"
|
|
34
|
+
? next[head]
|
|
35
|
+
: {};
|
|
36
|
+
next[head] = writeNested(child, rest, value);
|
|
37
|
+
}
|
|
38
|
+
return next;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Run the connect flow for a single provider.
|
|
42
|
+
*
|
|
43
|
+
* Env-precedence short-circuit: if the provider's configured credential
|
|
44
|
+
* already comes from an environment variable, the file-config write would
|
|
45
|
+
* be invisible to the next tool call (env vars win in `resolveConfig`).
|
|
46
|
+
* Notify the user explicitly and return `blocked_by_env` — do not open
|
|
47
|
+
* the browser or collect a pasted value.
|
|
48
|
+
*/
|
|
49
|
+
export async function runProviderConnect(ctx, providerId) {
|
|
50
|
+
const descriptor = getProvider(providerId);
|
|
51
|
+
// Env-precedence check.
|
|
52
|
+
if (getCredentialSource(providerId) === "env") {
|
|
53
|
+
ctx.ui.notify(`${descriptor.displayName} is currently set via the ${descriptor.envVar} environment variable. ` +
|
|
54
|
+
`To change it from here, unset that variable first and reopen /connect ${descriptor.aliases[0] ?? descriptor.id}. ` +
|
|
55
|
+
`Otherwise, update ${descriptor.envVar} directly in your shell profile.`, "warning");
|
|
56
|
+
return { status: "blocked_by_env" };
|
|
57
|
+
}
|
|
58
|
+
// Open the signup URL in the user's browser. We ignore errors here — if
|
|
59
|
+
// the browser can't be opened, the user can still paste a key they
|
|
60
|
+
// already have, so we continue rather than bailing.
|
|
61
|
+
await openInBrowser(descriptor.signupUrl).catch(() => { });
|
|
62
|
+
ctx.ui.notify(`Opening ${descriptor.displayName} signup in your browser...`, "info");
|
|
63
|
+
// Prompt for the key. Uses the provider's instructionsHint as the
|
|
64
|
+
// placeholder text to remind the user what they're pasting.
|
|
65
|
+
const pasted = await ctx.ui.input(`Paste your ${descriptor.displayName} API key`, descriptor.instructionsHint);
|
|
66
|
+
if (!pasted) {
|
|
67
|
+
return { status: "cancelled" };
|
|
68
|
+
}
|
|
69
|
+
const trimmed = pasted.trim();
|
|
70
|
+
if (trimmed.length === 0) {
|
|
71
|
+
return { status: "cancelled" };
|
|
72
|
+
}
|
|
73
|
+
// Validate the key with the provider BEFORE persisting. Hard auth failures
|
|
74
|
+
// short-circuit here without writing anything; transient failures warn
|
|
75
|
+
// but proceed to persist so users don't get stuck on a provider outage.
|
|
76
|
+
ctx.ui.notify(`Verifying your ${descriptor.displayName} key...`, "info");
|
|
77
|
+
const validation = await validateCredential(providerId, trimmed);
|
|
78
|
+
if (validation.status === "invalid") {
|
|
79
|
+
const statusHint = validation.httpStatus !== undefined ? ` (HTTP ${validation.httpStatus})` : "";
|
|
80
|
+
const messageHint = validation.message ? ` — ${validation.message}` : "";
|
|
81
|
+
ctx.ui.notify(`${descriptor.displayName} rejected the key${statusHint}${messageHint}. ` +
|
|
82
|
+
`Your existing configuration was not changed. Re-run /connect ${descriptor.aliases[0] ?? descriptor.id} to try a different key.`, "error");
|
|
83
|
+
return {
|
|
84
|
+
status: "invalid_key",
|
|
85
|
+
httpStatus: validation.httpStatus,
|
|
86
|
+
message: validation.message,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (validation.status === "transient") {
|
|
90
|
+
ctx.ui.notify(`Couldn't reach ${descriptor.displayName} to verify the key (${validation.reason}). ` +
|
|
91
|
+
`Saving it anyway — the next request will surface any issue.`, "warning");
|
|
92
|
+
// Fall through to persist.
|
|
93
|
+
}
|
|
94
|
+
// Persist to file config. Merge into the existing structure, preserving
|
|
95
|
+
// any unrelated fields.
|
|
96
|
+
const existing = loadFileConfig();
|
|
97
|
+
const updated = writeNested(existing, descriptor.configPath, trimmed);
|
|
98
|
+
saveFileConfig(updated);
|
|
99
|
+
// Refresh the cached Config so the next tool call sees the new value.
|
|
100
|
+
loadConfig();
|
|
101
|
+
// Update onboarding state to completed.
|
|
102
|
+
const state = loadOnboardingState();
|
|
103
|
+
saveOnboardingState(markProviderCompleted(state, providerId));
|
|
104
|
+
ctx.ui.notify(`${descriptor.displayName} connected. Your key has been saved.`, "info");
|
|
105
|
+
return { status: "connected" };
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=connect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/onboarding/connect.ts"],"names":[],"mappings":"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"}
|