opencandle 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +150 -0
- package/dist/analysts/orchestrator.d.ts +9 -0
- package/dist/analysts/orchestrator.js +100 -0
- package/dist/analysts/orchestrator.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +122 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.js +76 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/infra/browser.d.ts +27 -0
- package/dist/infra/browser.js +102 -0
- package/dist/infra/browser.js.map +1 -0
- package/dist/infra/cache.d.ts +18 -0
- package/dist/infra/cache.js +42 -0
- package/dist/infra/cache.js.map +1 -0
- package/dist/infra/http-client.d.ts +13 -0
- package/dist/infra/http-client.js +54 -0
- package/dist/infra/http-client.js.map +1 -0
- package/dist/infra/index.d.ts +5 -0
- package/dist/infra/index.js +6 -0
- package/dist/infra/index.js.map +1 -0
- package/dist/infra/open-url.d.ts +1 -0
- package/dist/infra/open-url.js +29 -0
- package/dist/infra/open-url.js.map +1 -0
- package/dist/infra/opencandle-paths.d.ts +11 -0
- package/dist/infra/opencandle-paths.js +48 -0
- package/dist/infra/opencandle-paths.js.map +1 -0
- package/dist/infra/rate-limiter.d.ts +7 -0
- package/dist/infra/rate-limiter.js +38 -0
- package/dist/infra/rate-limiter.js.map +1 -0
- package/dist/memory/index.d.ts +5 -0
- package/dist/memory/index.js +5 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/preference-extractor.d.ts +6 -0
- package/dist/memory/preference-extractor.js +88 -0
- package/dist/memory/preference-extractor.js.map +1 -0
- package/dist/memory/retrieval.d.ts +8 -0
- package/dist/memory/retrieval.js +61 -0
- package/dist/memory/retrieval.js.map +1 -0
- package/dist/memory/sqlite.d.ts +5 -0
- package/dist/memory/sqlite.js +95 -0
- package/dist/memory/sqlite.js.map +1 -0
- package/dist/memory/storage.d.ts +47 -0
- package/dist/memory/storage.js +124 -0
- package/dist/memory/storage.js.map +1 -0
- package/dist/onboarding/state.d.ts +8 -0
- package/dist/onboarding/state.js +31 -0
- package/dist/onboarding/state.js.map +1 -0
- package/dist/pi/opencandle-extension.d.ts +2 -0
- package/dist/pi/opencandle-extension.js +205 -0
- package/dist/pi/opencandle-extension.js.map +1 -0
- package/dist/pi/session.d.ts +10 -0
- package/dist/pi/session.js +28 -0
- package/dist/pi/session.js.map +1 -0
- package/dist/pi/setup.d.ts +10 -0
- package/dist/pi/setup.js +357 -0
- package/dist/pi/setup.js.map +1 -0
- package/dist/pi/tool-adapter.d.ts +5 -0
- package/dist/pi/tool-adapter.js +17 -0
- package/dist/pi/tool-adapter.js.map +1 -0
- package/dist/prompts/workflow-prompts.d.ts +9 -0
- package/dist/prompts/workflow-prompts.js +202 -0
- package/dist/prompts/workflow-prompts.js.map +1 -0
- package/dist/providers/alpha-vantage.d.ts +4 -0
- package/dist/providers/alpha-vantage.js +122 -0
- package/dist/providers/alpha-vantage.js.map +1 -0
- package/dist/providers/coingecko.d.ts +3 -0
- package/dist/providers/coingecko.js +53 -0
- package/dist/providers/coingecko.js.map +1 -0
- package/dist/providers/fear-greed.d.ts +2 -0
- package/dist/providers/fear-greed.js +26 -0
- package/dist/providers/fear-greed.js.map +1 -0
- package/dist/providers/fred.d.ts +2 -0
- package/dist/providers/fred.js +37 -0
- package/dist/providers/fred.js.map +1 -0
- package/dist/providers/index.d.ts +7 -0
- package/dist/providers/index.js +8 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/reddit.d.ts +9 -0
- package/dist/providers/reddit.js +69 -0
- package/dist/providers/reddit.js.map +1 -0
- package/dist/providers/sec-edgar.d.ts +9 -0
- package/dist/providers/sec-edgar.js +59 -0
- package/dist/providers/sec-edgar.js.map +1 -0
- package/dist/providers/yahoo-finance.d.ts +17 -0
- package/dist/providers/yahoo-finance.js +231 -0
- package/dist/providers/yahoo-finance.js.map +1 -0
- package/dist/routing/classify-intent.d.ts +2 -0
- package/dist/routing/classify-intent.js +147 -0
- package/dist/routing/classify-intent.js.map +1 -0
- package/dist/routing/defaults.d.ts +7 -0
- package/dist/routing/defaults.js +26 -0
- package/dist/routing/defaults.js.map +1 -0
- package/dist/routing/entity-extractor.d.ts +3 -0
- package/dist/routing/entity-extractor.js +130 -0
- package/dist/routing/entity-extractor.js.map +1 -0
- package/dist/routing/index.d.ts +5 -0
- package/dist/routing/index.js +5 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/routing/slot-resolver.d.ts +15 -0
- package/dist/routing/slot-resolver.js +120 -0
- package/dist/routing/slot-resolver.js.map +1 -0
- package/dist/routing/types.d.ts +51 -0
- package/dist/routing/types.js +2 -0
- package/dist/routing/types.js.map +1 -0
- package/dist/system-prompt.d.ts +1 -0
- package/dist/system-prompt.js +49 -0
- package/dist/system-prompt.js.map +1 -0
- package/dist/tool-kit.d.ts +19 -0
- package/dist/tool-kit.js +20 -0
- package/dist/tool-kit.js.map +1 -0
- package/dist/tools/fundamentals/company-overview.d.ts +7 -0
- package/dist/tools/fundamentals/company-overview.js +40 -0
- package/dist/tools/fundamentals/company-overview.js.map +1 -0
- package/dist/tools/fundamentals/comps.d.ts +22 -0
- package/dist/tools/fundamentals/comps.js +110 -0
- package/dist/tools/fundamentals/comps.js.map +1 -0
- package/dist/tools/fundamentals/dcf.d.ts +46 -0
- package/dist/tools/fundamentals/dcf.js +184 -0
- package/dist/tools/fundamentals/dcf.js.map +1 -0
- package/dist/tools/fundamentals/earnings.d.ts +7 -0
- package/dist/tools/fundamentals/earnings.js +33 -0
- package/dist/tools/fundamentals/earnings.js.map +1 -0
- package/dist/tools/fundamentals/financials.d.ts +7 -0
- package/dist/tools/fundamentals/financials.js +37 -0
- package/dist/tools/fundamentals/financials.js.map +1 -0
- package/dist/tools/fundamentals/sec-filings.d.ts +8 -0
- package/dist/tools/fundamentals/sec-filings.js +40 -0
- package/dist/tools/fundamentals/sec-filings.js.map +1 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +51 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/macro/fear-greed.d.ts +5 -0
- package/dist/tools/macro/fear-greed.js +26 -0
- package/dist/tools/macro/fear-greed.js.map +1 -0
- package/dist/tools/macro/fred-data.d.ts +8 -0
- package/dist/tools/macro/fred-data.js +34 -0
- package/dist/tools/macro/fred-data.js.map +1 -0
- package/dist/tools/market/crypto-history.d.ts +8 -0
- package/dist/tools/market/crypto-history.js +32 -0
- package/dist/tools/market/crypto-history.js.map +1 -0
- package/dist/tools/market/crypto-price.d.ts +7 -0
- package/dist/tools/market/crypto-price.js +42 -0
- package/dist/tools/market/crypto-price.js.map +1 -0
- package/dist/tools/market/search-ticker.d.ts +6 -0
- package/dist/tools/market/search-ticker.js +33 -0
- package/dist/tools/market/search-ticker.js.map +1 -0
- package/dist/tools/market/stock-history.d.ts +9 -0
- package/dist/tools/market/stock-history.js +35 -0
- package/dist/tools/market/stock-history.js.map +1 -0
- package/dist/tools/market/stock-quote.d.ts +7 -0
- package/dist/tools/market/stock-quote.js +32 -0
- package/dist/tools/market/stock-quote.js.map +1 -0
- package/dist/tools/options/greeks.d.ts +14 -0
- package/dist/tools/options/greeks.js +65 -0
- package/dist/tools/options/greeks.js.map +1 -0
- package/dist/tools/options/option-chain.d.ts +9 -0
- package/dist/tools/options/option-chain.js +61 -0
- package/dist/tools/options/option-chain.js.map +1 -0
- package/dist/tools/portfolio/correlation.d.ts +10 -0
- package/dist/tools/portfolio/correlation.js +122 -0
- package/dist/tools/portfolio/correlation.js.map +1 -0
- package/dist/tools/portfolio/predictions.d.ts +49 -0
- package/dist/tools/portfolio/predictions.js +171 -0
- package/dist/tools/portfolio/predictions.js.map +1 -0
- package/dist/tools/portfolio/risk-analysis.d.ts +12 -0
- package/dist/tools/portfolio/risk-analysis.js +113 -0
- package/dist/tools/portfolio/risk-analysis.js.map +1 -0
- package/dist/tools/portfolio/tracker.d.ts +10 -0
- package/dist/tools/portfolio/tracker.js +125 -0
- package/dist/tools/portfolio/tracker.js.map +1 -0
- package/dist/tools/portfolio/watchlist.d.ts +10 -0
- package/dist/tools/portfolio/watchlist.js +120 -0
- package/dist/tools/portfolio/watchlist.js.map +1 -0
- package/dist/tools/sentiment/news-sentiment.d.ts +7 -0
- package/dist/tools/sentiment/news-sentiment.js +57 -0
- package/dist/tools/sentiment/news-sentiment.js.map +1 -0
- package/dist/tools/sentiment/reddit-sentiment.d.ts +8 -0
- package/dist/tools/sentiment/reddit-sentiment.js +37 -0
- package/dist/tools/sentiment/reddit-sentiment.js.map +1 -0
- package/dist/tools/technical/backtest.d.ts +26 -0
- package/dist/tools/technical/backtest.js +190 -0
- package/dist/tools/technical/backtest.js.map +1 -0
- package/dist/tools/technical/indicators.d.ts +23 -0
- package/dist/tools/technical/indicators.js +212 -0
- package/dist/tools/technical/indicators.js.map +1 -0
- package/dist/types/fundamentals.d.ts +44 -0
- package/dist/types/fundamentals.js +2 -0
- package/dist/types/fundamentals.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/macro.d.ts +24 -0
- package/dist/types/macro.js +14 -0
- package/dist/types/macro.js.map +1 -0
- package/dist/types/market.d.ts +41 -0
- package/dist/types/market.js +2 -0
- package/dist/types/market.js.map +1 -0
- package/dist/types/options.d.ts +33 -0
- package/dist/types/options.js +2 -0
- package/dist/types/options.js.map +1 -0
- package/dist/types/portfolio.d.ts +44 -0
- package/dist/types/portfolio.js +2 -0
- package/dist/types/portfolio.js.map +1 -0
- package/dist/types/sentiment.d.ts +24 -0
- package/dist/types/sentiment.js +2 -0
- package/dist/types/sentiment.js.map +1 -0
- package/dist/workflows/compare-assets.d.ts +3 -0
- package/dist/workflows/compare-assets.js +14 -0
- package/dist/workflows/compare-assets.js.map +1 -0
- package/dist/workflows/index.d.ts +4 -0
- package/dist/workflows/index.js +4 -0
- package/dist/workflows/index.js.map +1 -0
- package/dist/workflows/options-screener.d.ts +3 -0
- package/dist/workflows/options-screener.js +22 -0
- package/dist/workflows/options-screener.js.map +1 -0
- package/dist/workflows/portfolio-builder.d.ts +3 -0
- package/dist/workflows/portfolio-builder.js +26 -0
- package/dist/workflows/portfolio-builder.js.map +1 -0
- package/dist/workflows/types.d.ts +4 -0
- package/dist/workflows/types.js +2 -0
- package/dist/workflows/types.js.map +1 -0
- package/package.json +97 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kahtaf
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# OpenCandle
|
|
2
|
+
|
|
3
|
+
A financial agent that talks to markets. Ask it for stock prices, options chains with Greeks, macro data, sentiment — it fetches real data, computes analytics locally, and gives you actionable answers.
|
|
4
|
+
|
|
5
|
+
## What This Does
|
|
6
|
+
|
|
7
|
+
OpenCandle is an AI-powered terminal agent for investors and traders. Instead of switching between Yahoo Finance, FRED, Reddit, and a spreadsheet, you ask one agent and it chains the right tools together. It computes technical indicators and options Greeks locally (Black-Scholes), so there's no API dependency for math.
|
|
8
|
+
|
|
9
|
+
Type `analyze TSLA` and it runs a full 5-analyst breakdown — fundamentals, technicals, options positioning, sentiment, risk — then synthesizes a verdict.
|
|
10
|
+
|
|
11
|
+
[Pi](https://pi.dev/) powers the runtime, TUI, auth, and model selection. OpenCandle keeps its own user data in `~/.opencandle/`.
|
|
12
|
+
|
|
13
|
+
## Getting Started
|
|
14
|
+
|
|
15
|
+
### Standalone CLI
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g opencandle
|
|
19
|
+
opencandle
|
|
20
|
+
|
|
21
|
+
# or run without installing globally
|
|
22
|
+
npx opencandle@latest
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
On first run, OpenCandle guides you through AI model setup before chat starts. If you want to rerun that flow later, use `/setup`.
|
|
26
|
+
|
|
27
|
+
### From Source
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install
|
|
31
|
+
cp .env.example .env
|
|
32
|
+
# Add any LLM env vars you want to use locally (for example GEMINI_API_KEY)
|
|
33
|
+
npm start
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### API Keys
|
|
37
|
+
|
|
38
|
+
| Key | Required | Free Tier | What It Unlocks |
|
|
39
|
+
|-----|----------|-----------|-----------------|
|
|
40
|
+
| `GEMINI_API_KEY` | No | Yes | Google Gemini via Pi auth/model registry |
|
|
41
|
+
| `OPENAI_API_KEY` | No | Paid | OpenAI models via Pi auth/model registry |
|
|
42
|
+
| `ANTHROPIC_API_KEY` | No | Paid | Anthropic models via Pi auth/model registry |
|
|
43
|
+
| `ALPHA_VANTAGE_API_KEY` | No | 25 req/day | Company fundamentals, earnings, financials |
|
|
44
|
+
| `FRED_API_KEY` | No | Generous | Fed rates, CPI, GDP, unemployment, yield curve |
|
|
45
|
+
|
|
46
|
+
Yahoo Finance, CoinGecko, Reddit, and Fear & Greed Index need no keys.
|
|
47
|
+
Pi also supports OAuth-backed and custom providers through `~/.pi/agent/auth.json`, `/login`, `/model`, and `~/.pi/agent/models.json`.
|
|
48
|
+
|
|
49
|
+
### State and Config
|
|
50
|
+
|
|
51
|
+
- Pi runtime config and optional project overrides live in `.pi/` and `~/.pi/agent/...`.
|
|
52
|
+
- OpenCandle finance-provider config lives in `~/.opencandle/config.json`:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"providers": {
|
|
57
|
+
"alphaVantage": {
|
|
58
|
+
"apiKey": "..."
|
|
59
|
+
},
|
|
60
|
+
"fred": {
|
|
61
|
+
"apiKey": "..."
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- Environment variables still work and override `~/.opencandle/config.json`.
|
|
68
|
+
- OpenCandle user data lives in `~/.opencandle/`:
|
|
69
|
+
- `~/.opencandle/watchlist.json`
|
|
70
|
+
- `~/.opencandle/portfolio.json`
|
|
71
|
+
- `~/.opencandle/predictions.json`
|
|
72
|
+
- `~/.opencandle/state.db`
|
|
73
|
+
- `~/.opencandle/logs/...`
|
|
74
|
+
- The published CLI should work from any directory without depending on a repo-local `.pi/extensions/...` file. Project `.pi/` remains optional for user overrides.
|
|
75
|
+
|
|
76
|
+
## Usage
|
|
77
|
+
|
|
78
|
+
OpenCandle now runs inside Pi's interactive TUI. Useful controls:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
/model Switch provider/model
|
|
82
|
+
/login Authenticate an OAuth-backed provider
|
|
83
|
+
/setup Rerun OpenCandle setup
|
|
84
|
+
/analyze NVDA Run the multi-analyst workflow
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Natural-language prompts still work:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
What's the price of AAPL?
|
|
91
|
+
Get the options chain for TSLA expiring April 24
|
|
92
|
+
Show me MSFT puts with Greeks
|
|
93
|
+
What's the Fear and Greed index?
|
|
94
|
+
Get the fed funds rate from FRED
|
|
95
|
+
Add 100 shares of NVDA at 120 to my portfolio, then show my portfolio
|
|
96
|
+
Run risk analysis on SPY
|
|
97
|
+
analyze AAPL
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Tools (23)
|
|
101
|
+
|
|
102
|
+
| Category | Tools | Data Source |
|
|
103
|
+
|----------|-------|------------|
|
|
104
|
+
| **Market Data** | `search_ticker`, `get_stock_quote`, `get_stock_history`, `get_crypto_price`, `get_crypto_history` | Yahoo Finance, CoinGecko |
|
|
105
|
+
| **Options** | `get_option_chain` — strikes, bids/asks, volume, OI, IV, computed Greeks | Yahoo Finance + Black-Scholes |
|
|
106
|
+
| **Fundamentals** | `get_company_overview`, `get_financials`, `get_earnings`, `compute_dcf`, `compare_companies`, `get_sec_filings` | Alpha Vantage, SEC EDGAR |
|
|
107
|
+
| **Technical** | `get_technical_indicators`, `backtest_strategy` — SMA, EMA, RSI, MACD, Bollinger Bands, backtesting | Computed locally from OHLCV |
|
|
108
|
+
| **Macro** | `get_economic_data`, `get_fear_greed` | FRED, alternative.me |
|
|
109
|
+
| **Sentiment** | `get_reddit_sentiment`, `get_reddit_discussions` | Reddit JSON API |
|
|
110
|
+
| **Portfolio** | `track_portfolio`, `analyze_risk`, `manage_watchlist`, `analyze_correlation`, `track_prediction` | Yahoo Finance + local math |
|
|
111
|
+
|
|
112
|
+
## How It Works
|
|
113
|
+
|
|
114
|
+
Built on [Pi-mono](https://github.com/badlogic/pi-mono)'s `pi-coding-agent` SDK and TUI, with OpenCandle loaded as a bundled finance-only Pi extension. Tools are defined with [TypeBox](https://github.com/sinclairzx81/typebox) schemas and registered through Pi's extension system.
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
User prompt -> Pi session -> selected provider/model -> tool calls -> execute in parallel -> response
|
|
118
|
+
^ |
|
|
119
|
+
|____________________ Pi session + model registry _________________|
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Key architectural choices:
|
|
123
|
+
- **Local computation** over API calls for math (indicators, Greeks, risk metrics)
|
|
124
|
+
- **Stealth browser fallback** via [Camoufox](https://github.com/daijro/camoufox) when Yahoo rate-limits Node.js `fetch`
|
|
125
|
+
- **TTL caching + token bucket rate limiting** per provider
|
|
126
|
+
- **Pi-native auth/model flow** via `/model`, `/login`, `auth.json`, and `models.json`
|
|
127
|
+
- **Global OpenCandle state** under `~/.opencandle/`, separate from Pi config
|
|
128
|
+
- **Multi-analyst orchestration** via Pi extension commands and follow-up message hooks
|
|
129
|
+
|
|
130
|
+
## Test
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npm test # 208 unit tests
|
|
134
|
+
npm run test:watch # watch mode
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Project Docs
|
|
138
|
+
|
|
139
|
+
- OSS launch and npm release plan: [docs/production-plan.md](https://github.com/Kahtaf/OpenCandle/blob/main/docs/production-plan.md)
|
|
140
|
+
- Contributor guide: [CONTRIBUTING.md](https://github.com/Kahtaf/OpenCandle/blob/main/CONTRIBUTING.md)
|
|
141
|
+
- Security policy: [SECURITY.md](https://github.com/Kahtaf/OpenCandle/blob/main/SECURITY.md)
|
|
142
|
+
- Release history: [CHANGELOG.md](https://github.com/Kahtaf/OpenCandle/blob/main/CHANGELOG.md)
|
|
143
|
+
|
|
144
|
+
## Tech Stack
|
|
145
|
+
|
|
146
|
+
- **Runtime**: TypeScript, Node.js
|
|
147
|
+
- **LLM**: Pi model registry with Gemini, OpenAI, Anthropic, and custom providers
|
|
148
|
+
- **Browser**: Camoufox (anti-detection Firefox for scraping fallback)
|
|
149
|
+
- **Testing**: Vitest with fixture-mocked `fetch`
|
|
150
|
+
- **No frameworks**: Raw providers, no LangChain/LlamaIndex
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type AnalystRole = "valuation" | "momentum" | "options" | "contrarian" | "risk";
|
|
2
|
+
export declare function getInitialAnalysisPrompt(symbol: string): string;
|
|
3
|
+
export declare function getComprehensiveAnalysisPrompts(symbol: string): string[];
|
|
4
|
+
export declare function runComprehensiveAnalysis(enqueueFollowUp: (prompt: string) => void, symbol: string): void;
|
|
5
|
+
export declare function isAnalysisRequest(input: string): {
|
|
6
|
+
match: boolean;
|
|
7
|
+
symbol?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function normalizeSymbol(input: string): string | undefined;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const SYMBOL_CAPTURE = "(\\$?[A-Za-z]{1,5}(?:[./-][A-Za-z]{1,2})?)";
|
|
2
|
+
const NORMALIZED_SYMBOL_PATTERN = /^[A-Z]{1,5}(?:[./-][A-Z]{1,2})?$/;
|
|
3
|
+
const VOTING_INSTRUCTION = `
|
|
4
|
+
|
|
5
|
+
End your analysis with this exact format:
|
|
6
|
+
SIGNAL: BUY | HOLD | SELL
|
|
7
|
+
CONVICTION: [1-10]
|
|
8
|
+
THESIS: [one sentence summary of your position]`;
|
|
9
|
+
const EXECUTION_GUARDRAILS = `
|
|
10
|
+
Execution rules:
|
|
11
|
+
- Reuse tool outputs that were already fetched earlier in the session. Do not call the same tool again for the same symbol unless you need a missing field.
|
|
12
|
+
- If a required provider returns unavailable or missing data, stop that leg quickly, label the missing metrics as unavailable, and continue with the remaining evidence.
|
|
13
|
+
- Do not retry the same failing fundamentals call multiple times.`;
|
|
14
|
+
const ANALYST_PROMPTS = {
|
|
15
|
+
valuation: (symbol) => `**[Valuation Analyst]** You are a Damodaran-style valuation analyst. Your approach: connect the company's narrative to numbers, then compute intrinsic value. Analyze ${symbol}:
|
|
16
|
+
1. Start with get_company_overview for P/E, forward P/E, EPS, profit margin, and market cap.
|
|
17
|
+
2. If overview data is available, use get_financials for revenue, income, and free cash flow trends across years.
|
|
18
|
+
3. If financial statements are available, use get_earnings for EPS surprise patterns and growth trajectory.
|
|
19
|
+
4. Only use compute_dcf once you have the inputs needed to estimate intrinsic value.
|
|
20
|
+
Assess: What growth rate is the market implicitly pricing in? Is the current price above or below your intrinsic value range? Cite specific numbers with their source tool. Keep reasoning data-driven — every claim must reference a fetched number.${EXECUTION_GUARDRAILS}${VOTING_INSTRUCTION}`,
|
|
21
|
+
momentum: (symbol) => `**[Momentum Analyst]** You are a CAN SLIM-style momentum analyst. Price action and volume are your primary evidence. Analyze ${symbol}:
|
|
22
|
+
1. Use get_stock_history with 1y range, then get_technical_indicators.
|
|
23
|
+
2. Focus on: Is price making new highs or breaking down from a base? Is OBV rising (volume confirming) or diverging? Where is price relative to VWAP?
|
|
24
|
+
3. Check RSI (overbought >70 / oversold <30) and MACD histogram direction.
|
|
25
|
+
4. Identify key support/resistance from Bollinger Bands and SMA(20)/SMA(50).
|
|
26
|
+
5. Use get_earnings to check if earnings are accelerating quarter over quarter.
|
|
27
|
+
State specific price levels. A breakout on rising volume is bullish; a breakdown on high volume is bearish. No vague language — cite the numbers.${EXECUTION_GUARDRAILS}${VOTING_INSTRUCTION}`,
|
|
28
|
+
options: (symbol) => `**[Options Analyst]** You analyze what the derivatives market is pricing in. Analyze ${symbol}:
|
|
29
|
+
1. Use get_option_chain to review the full chain with strikes, volume, open interest, IV, and Greeks.
|
|
30
|
+
2. Compute the put/call ratio from volume data — above 1.0 is bearish bias, below 0.7 is bullish.
|
|
31
|
+
3. Look for unusually high volume contracts (>3x average OI) that signal institutional positioning.
|
|
32
|
+
4. Note the overall IV level — is it elevated (expecting a move) or compressed (quiet period)?
|
|
33
|
+
5. Check if smart money is positioning via deep ITM or OTM options with high volume.
|
|
34
|
+
What is the options market pricing in that the stock price alone doesn't show?${EXECUTION_GUARDRAILS}${VOTING_INSTRUCTION}`,
|
|
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
|
+
1. Use get_fear_greed for overall market mood — extreme readings signal opportunity.
|
|
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. Use get_reddit_discussions for ${symbol} to gauge retail narrative.
|
|
39
|
+
4. Cross-reference: Is sentiment overly bullish while fundamentals (revenue, margins, FCF) are deteriorating? Is everyone bearish while the numbers quietly improve?
|
|
40
|
+
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
|
+
Where is the consensus wrong? What is the market over-pricing or under-pricing?${EXECUTION_GUARDRAILS}${VOTING_INSTRUCTION}`,
|
|
42
|
+
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}:
|
|
43
|
+
1. Use analyze_risk to compute annualized volatility, Sharpe ratio, max drawdown, and VaR(95%).
|
|
44
|
+
2. Position sizing: Using the 2% portfolio risk rule, compute max position size. Formula: position_size = (0.02 * portfolio_value) / (entry_price * stop_loss_pct). Assume $100K portfolio.
|
|
45
|
+
3. Risk/reward: Is potential upside at least 2x the max drawdown? If not, the trade is unfavorable regardless of thesis.
|
|
46
|
+
4. Correlation: If this is in a portfolio, would it add diversification or concentration risk?
|
|
47
|
+
5. Scenario analysis: What is the max realistic downside in a 1-sigma and 2-sigma move?
|
|
48
|
+
Be quantitative. Every assessment must include a number.${EXECUTION_GUARDRAILS}${VOTING_INSTRUCTION}`,
|
|
49
|
+
};
|
|
50
|
+
const SYNTHESIS_PROMPT = (symbol) => `**[Synthesis]** You have received five analyst signals above for ${symbol}. Tally the SIGNAL votes (BUY/HOLD/SELL) and weight them by CONVICTION scores. Then provide:
|
|
51
|
+
1. **Vote Tally**: X BUY, Y HOLD, Z SELL — weighted average conviction
|
|
52
|
+
2. **Verdict**: Buy, Hold, or Sell — based on the signal consensus
|
|
53
|
+
3. **Key thesis** in 2-3 sentences
|
|
54
|
+
4. **Bull case** — what could go right
|
|
55
|
+
5. **Bear case** — what could go wrong
|
|
56
|
+
6. **Key levels** — entry, stop-loss, and target prices
|
|
57
|
+
7. **Position sizing recommendation** based on risk profile
|
|
58
|
+
|
|
59
|
+
Be direct and actionable. This is your final word on ${symbol}.`;
|
|
60
|
+
const VALIDATION_PROMPT = (symbol) => `**[Validation Check]** Review your complete analysis of ${symbol} above. For each specific number you cited (price, P/E, revenue, RSI, intrinsic value, etc.), verify it matches the tool output data you received. Flag any inconsistencies. If you stated a number without fetching it first, call that out as UNVERIFIED. Output: VALIDATED if all numbers check out, or list specific corrections needed.`;
|
|
61
|
+
export function getInitialAnalysisPrompt(symbol) {
|
|
62
|
+
return `Begin comprehensive analysis of ${symbol}. Start by getting the current stock quote.`;
|
|
63
|
+
}
|
|
64
|
+
export function getComprehensiveAnalysisPrompts(symbol) {
|
|
65
|
+
const roles = ["valuation", "momentum", "options", "contrarian", "risk"];
|
|
66
|
+
const prompts = [getInitialAnalysisPrompt(symbol)];
|
|
67
|
+
for (const role of roles) {
|
|
68
|
+
prompts.push(ANALYST_PROMPTS[role](symbol));
|
|
69
|
+
}
|
|
70
|
+
prompts.push(SYNTHESIS_PROMPT(symbol));
|
|
71
|
+
prompts.push(VALIDATION_PROMPT(symbol));
|
|
72
|
+
return prompts;
|
|
73
|
+
}
|
|
74
|
+
export function runComprehensiveAnalysis(enqueueFollowUp, symbol) {
|
|
75
|
+
for (const prompt of getComprehensiveAnalysisPrompts(symbol).slice(1)) {
|
|
76
|
+
enqueueFollowUp(prompt);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export function isAnalysisRequest(input) {
|
|
80
|
+
const patterns = [
|
|
81
|
+
new RegExp(`^analyze\\s+${SYMBOL_CAPTURE}\\s*$`, "i"),
|
|
82
|
+
new RegExp(`^full\\s+analysis\\s+(?:of\\s+)?${SYMBOL_CAPTURE}\\s*$`, "i"),
|
|
83
|
+
new RegExp(`^deep\\s+dive\\s+(?:on\\s+)?${SYMBOL_CAPTURE}\\s*$`, "i"),
|
|
84
|
+
];
|
|
85
|
+
for (const pattern of patterns) {
|
|
86
|
+
const match = input.match(pattern);
|
|
87
|
+
if (match) {
|
|
88
|
+
return { match: true, symbol: match[1].replace(/\$/g, "").toUpperCase() };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return { match: false };
|
|
92
|
+
}
|
|
93
|
+
export function normalizeSymbol(input) {
|
|
94
|
+
const trimmed = input.trim();
|
|
95
|
+
if (!trimmed)
|
|
96
|
+
return undefined;
|
|
97
|
+
const candidate = trimmed.replace(/\$/g, "").toUpperCase();
|
|
98
|
+
return NORMALIZED_SYMBOL_PATTERN.test(candidate) ? candidate : undefined;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/analysts/orchestrator.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from "node:util";
|
|
3
|
+
import { AuthStorage, DefaultPackageManager, InteractiveMode, ModelRegistry, SettingsManager, getAgentDir, initTheme, } from "@mariozechner/pi-coding-agent";
|
|
4
|
+
import { createOpenCandleSession } from "./pi/session.js";
|
|
5
|
+
import { loadEnv } from "./config.js";
|
|
6
|
+
async function handlePackageCommand(args, cwd, agentDir) {
|
|
7
|
+
const [command, ...rest] = args;
|
|
8
|
+
if (!command ||
|
|
9
|
+
!["install", "remove", "uninstall", "list", "update"].includes(command)) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
const settingsManager = SettingsManager.create(cwd, agentDir);
|
|
13
|
+
const packageManager = new DefaultPackageManager({
|
|
14
|
+
cwd,
|
|
15
|
+
agentDir,
|
|
16
|
+
settingsManager,
|
|
17
|
+
});
|
|
18
|
+
packageManager.setProgressCallback((event) => {
|
|
19
|
+
if (event.type === "start" || event.type === "progress") {
|
|
20
|
+
process.stdout.write(`${event.message}\n`);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const source = rest.find((a) => !a.startsWith("-"));
|
|
24
|
+
const local = rest.includes("-l") || rest.includes("--local");
|
|
25
|
+
switch (command === "uninstall" ? "remove" : command) {
|
|
26
|
+
case "install": {
|
|
27
|
+
if (!source) {
|
|
28
|
+
console.error("Usage: opencandle install <source> [-l]");
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
await packageManager.install(source, { local });
|
|
33
|
+
packageManager.addSourceToSettings(source, { local });
|
|
34
|
+
console.log(`Installed ${source}`);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
case "remove": {
|
|
38
|
+
if (!source) {
|
|
39
|
+
console.error("Usage: opencandle remove <source> [-l]");
|
|
40
|
+
process.exitCode = 1;
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
await packageManager.remove(source, { local });
|
|
44
|
+
const removed = packageManager.removeSourceFromSettings(source, {
|
|
45
|
+
local,
|
|
46
|
+
});
|
|
47
|
+
if (!removed) {
|
|
48
|
+
console.error(`No matching package found for ${source}`);
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.log(`Removed ${source}`);
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
case "list": {
|
|
57
|
+
const globalPkgs = settingsManager.getGlobalSettings().packages ?? [];
|
|
58
|
+
const projectPkgs = settingsManager.getProjectSettings().packages ?? [];
|
|
59
|
+
if (globalPkgs.length === 0 && projectPkgs.length === 0) {
|
|
60
|
+
console.log("No packages installed.");
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
if (globalPkgs.length > 0) {
|
|
64
|
+
console.log("User packages:");
|
|
65
|
+
for (const pkg of globalPkgs) {
|
|
66
|
+
const s = typeof pkg === "string" ? pkg : pkg.source;
|
|
67
|
+
const path = packageManager.getInstalledPath(s, "user");
|
|
68
|
+
console.log(` ${s}${path ? `\n ${path}` : ""}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (projectPkgs.length > 0) {
|
|
72
|
+
console.log("Project packages:");
|
|
73
|
+
for (const pkg of projectPkgs) {
|
|
74
|
+
const s = typeof pkg === "string" ? pkg : pkg.source;
|
|
75
|
+
const path = packageManager.getInstalledPath(s, "project");
|
|
76
|
+
console.log(` ${s}${path ? `\n ${path}` : ""}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
case "update": {
|
|
82
|
+
await packageManager.update(source);
|
|
83
|
+
console.log(source ? `Updated ${source}` : "All packages updated.");
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
async function main() {
|
|
90
|
+
const { positionals } = parseArgs({ allowPositionals: true, strict: false });
|
|
91
|
+
const cwd = process.cwd();
|
|
92
|
+
const agentDir = getAgentDir();
|
|
93
|
+
if (await handlePackageCommand(positionals, cwd, agentDir)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Default: start the OpenCandle interactive agent
|
|
97
|
+
loadEnv();
|
|
98
|
+
const settingsManager = SettingsManager.create(cwd, agentDir);
|
|
99
|
+
const authStorage = AuthStorage.create();
|
|
100
|
+
const modelRegistry = ModelRegistry.create(authStorage);
|
|
101
|
+
const shouldSuppressFallbackMessage = modelRegistry.getAvailable().length === 0;
|
|
102
|
+
initTheme(settingsManager.getTheme(), true);
|
|
103
|
+
const { session, modelFallbackMessage } = await createOpenCandleSession({
|
|
104
|
+
cwd,
|
|
105
|
+
settingsManager,
|
|
106
|
+
authStorage,
|
|
107
|
+
modelRegistry,
|
|
108
|
+
});
|
|
109
|
+
try {
|
|
110
|
+
const interactiveMode = new InteractiveMode(session, {
|
|
111
|
+
modelFallbackMessage: shouldSuppressFallbackMessage
|
|
112
|
+
? undefined
|
|
113
|
+
: modelFallbackMessage,
|
|
114
|
+
});
|
|
115
|
+
await interactiveMode.run();
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
session.dispose();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
await main();
|
|
122
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface Config {
|
|
2
|
+
alphaVantageApiKey?: string;
|
|
3
|
+
fredApiKey?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface OpenCandleFileConfig {
|
|
6
|
+
providers?: {
|
|
7
|
+
alphaVantage?: {
|
|
8
|
+
apiKey?: string;
|
|
9
|
+
};
|
|
10
|
+
fred?: {
|
|
11
|
+
apiKey?: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface FinanceProviderReadiness {
|
|
16
|
+
hasAlphaVantage: boolean;
|
|
17
|
+
hasFred: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function loadEnv(path?: string): void;
|
|
20
|
+
export declare function loadFileConfig(path?: string): OpenCandleFileConfig;
|
|
21
|
+
export declare function saveFileConfig(config: OpenCandleFileConfig, path?: string): void;
|
|
22
|
+
export declare function getFinanceProviderReadiness(path?: string): FinanceProviderReadiness;
|
|
23
|
+
export declare function loadConfig(): Config;
|
|
24
|
+
export declare function getConfig(): Config;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { ensureParentDir, getConfigPath } from "./infra/opencandle-paths.js";
|
|
3
|
+
export function loadEnv(path = ".env") {
|
|
4
|
+
let content;
|
|
5
|
+
try {
|
|
6
|
+
content = readFileSync(path, "utf-8");
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
for (const line of content.split("\n")) {
|
|
12
|
+
const trimmed = line.trim();
|
|
13
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
14
|
+
continue;
|
|
15
|
+
const eqIndex = trimmed.indexOf("=");
|
|
16
|
+
if (eqIndex === -1)
|
|
17
|
+
continue;
|
|
18
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
19
|
+
const value = trimmed.slice(eqIndex + 1).trim();
|
|
20
|
+
if (key && value) {
|
|
21
|
+
process.env[key] = value;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
let cachedConfig = null;
|
|
26
|
+
function resolveConfig(fileConfig) {
|
|
27
|
+
return {
|
|
28
|
+
alphaVantageApiKey: process.env.ALPHA_VANTAGE_API_KEY ?? fileConfig.providers?.alphaVantage?.apiKey,
|
|
29
|
+
fredApiKey: process.env.FRED_API_KEY ?? fileConfig.providers?.fred?.apiKey,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function loadFileConfig(path = getConfigPath()) {
|
|
33
|
+
if (!existsSync(path)) {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
let content;
|
|
37
|
+
try {
|
|
38
|
+
content = readFileSync(path, "utf-8");
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
42
|
+
throw new Error(`Unable to read OpenCandle config at ${path}: ${message}`);
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const parsed = JSON.parse(content);
|
|
46
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
50
|
+
throw new Error(`Invalid OpenCandle config at ${path}: ${message}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function saveFileConfig(config, path = getConfigPath()) {
|
|
54
|
+
ensureParentDir(path);
|
|
55
|
+
writeFileSync(path, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
|
|
56
|
+
}
|
|
57
|
+
export function getFinanceProviderReadiness(path = getConfigPath()) {
|
|
58
|
+
loadEnv();
|
|
59
|
+
const config = resolveConfig(loadFileConfig(path));
|
|
60
|
+
return {
|
|
61
|
+
hasAlphaVantage: Boolean(config.alphaVantageApiKey),
|
|
62
|
+
hasFred: Boolean(config.fredApiKey),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function loadConfig() {
|
|
66
|
+
loadEnv();
|
|
67
|
+
cachedConfig = resolveConfig(loadFileConfig());
|
|
68
|
+
return cachedConfig;
|
|
69
|
+
}
|
|
70
|
+
export function getConfig() {
|
|
71
|
+
if (!cachedConfig) {
|
|
72
|
+
return loadConfig();
|
|
73
|
+
}
|
|
74
|
+
return cachedConfig;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { createOpenCandleSession, type CreateOpenCandleSessionOptions } from "./pi/session.js";
|
|
2
|
+
export { default as openCandleExtension } from "./pi/opencandle-extension.js";
|
|
3
|
+
export { agentToolToPiTool, getOpenCandleToolDefinitions } from "./pi/tool-adapter.js";
|
|
4
|
+
export { registerOpenCandleTools } from "./tool-kit.js";
|
|
5
|
+
export { getAllTools } from "./tools/index.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createOpenCandleSession } from "./pi/session.js";
|
|
2
|
+
export { default as openCandleExtension } from "./pi/opencandle-extension.js";
|
|
3
|
+
export { agentToolToPiTool, getOpenCandleToolDefinitions } from "./pi/tool-adapter.js";
|
|
4
|
+
export { registerOpenCandleTools } from "./tool-kit.js";
|
|
5
|
+
export { getAllTools } from "./tools/index.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAuC,MAAM,iBAAiB,CAAC;AAC/F,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Page } from "playwright-core";
|
|
2
|
+
export declare const StealthBrowser: {
|
|
3
|
+
/**
|
|
4
|
+
* Navigate to a URL, run a JS function in the page context, and return the result.
|
|
5
|
+
*/
|
|
6
|
+
evaluate<T>(url: string, fn: () => T | Promise<T>): Promise<T>;
|
|
7
|
+
/**
|
|
8
|
+
* Fetch JSON from a URL using the browser's session (cookies, TLS fingerprint).
|
|
9
|
+
* Useful for APIs that block Node.js fetch but allow real browsers.
|
|
10
|
+
*/
|
|
11
|
+
fetchJson<T>(url: string, options?: {
|
|
12
|
+
cookies?: string;
|
|
13
|
+
}): Promise<T>;
|
|
14
|
+
/**
|
|
15
|
+
* Run a custom async function in the browser page context.
|
|
16
|
+
* The page must already be on a relevant domain for cookies to work.
|
|
17
|
+
*/
|
|
18
|
+
run<T>(fn: (page: Page) => Promise<T>): Promise<T>;
|
|
19
|
+
/**
|
|
20
|
+
* Navigate to a URL and establish session cookies for that domain.
|
|
21
|
+
*/
|
|
22
|
+
initSession(url: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Close the browser. It will be re-launched on next use.
|
|
25
|
+
*/
|
|
26
|
+
close(): Promise<void>;
|
|
27
|
+
};
|