opencandle 0.11.0 → 0.12.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 +25 -28
- package/dist/analysts/contracts.js +0 -1
- package/dist/analysts/orchestrator.d.ts +2 -0
- package/dist/analysts/orchestrator.js +19 -1
- package/dist/cli-main.js +13 -7
- package/dist/cli-options.d.ts +4 -0
- package/dist/cli-options.js +33 -0
- package/dist/cli.js +8 -3
- package/dist/config.js +0 -1
- package/dist/doctor/cli-command.js +2 -1
- package/dist/doctor/render.js +0 -1
- package/dist/doctor/report.js +41 -12
- package/dist/gui/server/ask-user-bridge.d.ts +19 -0
- package/dist/gui/server/ask-user-bridge.js +55 -0
- package/dist/gui/server/automation-heartbeat.d.ts +25 -0
- package/dist/gui/server/automation-heartbeat.js +61 -0
- package/dist/gui/server/background-quotes.d.ts +39 -0
- package/dist/gui/server/background-quotes.js +71 -0
- package/dist/gui/server/chat-event-adapter.d.ts +16 -0
- package/dist/gui/server/chat-event-adapter.js +263 -0
- package/dist/gui/server/gui-session-manager.d.ts +2 -0
- package/dist/gui/server/gui-session-manager.js +4 -0
- package/dist/gui/server/http-routes.d.ts +69 -0
- package/dist/gui/server/http-routes.js +1008 -0
- package/dist/gui/server/invoke-tool.d.ts +47 -0
- package/dist/gui/server/invoke-tool.js +373 -0
- package/dist/gui/server/live-chat-event-adapter.d.ts +19 -0
- package/dist/gui/server/live-chat-event-adapter.js +206 -0
- package/dist/gui/server/local-session-coordinator.d.ts +26 -0
- package/dist/gui/server/local-session-coordinator.js +53 -0
- package/dist/gui/server/market-state-api.d.ts +138 -0
- package/dist/gui/server/market-state-api.js +355 -0
- package/dist/gui/server/model-setup.d.ts +64 -0
- package/dist/gui/server/model-setup.js +150 -0
- package/dist/gui/server/private-api-access.d.ts +6 -0
- package/dist/gui/server/private-api-access.js +53 -0
- package/dist/gui/server/projector.d.ts +49 -0
- package/dist/gui/server/projector.js +296 -0
- package/dist/gui/server/prompt-observation.d.ts +8 -0
- package/dist/gui/server/prompt-observation.js +43 -0
- package/dist/gui/server/quote-snapshot-store.d.ts +14 -0
- package/dist/gui/server/quote-snapshot-store.js +49 -0
- package/dist/gui/server/server.d.ts +1 -0
- package/dist/gui/server/server.js +259 -0
- package/dist/gui/server/session-actions.d.ts +60 -0
- package/dist/gui/server/session-actions.js +218 -0
- package/dist/gui/server/session-entry-wait.d.ts +27 -0
- package/dist/gui/server/session-entry-wait.js +129 -0
- package/dist/gui/server/session-list.d.ts +2 -0
- package/dist/gui/server/session-list.js +11 -0
- package/dist/gui/server/shutdown.d.ts +10 -0
- package/dist/gui/server/shutdown.js +29 -0
- package/dist/gui/server/tool-invoke-ack.d.ts +17 -0
- package/dist/gui/server/tool-invoke-ack.js +26 -0
- package/dist/gui/server/tool-metadata.d.ts +93 -0
- package/dist/gui/server/tool-metadata.js +148 -0
- package/dist/gui/server/websocket.d.ts +9 -0
- package/dist/gui/server/websocket.js +124 -0
- package/dist/gui/server/writer-lock.d.ts +1 -0
- package/dist/gui/server/writer-lock.js +1 -0
- package/dist/gui/server/ws-hub.d.ts +50 -0
- package/dist/gui/server/ws-hub.js +284 -0
- package/dist/gui/shared/chat-events.d.ts +174 -0
- package/dist/gui/shared/chat-events.js +13 -0
- package/dist/gui/shared/event-reducer.d.ts +3 -0
- package/dist/gui/shared/event-reducer.js +187 -0
- package/dist/index.js +0 -1
- package/dist/infra/cache.d.ts +6 -0
- package/dist/infra/cache.js +16 -7
- package/dist/infra/freshness.d.ts +21 -0
- package/dist/infra/freshness.js +118 -0
- package/dist/infra/http-client.js +1 -2
- package/dist/infra/index.js +0 -1
- package/dist/infra/market-calendar.d.ts +14 -0
- package/dist/infra/market-calendar.js +136 -0
- package/dist/infra/native-dependencies.js +0 -1
- package/dist/infra/node-version.js +0 -1
- package/dist/infra/open-url.js +0 -1
- package/dist/infra/opencandle-paths.js +0 -1
- package/dist/infra/rate-limiter.js +1 -1
- package/dist/market-state/alert-conditions.js +0 -1
- package/dist/market-state/alert-runner.d.ts +1 -0
- package/dist/market-state/alert-runner.js +5 -4
- package/dist/market-state/daily-report.js +0 -1
- package/dist/market-state/local-automation-service.js +0 -1
- package/dist/market-state/notification-delivery.js +0 -1
- package/dist/market-state/resolve-for-mutation.js +0 -1
- package/dist/market-state/resolve.js +0 -1
- package/dist/market-state/service.d.ts +26 -21
- package/dist/market-state/service.js +175 -36
- package/dist/market-state/summaries.d.ts +8 -0
- package/dist/market-state/summaries.js +58 -0
- package/dist/memory/index.js +0 -1
- package/dist/memory/manager.js +0 -1
- package/dist/memory/preference-extractor.js +0 -1
- package/dist/memory/retrieval.js +0 -1
- package/dist/memory/sqlite.js +60 -11
- package/dist/memory/storage.js +0 -1
- package/dist/memory/tool-defaults.js +0 -1
- package/dist/memory/types.js +0 -1
- package/dist/monitor.js +0 -1
- package/dist/onboarding/connect.js +0 -1
- package/dist/onboarding/credential-interceptor.js +0 -1
- package/dist/onboarding/degradation-accumulator.js +0 -1
- package/dist/onboarding/prompt-user.d.ts +1 -1
- package/dist/onboarding/prompt-user.js +0 -1
- package/dist/onboarding/provider-status.js +0 -1
- package/dist/onboarding/providers.d.ts +25 -1
- package/dist/onboarding/providers.js +26 -1
- package/dist/onboarding/state.js +0 -1
- package/dist/onboarding/tool-helpers.js +0 -1
- package/dist/onboarding/tool-tags.js +0 -1
- package/dist/onboarding/validate-model-key.d.ts +17 -0
- package/dist/onboarding/validate-model-key.js +54 -0
- package/dist/onboarding/validation.js +0 -1
- package/dist/pi/opencandle-extension.js +46 -7
- package/dist/pi/session-action-dedupe.js +0 -1
- package/dist/pi/session-storage.js +0 -1
- package/dist/pi/session-writer-lock.js +0 -1
- package/dist/pi/session.js +0 -1
- package/dist/pi/setup.d.ts +2 -0
- package/dist/pi/setup.js +10 -3
- package/dist/pi/tool-adapter.js +0 -1
- package/dist/pi/tui-session-coordinator.js +0 -1
- package/dist/prompts/context-builder.js +1 -2
- package/dist/prompts/disclaimer.js +0 -1
- package/dist/prompts/policy-cards.js +0 -1
- package/dist/prompts/sections.js +0 -1
- package/dist/prompts/symbol-preflight.js +0 -1
- package/dist/prompts/workflow-prompts.js +0 -1
- package/dist/providers/alpha-vantage.js +8 -3
- package/dist/providers/coingecko.js +1 -1
- package/dist/providers/errors.js +0 -1
- package/dist/providers/exa-search.js +11 -10
- package/dist/providers/external-tool-command.js +0 -1
- package/dist/providers/external-tool-error.js +0 -1
- package/dist/providers/fear-greed.js +0 -1
- package/dist/providers/finnhub.js +0 -1
- package/dist/providers/fred.js +0 -1
- package/dist/providers/index.js +0 -1
- package/dist/providers/polymarket.d.ts +2 -0
- package/dist/providers/polymarket.js +162 -0
- package/dist/providers/provider-credential-error.js +0 -1
- package/dist/providers/reddit-cli.js +0 -1
- package/dist/providers/reddit.js +0 -1
- package/dist/providers/sec-edgar.js +0 -1
- package/dist/providers/tradingview.js +1 -2
- package/dist/providers/twitter-cli.js +0 -1
- package/dist/providers/twitter.js +0 -1
- package/dist/providers/web-search.js +15 -12
- package/dist/providers/with-fallback.js +0 -1
- package/dist/providers/wrap-provider.js +5 -4
- package/dist/providers/yahoo-finance.d.ts +3 -0
- package/dist/providers/yahoo-finance.js +272 -13
- package/dist/routing/classify-intent.js +0 -1
- package/dist/routing/defaults.js +0 -1
- package/dist/routing/entity-extractor.js +18 -3
- package/dist/routing/fund-symbols.js +0 -1
- package/dist/routing/horizon.js +0 -1
- package/dist/routing/index.js +0 -1
- package/dist/routing/legacy-rule-router.js +0 -1
- package/dist/routing/planning.js +0 -1
- package/dist/routing/route-manifest.js +1 -2
- package/dist/routing/router-llm-client.d.ts +2 -2
- package/dist/routing/router-llm-client.js +18 -4
- package/dist/routing/router-prompt.js +0 -1
- package/dist/routing/router-types.js +0 -1
- package/dist/routing/router.d.ts +1 -1
- package/dist/routing/router.js +274 -6
- package/dist/routing/slot-resolver.d.ts +1 -0
- package/dist/routing/slot-resolver.js +1 -2
- package/dist/routing/symbol-disambiguator.js +0 -1
- package/dist/routing/turn-context.js +0 -1
- package/dist/routing/types.js +0 -1
- package/dist/runtime/answer-contracts.js +0 -1
- package/dist/runtime/artifact-contracts.js +0 -1
- package/dist/runtime/evidence.d.ts +1 -0
- package/dist/runtime/evidence.js +0 -1
- package/dist/runtime/numeric-claims.d.ts +23 -0
- package/dist/runtime/numeric-claims.js +99 -0
- package/dist/runtime/planning-evidence.js +1 -77
- package/dist/runtime/prompt-step.d.ts +10 -1
- package/dist/runtime/prompt-step.js +116 -3
- package/dist/runtime/provider-tracker.js +0 -1
- package/dist/runtime/run-context.js +0 -1
- package/dist/runtime/session-coordinator.d.ts +11 -1
- package/dist/runtime/session-coordinator.js +352 -50
- package/dist/runtime/session-title.js +0 -1
- package/dist/runtime/tool-defaults-wrapper.js +0 -1
- package/dist/runtime/validation.d.ts +3 -1
- package/dist/runtime/validation.js +0 -1
- package/dist/runtime/workflow-events.d.ts +1 -1
- package/dist/runtime/workflow-events.js +0 -1
- package/dist/runtime/workflow-runner.d.ts +1 -0
- package/dist/runtime/workflow-runner.js +8 -3
- package/dist/runtime/workflow-types.d.ts +3 -0
- package/dist/runtime/workflow-types.js +0 -1
- package/dist/sentiment/adapters/finnhub.js +0 -1
- package/dist/sentiment/adapters/reddit.js +0 -1
- package/dist/sentiment/adapters/twitter.js +0 -1
- package/dist/sentiment/adapters/web.js +0 -1
- package/dist/sentiment/index.js +4 -2
- package/dist/sentiment/insights.js +0 -1
- package/dist/sentiment/keywords.js +0 -1
- package/dist/sentiment/pipeline.js +0 -1
- package/dist/sentiment/scorer.js +0 -1
- package/dist/sentiment/store.js +0 -1
- package/dist/sentiment/trends.js +0 -1
- package/dist/sentiment/types.js +0 -1
- package/dist/system-prompt.js +0 -1
- package/dist/tool-kit.js +0 -1
- package/dist/tools/fundamentals/company-overview.d.ts +1 -1
- package/dist/tools/fundamentals/company-overview.js +2 -1
- package/dist/tools/fundamentals/comps.d.ts +1 -0
- package/dist/tools/fundamentals/comps.js +25 -12
- package/dist/tools/fundamentals/dcf.js +183 -113
- package/dist/tools/fundamentals/earnings.d.ts +1 -1
- package/dist/tools/fundamentals/earnings.js +2 -1
- package/dist/tools/fundamentals/financials.js +2 -1
- package/dist/tools/fundamentals/sec-filings.js +0 -1
- package/dist/tools/index.d.ts +117 -2
- package/dist/tools/index.js +3 -1
- package/dist/tools/interaction/ask-user.js +11 -1
- package/dist/tools/macro/event-probabilities.d.ts +8 -0
- package/dist/tools/macro/event-probabilities.js +120 -0
- package/dist/tools/macro/fear-greed.d.ts +1 -1
- package/dist/tools/macro/fear-greed.js +0 -1
- package/dist/tools/macro/fred-data.d.ts +1 -1
- package/dist/tools/macro/fred-data.js +2 -1
- package/dist/tools/market/crypto-history.js +0 -1
- package/dist/tools/market/crypto-price.d.ts +4 -1
- package/dist/tools/market/crypto-price.js +10 -2
- package/dist/tools/market/screen-stocks.js +14 -4
- package/dist/tools/market/search-ticker.js +1 -2
- package/dist/tools/market/stock-history.js +0 -1
- package/dist/tools/market/stock-quote.d.ts +4 -1
- package/dist/tools/market/stock-quote.js +9 -5
- package/dist/tools/options/greeks.js +0 -1
- package/dist/tools/options/option-chain.d.ts +4 -1
- package/dist/tools/options/option-chain.js +12 -2
- package/dist/tools/portfolio/alerts.d.ts +2 -1
- package/dist/tools/portfolio/alerts.js +228 -2
- package/dist/tools/portfolio/correlation.js +23 -5
- package/dist/tools/portfolio/daily-report.js +0 -1
- package/dist/tools/portfolio/holdings-overlap.js +0 -1
- package/dist/tools/portfolio/notifications.js +0 -1
- package/dist/tools/portfolio/risk-analysis.d.ts +1 -1
- package/dist/tools/portfolio/risk-analysis.js +1 -2
- package/dist/tools/portfolio/tracker.d.ts +3 -1
- package/dist/tools/portfolio/tracker.js +57 -10
- package/dist/tools/portfolio/watchlist.d.ts +3 -6
- package/dist/tools/portfolio/watchlist.js +101 -110
- package/dist/tools/sentiment/insight-format.js +0 -1
- package/dist/tools/sentiment/query-match.js +0 -1
- package/dist/tools/sentiment/reddit-sentiment.js +0 -1
- package/dist/tools/sentiment/sentiment-summary.js +8 -4
- package/dist/tools/sentiment/sentiment-trend.d.ts +5 -1
- package/dist/tools/sentiment/sentiment-trend.js +6 -2
- package/dist/tools/sentiment/twitter-sentiment.js +0 -1
- package/dist/tools/sentiment/untrusted-text.js +0 -1
- package/dist/tools/sentiment/web-search.d.ts +1 -1
- package/dist/tools/sentiment/web-search.js +0 -1
- package/dist/tools/sentiment/web-sentiment.js +0 -1
- package/dist/tools/technical/backtest.js +0 -1
- package/dist/tools/technical/indicators.js +1 -2
- package/dist/types/fundamentals.d.ts +1 -0
- package/dist/types/fundamentals.js +0 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +0 -1
- package/dist/types/macro.js +0 -1
- package/dist/types/market.d.ts +8 -0
- package/dist/types/market.js +0 -1
- package/dist/types/options.d.ts +1 -0
- package/dist/types/options.js +0 -1
- package/dist/types/portfolio.js +0 -1
- package/dist/types/prediction-markets.d.ts +13 -0
- package/dist/types/prediction-markets.js +1 -0
- package/dist/types/sentiment.js +0 -1
- package/dist/workflows/compare-assets.js +0 -1
- package/dist/workflows/index.js +0 -1
- package/dist/workflows/options-screener.js +0 -1
- package/dist/workflows/portfolio-builder.js +0 -1
- package/gui/web/dist/assets/CatalogOverlay-CAc7e3Pf.js +1 -0
- package/gui/web/dist/assets/index-BOEKd9wT.css +2 -0
- package/gui/web/dist/assets/index-C-H05cQ2.js +65 -0
- package/gui/web/dist/index.html +2 -2
- package/package.json +16 -22
- package/dist/analysts/contracts.js.map +0 -1
- package/dist/analysts/orchestrator.js.map +0 -1
- package/dist/cli-main.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/doctor/cli-command.js.map +0 -1
- package/dist/doctor/render.js.map +0 -1
- package/dist/doctor/report.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/infra/cache.js.map +0 -1
- package/dist/infra/http-client.js.map +0 -1
- package/dist/infra/index.js.map +0 -1
- package/dist/infra/native-dependencies.js.map +0 -1
- package/dist/infra/node-version.js.map +0 -1
- package/dist/infra/open-url.js.map +0 -1
- package/dist/infra/opencandle-paths.js.map +0 -1
- package/dist/infra/rate-limiter.js.map +0 -1
- package/dist/market-state/alert-conditions.js.map +0 -1
- package/dist/market-state/alert-runner.js.map +0 -1
- package/dist/market-state/daily-report.js.map +0 -1
- package/dist/market-state/local-automation-service.js.map +0 -1
- package/dist/market-state/notification-delivery.js.map +0 -1
- package/dist/market-state/resolve-for-mutation.js.map +0 -1
- package/dist/market-state/resolve.js.map +0 -1
- package/dist/market-state/service.js.map +0 -1
- package/dist/memory/index.js.map +0 -1
- package/dist/memory/manager.js.map +0 -1
- package/dist/memory/preference-extractor.js.map +0 -1
- package/dist/memory/retrieval.js.map +0 -1
- package/dist/memory/sqlite.js.map +0 -1
- package/dist/memory/storage.js.map +0 -1
- package/dist/memory/tool-defaults.js.map +0 -1
- package/dist/memory/types.js.map +0 -1
- package/dist/monitor.js.map +0 -1
- package/dist/onboarding/connect.js.map +0 -1
- package/dist/onboarding/credential-interceptor.js.map +0 -1
- package/dist/onboarding/degradation-accumulator.js.map +0 -1
- package/dist/onboarding/prompt-user.js.map +0 -1
- package/dist/onboarding/provider-status.js.map +0 -1
- package/dist/onboarding/providers.js.map +0 -1
- package/dist/onboarding/state.js.map +0 -1
- package/dist/onboarding/tool-helpers.js.map +0 -1
- package/dist/onboarding/tool-tags.js.map +0 -1
- package/dist/onboarding/validation.js.map +0 -1
- package/dist/pi/opencandle-extension.js.map +0 -1
- package/dist/pi/session-action-dedupe.js.map +0 -1
- package/dist/pi/session-storage.js.map +0 -1
- package/dist/pi/session-writer-lock.js.map +0 -1
- package/dist/pi/session.js.map +0 -1
- package/dist/pi/setup.js.map +0 -1
- package/dist/pi/tool-adapter.js.map +0 -1
- package/dist/pi/tui-session-coordinator.js.map +0 -1
- package/dist/prompts/context-builder.js.map +0 -1
- package/dist/prompts/disclaimer.js.map +0 -1
- package/dist/prompts/policy-cards.js.map +0 -1
- package/dist/prompts/sections.js.map +0 -1
- package/dist/prompts/symbol-preflight.js.map +0 -1
- package/dist/prompts/workflow-prompts.js.map +0 -1
- package/dist/providers/alpha-vantage.js.map +0 -1
- package/dist/providers/coingecko.js.map +0 -1
- package/dist/providers/errors.js.map +0 -1
- package/dist/providers/exa-search.js.map +0 -1
- package/dist/providers/external-tool-command.js.map +0 -1
- package/dist/providers/external-tool-error.js.map +0 -1
- package/dist/providers/fear-greed.js.map +0 -1
- package/dist/providers/finnhub.js.map +0 -1
- package/dist/providers/fred.js.map +0 -1
- package/dist/providers/index.js.map +0 -1
- package/dist/providers/provider-credential-error.js.map +0 -1
- package/dist/providers/reddit-cli.js.map +0 -1
- package/dist/providers/reddit.js.map +0 -1
- package/dist/providers/sec-edgar.js.map +0 -1
- package/dist/providers/tradingview.js.map +0 -1
- package/dist/providers/twitter-cli.js.map +0 -1
- package/dist/providers/twitter.js.map +0 -1
- package/dist/providers/web-search.js.map +0 -1
- package/dist/providers/with-fallback.js.map +0 -1
- package/dist/providers/wrap-provider.js.map +0 -1
- package/dist/providers/yahoo-finance.js.map +0 -1
- package/dist/routing/classify-intent.js.map +0 -1
- package/dist/routing/defaults.js.map +0 -1
- package/dist/routing/entity-extractor.js.map +0 -1
- package/dist/routing/fund-symbols.js.map +0 -1
- package/dist/routing/horizon.js.map +0 -1
- package/dist/routing/index.js.map +0 -1
- package/dist/routing/legacy-rule-router.js.map +0 -1
- package/dist/routing/planning.js.map +0 -1
- package/dist/routing/route-manifest.js.map +0 -1
- package/dist/routing/router-llm-client.js.map +0 -1
- package/dist/routing/router-prompt.js.map +0 -1
- package/dist/routing/router-types.js.map +0 -1
- package/dist/routing/router.js.map +0 -1
- package/dist/routing/slot-resolver.js.map +0 -1
- package/dist/routing/symbol-disambiguator.js.map +0 -1
- package/dist/routing/turn-context.js.map +0 -1
- package/dist/routing/types.js.map +0 -1
- package/dist/runtime/answer-contracts.js.map +0 -1
- package/dist/runtime/artifact-contracts.js.map +0 -1
- package/dist/runtime/evidence.js.map +0 -1
- package/dist/runtime/planning-evidence.js.map +0 -1
- package/dist/runtime/prompt-step.js.map +0 -1
- package/dist/runtime/provider-tracker.js.map +0 -1
- package/dist/runtime/run-context.js.map +0 -1
- package/dist/runtime/session-coordinator.js.map +0 -1
- package/dist/runtime/session-title.js.map +0 -1
- package/dist/runtime/tool-defaults-wrapper.js.map +0 -1
- package/dist/runtime/validation.js.map +0 -1
- package/dist/runtime/workflow-events.js.map +0 -1
- package/dist/runtime/workflow-runner.js.map +0 -1
- package/dist/runtime/workflow-types.js.map +0 -1
- package/dist/sentiment/adapters/finnhub.js.map +0 -1
- package/dist/sentiment/adapters/reddit.js.map +0 -1
- package/dist/sentiment/adapters/twitter.js.map +0 -1
- package/dist/sentiment/adapters/web.js.map +0 -1
- package/dist/sentiment/index.js.map +0 -1
- package/dist/sentiment/insights.js.map +0 -1
- package/dist/sentiment/keywords.js.map +0 -1
- package/dist/sentiment/pipeline.js.map +0 -1
- package/dist/sentiment/scorer.js.map +0 -1
- package/dist/sentiment/store.js.map +0 -1
- package/dist/sentiment/trends.js.map +0 -1
- package/dist/sentiment/types.js.map +0 -1
- package/dist/system-prompt.js.map +0 -1
- package/dist/tool-kit.js.map +0 -1
- package/dist/tools/fundamentals/company-overview.js.map +0 -1
- package/dist/tools/fundamentals/comps.js.map +0 -1
- package/dist/tools/fundamentals/dcf.js.map +0 -1
- package/dist/tools/fundamentals/earnings.js.map +0 -1
- package/dist/tools/fundamentals/financials.js.map +0 -1
- package/dist/tools/fundamentals/sec-filings.js.map +0 -1
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/interaction/ask-user.js.map +0 -1
- package/dist/tools/macro/fear-greed.js.map +0 -1
- package/dist/tools/macro/fred-data.js.map +0 -1
- package/dist/tools/market/crypto-history.js.map +0 -1
- package/dist/tools/market/crypto-price.js.map +0 -1
- package/dist/tools/market/screen-stocks.js.map +0 -1
- package/dist/tools/market/search-ticker.js.map +0 -1
- package/dist/tools/market/stock-history.js.map +0 -1
- package/dist/tools/market/stock-quote.js.map +0 -1
- package/dist/tools/options/greeks.js.map +0 -1
- package/dist/tools/options/option-chain.js.map +0 -1
- package/dist/tools/portfolio/alerts.js.map +0 -1
- package/dist/tools/portfolio/correlation.js.map +0 -1
- package/dist/tools/portfolio/daily-report.js.map +0 -1
- package/dist/tools/portfolio/holdings-overlap.js.map +0 -1
- package/dist/tools/portfolio/notifications.js.map +0 -1
- package/dist/tools/portfolio/risk-analysis.js.map +0 -1
- package/dist/tools/portfolio/tracker.js.map +0 -1
- package/dist/tools/portfolio/watchlist.js.map +0 -1
- package/dist/tools/sentiment/insight-format.js.map +0 -1
- package/dist/tools/sentiment/query-match.js.map +0 -1
- package/dist/tools/sentiment/reddit-sentiment.js.map +0 -1
- package/dist/tools/sentiment/sentiment-summary.js.map +0 -1
- package/dist/tools/sentiment/sentiment-trend.js.map +0 -1
- package/dist/tools/sentiment/twitter-sentiment.js.map +0 -1
- package/dist/tools/sentiment/untrusted-text.js.map +0 -1
- package/dist/tools/sentiment/web-search.js.map +0 -1
- package/dist/tools/sentiment/web-sentiment.js.map +0 -1
- package/dist/tools/technical/backtest.js.map +0 -1
- package/dist/tools/technical/indicators.js.map +0 -1
- package/dist/types/fundamentals.js.map +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/types/macro.js.map +0 -1
- package/dist/types/market.js.map +0 -1
- package/dist/types/options.js.map +0 -1
- package/dist/types/portfolio.js.map +0 -1
- package/dist/types/sentiment.js.map +0 -1
- package/dist/workflows/compare-assets.js.map +0 -1
- package/dist/workflows/index.js.map +0 -1
- package/dist/workflows/options-screener.js.map +0 -1
- package/dist/workflows/portfolio-builder.js.map +0 -1
- package/gui/server/ask-user-bridge.ts +0 -89
- package/gui/server/automation-heartbeat.ts +0 -97
- package/gui/server/background-quotes.ts +0 -127
- package/gui/server/chat-event-adapter.ts +0 -210
- package/gui/server/chat-run-session.ts +0 -16
- package/gui/server/gui-session-manager.ts +0 -5
- package/gui/server/http-routes.ts +0 -953
- package/gui/server/invoke-tool.ts +0 -489
- package/gui/server/live-chat-event-adapter.ts +0 -208
- package/gui/server/local-session-coordinator.ts +0 -97
- package/gui/server/market-state-api.ts +0 -273
- package/gui/server/model-setup.ts +0 -254
- package/gui/server/package.json +0 -5
- package/gui/server/private-api-access.ts +0 -62
- package/gui/server/projector.ts +0 -263
- package/gui/server/prompt-observation.ts +0 -58
- package/gui/server/quote-snapshot-store.ts +0 -50
- package/gui/server/server.ts +0 -289
- package/gui/server/session-actions.ts +0 -331
- package/gui/server/session-entry-wait.ts +0 -160
- package/gui/server/shutdown.ts +0 -47
- package/gui/server/tool-invoke-ack.ts +0 -49
- package/gui/server/tool-metadata.ts +0 -167
- package/gui/server/websocket.ts +0 -138
- package/gui/server/writer-lock.ts +0 -1
- package/gui/server/ws-hub.ts +0 -391
- package/gui/shared/chat-events.ts +0 -156
- package/gui/shared/event-reducer.ts +0 -219
- package/gui/web/dist/assets/CatalogOverlay-ChRTKNlf.js +0 -1
- package/gui/web/dist/assets/index-BzyqyVnd.css +0 -2
- package/gui/web/dist/assets/index-DvMjkOP9.js +0 -65
- package/src/analysts/contracts.ts +0 -176
- package/src/analysts/orchestrator.ts +0 -224
- package/src/cli-main.ts +0 -510
- package/src/cli.ts +0 -17
- package/src/config.ts +0 -272
- package/src/doctor/cli-command.ts +0 -83
- package/src/doctor/render.ts +0 -37
- package/src/doctor/report.ts +0 -638
- package/src/index.ts +0 -5
- package/src/infra/cache.ts +0 -114
- package/src/infra/http-client.ts +0 -134
- package/src/infra/index.ts +0 -14
- package/src/infra/native-dependencies.ts +0 -84
- package/src/infra/node-version.ts +0 -23
- package/src/infra/open-url.ts +0 -28
- package/src/infra/opencandle-paths.ts +0 -53
- package/src/infra/rate-limiter.ts +0 -76
- package/src/market-state/alert-conditions.ts +0 -82
- package/src/market-state/alert-runner.ts +0 -863
- package/src/market-state/daily-report.ts +0 -237
- package/src/market-state/local-automation-service.ts +0 -162
- package/src/market-state/notification-delivery.ts +0 -158
- package/src/market-state/resolve-for-mutation.ts +0 -24
- package/src/market-state/resolve.ts +0 -112
- package/src/market-state/service.ts +0 -2208
- package/src/memory/index.ts +0 -10
- package/src/memory/manager.ts +0 -190
- package/src/memory/preference-extractor.ts +0 -106
- package/src/memory/retrieval.ts +0 -71
- package/src/memory/sqlite.ts +0 -577
- package/src/memory/storage.ts +0 -195
- package/src/memory/tool-defaults.ts +0 -108
- package/src/memory/types.ts +0 -71
- package/src/monitor.ts +0 -123
- package/src/onboarding/connect.ts +0 -177
- package/src/onboarding/credential-interceptor.ts +0 -122
- package/src/onboarding/degradation-accumulator.ts +0 -77
- package/src/onboarding/prompt-user.ts +0 -85
- package/src/onboarding/provider-status.ts +0 -382
- package/src/onboarding/providers.ts +0 -414
- package/src/onboarding/state.ts +0 -216
- package/src/onboarding/tool-helpers.ts +0 -104
- package/src/onboarding/tool-tags.ts +0 -244
- package/src/onboarding/validation.ts +0 -152
- package/src/pi/opencandle-extension.ts +0 -1244
- package/src/pi/session-action-dedupe.ts +0 -155
- package/src/pi/session-storage.ts +0 -5
- package/src/pi/session-writer-lock.ts +0 -426
- package/src/pi/session.ts +0 -84
- package/src/pi/setup.ts +0 -399
- package/src/pi/tool-adapter.ts +0 -49
- package/src/pi/tui-session-coordinator.ts +0 -351
- package/src/prompts/context-builder.ts +0 -326
- package/src/prompts/disclaimer.ts +0 -9
- package/src/prompts/policy-cards.ts +0 -228
- package/src/prompts/sections.ts +0 -46
- package/src/prompts/symbol-preflight.ts +0 -80
- package/src/prompts/workflow-prompts.ts +0 -504
- package/src/providers/alpha-vantage.ts +0 -334
- package/src/providers/coingecko.ts +0 -93
- package/src/providers/errors.ts +0 -9
- package/src/providers/exa-search.ts +0 -375
- package/src/providers/external-tool-command.ts +0 -164
- package/src/providers/external-tool-error.ts +0 -20
- package/src/providers/fear-greed.ts +0 -45
- package/src/providers/finnhub.ts +0 -125
- package/src/providers/fred.ts +0 -83
- package/src/providers/index.ts +0 -17
- package/src/providers/provider-credential-error.ts +0 -23
- package/src/providers/reddit-cli.ts +0 -286
- package/src/providers/reddit.ts +0 -106
- package/src/providers/sec-edgar.ts +0 -326
- package/src/providers/tradingview.ts +0 -399
- package/src/providers/twitter-cli.ts +0 -202
- package/src/providers/twitter.ts +0 -102
- package/src/providers/web-search.ts +0 -303
- package/src/providers/with-fallback.ts +0 -42
- package/src/providers/wrap-provider.ts +0 -103
- package/src/providers/yahoo-finance.ts +0 -672
- package/src/routing/classify-intent.ts +0 -380
- package/src/routing/defaults.ts +0 -29
- package/src/routing/entity-extractor.ts +0 -540
- package/src/routing/fund-symbols.ts +0 -58
- package/src/routing/horizon.ts +0 -7
- package/src/routing/index.ts +0 -70
- package/src/routing/legacy-rule-router.ts +0 -13
- package/src/routing/planning.ts +0 -829
- package/src/routing/route-manifest.ts +0 -308
- package/src/routing/router-llm-client.ts +0 -52
- package/src/routing/router-prompt.ts +0 -159
- package/src/routing/router-types.ts +0 -84
- package/src/routing/router.ts +0 -997
- package/src/routing/slot-resolver.ts +0 -213
- package/src/routing/symbol-disambiguator.ts +0 -72
- package/src/routing/turn-context.ts +0 -108
- package/src/routing/types.ts +0 -77
- package/src/runtime/answer-contracts.ts +0 -693
- package/src/runtime/artifact-contracts.ts +0 -77
- package/src/runtime/evidence.ts +0 -77
- package/src/runtime/planning-evidence.ts +0 -682
- package/src/runtime/prompt-step.ts +0 -60
- package/src/runtime/provider-tracker.ts +0 -40
- package/src/runtime/run-context.ts +0 -32
- package/src/runtime/session-coordinator.ts +0 -632
- package/src/runtime/session-title.ts +0 -60
- package/src/runtime/tool-defaults-wrapper.ts +0 -43
- package/src/runtime/validation.ts +0 -211
- package/src/runtime/workflow-events.ts +0 -75
- package/src/runtime/workflow-runner.ts +0 -182
- package/src/runtime/workflow-types.ts +0 -102
- package/src/sentiment/adapters/finnhub.ts +0 -49
- package/src/sentiment/adapters/reddit.ts +0 -65
- package/src/sentiment/adapters/twitter.ts +0 -36
- package/src/sentiment/adapters/web.ts +0 -44
- package/src/sentiment/index.ts +0 -49
- package/src/sentiment/insights.ts +0 -269
- package/src/sentiment/keywords.ts +0 -31
- package/src/sentiment/pipeline.ts +0 -91
- package/src/sentiment/scorer.ts +0 -89
- package/src/sentiment/store.ts +0 -260
- package/src/sentiment/trends.ts +0 -96
- package/src/sentiment/types.ts +0 -112
- package/src/system-prompt.ts +0 -115
- package/src/tool-kit.ts +0 -69
- package/src/tools/AGENTS.md +0 -36
- package/src/tools/fundamentals/company-overview.ts +0 -64
- package/src/tools/fundamentals/comps.ts +0 -169
- package/src/tools/fundamentals/dcf.ts +0 -367
- package/src/tools/fundamentals/earnings.ts +0 -57
- package/src/tools/fundamentals/financials.ts +0 -63
- package/src/tools/fundamentals/sec-filings.ts +0 -105
- package/src/tools/index.ts +0 -101
- package/src/tools/interaction/ask-user.ts +0 -93
- package/src/tools/macro/fear-greed.ts +0 -41
- package/src/tools/macro/fred-data.ts +0 -92
- package/src/tools/market/crypto-history.ts +0 -72
- package/src/tools/market/crypto-price.ts +0 -53
- package/src/tools/market/screen-stocks.ts +0 -279
- package/src/tools/market/search-ticker.ts +0 -254
- package/src/tools/market/stock-history.ts +0 -104
- package/src/tools/market/stock-quote.ts +0 -67
- package/src/tools/options/greeks.ts +0 -81
- package/src/tools/options/option-chain.ts +0 -120
- package/src/tools/portfolio/alerts.ts +0 -457
- package/src/tools/portfolio/correlation.ts +0 -189
- package/src/tools/portfolio/daily-report.ts +0 -107
- package/src/tools/portfolio/holdings-overlap.ts +0 -139
- package/src/tools/portfolio/notifications.ts +0 -45
- package/src/tools/portfolio/risk-analysis.ts +0 -173
- package/src/tools/portfolio/tracker.ts +0 -308
- package/src/tools/portfolio/watchlist.ts +0 -288
- package/src/tools/sentiment/insight-format.ts +0 -50
- package/src/tools/sentiment/query-match.ts +0 -117
- package/src/tools/sentiment/reddit-sentiment.ts +0 -403
- package/src/tools/sentiment/sentiment-summary.ts +0 -383
- package/src/tools/sentiment/sentiment-trend.ts +0 -75
- package/src/tools/sentiment/twitter-sentiment.ts +0 -287
- package/src/tools/sentiment/untrusted-text.ts +0 -21
- package/src/tools/sentiment/web-search.ts +0 -186
- package/src/tools/sentiment/web-sentiment.ts +0 -96
- package/src/tools/technical/backtest.ts +0 -336
- package/src/tools/technical/indicators.ts +0 -281
- package/src/types/fundamentals.ts +0 -46
- package/src/types/index.ts +0 -25
- package/src/types/macro.ts +0 -27
- package/src/types/market.ts +0 -44
- package/src/types/options.ts +0 -52
- package/src/types/portfolio.ts +0 -83
- package/src/types/sentiment.ts +0 -129
- package/src/workflows/compare-assets.ts +0 -89
- package/src/workflows/index.ts +0 -3
- package/src/workflows/options-screener.ts +0 -125
- package/src/workflows/portfolio-builder.ts +0 -63
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# OpenCandle
|
|
2
2
|
|
|
3
|
+
OpenCandle is an open source financial investigator: a terminal agent and local browser workbench for market research that starts from real provider data, shows source gaps, and keeps risk visible.
|
|
4
|
+
|
|
5
|
+
Requires Node.js 22.19+ or 24–26. macOS and Linux are fully supported; Windows is best-effort (WSL recommended).
|
|
6
|
+
|
|
3
7
|
```bash
|
|
4
8
|
npx opencandle
|
|
5
9
|
# or
|
|
6
10
|
npx opencandle gui
|
|
7
11
|
```
|
|
8
12
|
|
|
9
|
-
OpenCandle is an open source financial investigator: a terminal agent and local browser workbench for market research that starts from real provider data, shows source gaps, and keeps risk visible.
|
|
10
|
-
|
|
11
13
|
[](https://github.com/Kahtaf/OpenCandle/actions/workflows/ci.yml)
|
|
12
14
|
[](https://www.npmjs.com/package/opencandle)
|
|
13
15
|
[](https://github.com/Kahtaf/OpenCandle/blob/main/LICENSE)
|
|
@@ -18,15 +20,15 @@ OpenCandle is an open source financial investigator: a terminal agent and local
|
|
|
18
20
|
|
|
19
21
|
### Terminal UI
|
|
20
22
|
|
|
21
|
-
[](https://cdn.jsdelivr.net/gh/Kahtaf/OpenCandle@v0.11.1/assets/opencandle-tui.mp4)
|
|
22
24
|
|
|
23
|
-
[Watch the terminal UI demo](https://cdn.jsdelivr.net/gh/Kahtaf/OpenCandle@
|
|
25
|
+
[Watch the terminal UI demo](https://cdn.jsdelivr.net/gh/Kahtaf/OpenCandle@v0.11.1/assets/opencandle-tui.mp4) | [Download MP4](https://github.com/Kahtaf/OpenCandle/raw/refs/heads/main/assets/opencandle-tui.mp4)
|
|
24
26
|
|
|
25
27
|
### Local GUI
|
|
26
28
|
|
|
27
|
-
[](https://cdn.jsdelivr.net/gh/Kahtaf/OpenCandle@v0.11.1/assets/opencandle-gui.mp4)
|
|
28
30
|
|
|
29
|
-
[Watch the local GUI demo](https://cdn.jsdelivr.net/gh/Kahtaf/OpenCandle@
|
|
31
|
+
[Watch the local GUI demo](https://cdn.jsdelivr.net/gh/Kahtaf/OpenCandle@v0.11.1/assets/opencandle-gui.mp4) | [Download MP4](https://github.com/Kahtaf/OpenCandle/raw/refs/heads/main/assets/opencandle-gui.mp4)
|
|
30
32
|
|
|
31
33
|
## Why OpenCandle
|
|
32
34
|
|
|
@@ -46,24 +48,18 @@ OpenCandle is read-only research software. It does not place trades, route order
|
|
|
46
48
|
|
|
47
49
|
| Capability | What it gives you |
|
|
48
50
|
| --- | --- |
|
|
49
|
-
| Terminal agent | Fast keyboard-driven research inside Pi
|
|
51
|
+
| Terminal agent | Fast keyboard-driven research inside the bundled [Pi](https://github.com/earendil-works/pi) local TUI, with sessions, slash commands, model setup, and saved transcripts. Pi is the bundled agent runtime; no separate Pi install is needed. |
|
|
50
52
|
| Local browser GUI | Chat, session history, provider setup, tool discovery, workflow launches, and richer financial result cards at `http://127.0.0.1:14567`. |
|
|
51
53
|
| Evidence-first answers | Tools fetch and format data; the model synthesizes only after evidence is gathered. |
|
|
52
54
|
| Finance routing | Quote lookup, comparison, portfolio review, options strategy, filing checks, macro questions, sentiment reads, and educational prompts route differently. |
|
|
53
55
|
| Provider transparency | Missing keys, degraded sources, stale cache, and unavailable data are surfaced instead of hidden. |
|
|
54
|
-
| Local state | OpenCandle user state lives under `~/.opencandle/` unless `OPENCANDLE_HOME` is set; durable market state is stored in SQLite at `state.db
|
|
56
|
+
| Local state | OpenCandle user state lives under `~/.opencandle/` unless `OPENCANDLE_HOME` is set; durable market state is stored in SQLite at `~/.opencandle/state.db` (or `$OPENCANDLE_HOME/state.db`). |
|
|
55
57
|
| Extensible tools | TypeScript tool APIs, provider boundaries, workflow builders, and package exports for add-on tools. |
|
|
56
58
|
| Eval harness | Unit tests, live provider checks, CLI e2e, GUI browser smoke tests, and competitive finance evals. |
|
|
57
59
|
|
|
58
60
|
## Quick Start
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
npx opencandle
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
On first run, OpenCandle walks you through model setup. In the terminal, you can use Pi sign-in when available or provide a model API key. In the GUI, use the API-key setup panel or complete terminal `/setup` first and refresh the browser. Data-provider keys are separate and optional.
|
|
62
|
+
On first run, OpenCandle walks you through model setup. [Pi](https://github.com/earendil-works/pi) is the bundled agent runtime that handles model setup, the terminal shell, and saved sessions; no separate Pi install is needed. In the terminal, you can use Pi sign-in when available or provide a model API key. In the GUI, use the API-key setup panel or complete terminal `/setup` first and refresh the browser. Data-provider keys are separate and optional.
|
|
67
63
|
|
|
68
64
|
Start the GUI instead:
|
|
69
65
|
|
|
@@ -100,11 +96,11 @@ Useful slash commands:
|
|
|
100
96
|
Health diagnostics run from your shell:
|
|
101
97
|
|
|
102
98
|
```bash
|
|
103
|
-
opencandle doctor
|
|
104
|
-
opencandle doctor --json
|
|
105
|
-
opencandle doctor --sessions
|
|
106
|
-
opencandle doctor --full
|
|
107
|
-
opencandle doctor --enable twitter
|
|
99
|
+
npx opencandle doctor
|
|
100
|
+
npx opencandle doctor --json
|
|
101
|
+
npx opencandle doctor --sessions
|
|
102
|
+
npx opencandle doctor --full
|
|
103
|
+
npx opencandle doctor --enable twitter
|
|
108
104
|
```
|
|
109
105
|
|
|
110
106
|
The GUI also has a Diagnostics page at `/diagnostics` with the same health report, provider setup links, model setup actions, and an explicit browser-session check for Reddit and Twitter/X.
|
|
@@ -113,16 +109,16 @@ The GUI also has a Diagnostics page at `/diagnostics` with the same health repor
|
|
|
113
109
|
|
|
114
110
|
| Area | Examples | Source |
|
|
115
111
|
| --- | --- | --- |
|
|
116
|
-
| Market data | Quotes, history, ticker search, crypto price and history | Yahoo Finance, Alpha Vantage fallback when configured, CoinGecko |
|
|
112
|
+
| Market data | Quotes, history, ticker search, screeners, crypto price and history | Yahoo Finance, TradingView scanner, Alpha Vantage fallback when configured, CoinGecko |
|
|
117
113
|
| Options | Chains, open interest, IV, locally computed Greeks | Yahoo Finance plus local calculations |
|
|
118
114
|
| Fundamentals | Overview, financials, earnings, DCF, comparable companies | Alpha Vantage |
|
|
119
|
-
| Macro | Rates, CPI, GDP, unemployment, crypto Fear & Greed | FRED, alternative.me |
|
|
115
|
+
| Macro | Rates, CPI, GDP, unemployment, event probabilities, crypto Fear & Greed | FRED, Polymarket Gamma API, alternative.me |
|
|
120
116
|
| Technical | Indicators and strategy backtests | Local calculations over market history |
|
|
121
117
|
| Sentiment | Reddit, Twitter/X, Finnhub news, and web sentiment | `rdt-cli` and `twitter-cli` using your normal browser sessions, Finnhub, Exa, Brave, DuckDuckGo |
|
|
122
118
|
| Filings | SEC filing search | SEC EDGAR |
|
|
123
119
|
| Portfolio | Watchlists, holdings, correlation, risk | Local state plus market data |
|
|
124
120
|
|
|
125
|
-
Yahoo Finance, CoinGecko, SEC EDGAR, DuckDuckGo search, and the alternative.me crypto Fear & Greed index do not require OpenCandle provider keys. Reddit sentiment requires `rdt-cli` (`uv tool install rdt-cli`) plus an active Reddit session in your normal browser. Twitter/X sentiment requires `twitter-cli` (`uv tool install twitter-cli`) plus an active x.com session in your normal browser. Alpha Vantage, FRED, Brave, Exa, and Finnhub unlock deeper coverage when configured.
|
|
121
|
+
Yahoo Finance, TradingView scanner, Polymarket Gamma, CoinGecko, SEC EDGAR, DuckDuckGo search, and the alternative.me crypto Fear & Greed index do not require OpenCandle provider keys. Reddit sentiment requires `rdt-cli` (`uv tool install rdt-cli`) plus an active Reddit session in your normal browser. Twitter/X sentiment requires `twitter-cli` (`uv tool install twitter-cli`) plus an active x.com session in your normal browser. Alpha Vantage, FRED, Brave, Exa, and Finnhub unlock deeper coverage when configured.
|
|
126
122
|
|
|
127
123
|
## Configuration
|
|
128
124
|
|
|
@@ -165,7 +161,7 @@ npm run gui
|
|
|
165
161
|
|
|
166
162
|
## How It Fits Together
|
|
167
163
|
|
|
168
|
-

|
|
164
|
+

|
|
169
165
|
|
|
170
166
|
```text
|
|
171
167
|
User prompt
|
|
@@ -220,9 +216,10 @@ npm run test:watch
|
|
|
220
216
|
npm run test:e2e
|
|
221
217
|
npm run test:e2e:cli
|
|
222
218
|
npm run test:e2e:providers
|
|
223
|
-
npm run
|
|
224
|
-
npm run
|
|
225
|
-
npm run
|
|
219
|
+
npm run eval
|
|
220
|
+
npm run eval -- cases
|
|
221
|
+
npm run eval -- product
|
|
222
|
+
npm run eval -- competitive
|
|
226
223
|
```
|
|
227
224
|
|
|
228
225
|
Baseline check:
|
|
@@ -231,7 +228,7 @@ Baseline check:
|
|
|
231
228
|
npm test
|
|
232
229
|
```
|
|
233
230
|
|
|
234
|
-
The e2e, provider, and eval commands can hit live APIs, live model providers, or local agent CLIs. Run them intentionally; see [Testing and Evals](https://opencandle.app/docs/testing-and-evals.html).
|
|
231
|
+
The e2e, provider, and eval commands can hit live APIs, live model providers, or local agent CLIs. `npm run eval` lists every eval suite; run suites through `npm run eval -- <suite>`. Run them intentionally; see [Testing and Evals](https://opencandle.app/docs/testing-and-evals.html).
|
|
235
232
|
|
|
236
233
|
Repository rules that matter:
|
|
237
234
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { WorkflowDefinition } from "../runtime/prompt-step.js";
|
|
2
|
+
import type { AnalystOutput } from "../runtime/workflow-types.js";
|
|
2
3
|
export type AnalystRole = "valuation" | "momentum" | "options" | "contrarian" | "risk";
|
|
3
4
|
export declare function buildBullPrompt(symbol: string): string;
|
|
4
5
|
export declare function buildBearPrompt(symbol: string): string;
|
|
5
6
|
export declare function buildRebuttalPrompt(symbol: string): string;
|
|
7
|
+
export declare function buildAnalystVoteTallyBlock(outputs: AnalystOutput[]): string | null;
|
|
6
8
|
export declare function buildSynthesisPrompt(symbol: string): string;
|
|
7
9
|
export declare function getInitialAnalysisPrompt(symbol: string): string;
|
|
8
10
|
export declare function buildComprehensiveAnalysisDefinition(symbol: string): WorkflowDefinition;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { promptStep } from "../runtime/prompt-step.js";
|
|
2
|
+
import { isAnalystSplit, tallyVotes } from "./contracts.js";
|
|
2
3
|
const SYMBOL_CAPTURE = "(\\$?[A-Za-z]{1,5}(?:[./-][A-Za-z]{1,2})?)";
|
|
3
4
|
const NORMALIZED_SYMBOL_PATTERN = /^[A-Z]{1,5}(?:[./-][A-Z]{1,2})?$/;
|
|
4
5
|
const VOTING_INSTRUCTION = `
|
|
@@ -95,7 +96,24 @@ End with this exact format:
|
|
|
95
96
|
CONCESSIONS: [bullet list of points you concede]
|
|
96
97
|
REMAINING CONVICTION: [1-10, where 10 = fully confident despite bear case]`;
|
|
97
98
|
}
|
|
99
|
+
export function buildAnalystVoteTallyBlock(outputs) {
|
|
100
|
+
if (outputs.length < 2)
|
|
101
|
+
return null;
|
|
102
|
+
const tally = tallyVotes(outputs);
|
|
103
|
+
const split = isAnalystSplit(outputs);
|
|
104
|
+
return `## Deterministic Analyst Vote Tally
|
|
105
|
+
- Parsed analyst outputs: ${outputs.length}
|
|
106
|
+
- BUY: ${tally.buy}
|
|
107
|
+
- HOLD: ${tally.hold}
|
|
108
|
+
- SELL: ${tally.sell}
|
|
109
|
+
- Weighted average conviction: ${tally.weightedConviction}
|
|
110
|
+
- Computed verdict: ${tally.verdict}
|
|
111
|
+
- BUY+SELL split: ${split ? "yes" : "no"}`;
|
|
112
|
+
}
|
|
98
113
|
export function buildSynthesisPrompt(symbol) {
|
|
114
|
+
// The runtime tally block is injected at dispatch time by
|
|
115
|
+
// SessionCoordinator.prepareWorkflowPrompt, where parsed analyst outputs
|
|
116
|
+
// exist; this builder runs at workflow-definition time and stays static.
|
|
99
117
|
return `**[Synthesis]** You have received five analyst signals with conviction scores for ${symbol}, a bull case arguing FOR the position, and a bear case arguing AGAINST.
|
|
100
118
|
If a bull rebuttal with concessions appears above (not a line starting with "REBUTTAL SKIPPED"), treat the concessions as validated risks that must be addressed.
|
|
101
119
|
|
|
@@ -154,6 +172,7 @@ export function buildComprehensiveAnalysisDefinition(symbol) {
|
|
|
154
172
|
expectedOutputs: ["bear_thesis"],
|
|
155
173
|
}),
|
|
156
174
|
promptStep("debate_rebuttal", "Bull rebuttal (self-gating)", buildRebuttalPrompt(symbol), {
|
|
175
|
+
skippable: true,
|
|
157
176
|
requiredInputs: [...analystOutputs, "bull_thesis", "bear_thesis"],
|
|
158
177
|
expectedOutputs: ["rebuttal"],
|
|
159
178
|
}),
|
|
@@ -190,4 +209,3 @@ export function normalizeSymbol(input) {
|
|
|
190
209
|
const candidate = trimmed.replace(/\$/g, "").toUpperCase();
|
|
191
210
|
return NORMALIZED_SYMBOL_PATTERN.test(candidate) ? candidate : undefined;
|
|
192
211
|
}
|
|
193
|
-
//# sourceMappingURL=orchestrator.js.map
|
package/dist/cli-main.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
4
5
|
import { dirname, resolve } from "node:path";
|
|
5
6
|
import { createInterface } from "node:readline/promises";
|
|
@@ -98,9 +99,12 @@ async function handlePackageCommand(args, cwd, agentDir) {
|
|
|
98
99
|
async function handleGuiCommand(args, cwd) {
|
|
99
100
|
if (args[0] !== "gui")
|
|
100
101
|
return false;
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
const
|
|
102
|
+
const compiledServerPath = resolve(packageRoot, "dist/gui/server/server.js");
|
|
103
|
+
const sourceServerPath = resolve(packageRoot, "gui/server/server.ts");
|
|
104
|
+
const commandArgs = existsSync(compiledServerPath)
|
|
105
|
+
? [compiledServerPath, ...args.slice(1)]
|
|
106
|
+
: [require.resolve("tsx/cli"), sourceServerPath, ...args.slice(1)];
|
|
107
|
+
const child = spawn(process.execPath, commandArgs, {
|
|
104
108
|
cwd,
|
|
105
109
|
env: process.env,
|
|
106
110
|
stdio: "inherit",
|
|
@@ -121,9 +125,12 @@ async function handleGuiCommand(args, cwd) {
|
|
|
121
125
|
async function handleMonitorCommand(args, cwd) {
|
|
122
126
|
if (args[0] !== "monitor")
|
|
123
127
|
return false;
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
const
|
|
128
|
+
const compiledMonitorPath = resolve(packageRoot, "dist/monitor.js");
|
|
129
|
+
const sourceMonitorPath = resolve(packageRoot, "src/monitor.ts");
|
|
130
|
+
const commandArgs = existsSync(compiledMonitorPath)
|
|
131
|
+
? [compiledMonitorPath, ...args.slice(1)]
|
|
132
|
+
: [require.resolve("tsx/cli"), sourceMonitorPath, ...args.slice(1)];
|
|
133
|
+
const child = spawn(process.execPath, commandArgs, {
|
|
127
134
|
cwd,
|
|
128
135
|
env: process.env,
|
|
129
136
|
stdio: "inherit",
|
|
@@ -454,4 +461,3 @@ function asRecord(value) {
|
|
|
454
461
|
: {};
|
|
455
462
|
}
|
|
456
463
|
await main();
|
|
457
|
-
//# sourceMappingURL=cli-main.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
6
|
+
export function frontDoorCommand(args) {
|
|
7
|
+
if (args[0] === "--help" || args[0] === "-h")
|
|
8
|
+
return "help";
|
|
9
|
+
if (args[0] === "--version" || args[0] === "-v")
|
|
10
|
+
return "version";
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
export function renderFrontDoorCommand(command) {
|
|
14
|
+
if (command === "version")
|
|
15
|
+
return readPackageMetadata().version ?? "unknown";
|
|
16
|
+
return [
|
|
17
|
+
"Usage: opencandle [command]",
|
|
18
|
+
"",
|
|
19
|
+
"Commands:",
|
|
20
|
+
" (default) Start the interactive terminal TUI",
|
|
21
|
+
" gui Start the local GUI",
|
|
22
|
+
" monitor [--once] Run local alert/report automation",
|
|
23
|
+
" doctor [--json|--full|--sessions|--enable <provider>]",
|
|
24
|
+
" Check OpenCandle health",
|
|
25
|
+
" install <source> [-l] Install a package",
|
|
26
|
+
" remove|uninstall <source> [-l] Remove a package",
|
|
27
|
+
" list List installed packages",
|
|
28
|
+
" update [source] Update packages",
|
|
29
|
+
].join("\n");
|
|
30
|
+
}
|
|
31
|
+
function readPackageMetadata() {
|
|
32
|
+
return require(resolve(packageRoot, "package.json"));
|
|
33
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { frontDoorCommand, renderFrontDoorCommand } from "./cli-options.js";
|
|
2
3
|
import { ensureOpenCandleNativeDependencies } from "./infra/native-dependencies.js";
|
|
3
4
|
import { assertSupportedNodeVersion } from "./infra/node-version.js";
|
|
4
|
-
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
const command = frontDoorCommand(args);
|
|
7
|
+
if (command) {
|
|
8
|
+
console.log(renderFrontDoorCommand(command));
|
|
9
|
+
}
|
|
10
|
+
else if (args[0] === "doctor") {
|
|
5
11
|
const [{ loadEnv }, { handleDoctorCommand }, { getAgentDir }] = await Promise.all([
|
|
6
12
|
import("./config.js"),
|
|
7
13
|
import("./doctor/cli-command.js"),
|
|
8
14
|
import("@earendil-works/pi-coding-agent"),
|
|
9
15
|
]);
|
|
10
16
|
loadEnv();
|
|
11
|
-
await handleDoctorCommand(
|
|
17
|
+
await handleDoctorCommand(args, process.cwd(), getAgentDir());
|
|
12
18
|
}
|
|
13
19
|
else {
|
|
14
20
|
assertSupportedNodeVersion();
|
|
15
21
|
await ensureOpenCandleNativeDependencies();
|
|
16
22
|
await import("./cli-main.js");
|
|
17
23
|
}
|
|
18
|
-
//# sourceMappingURL=cli.js.map
|
package/dist/config.js
CHANGED
|
@@ -42,6 +42,8 @@ export async function handleDoctorCommand(args, cwd, agentDir) {
|
|
|
42
42
|
modelSetup: buildCliModelSetupState(modelRegistry, settingsManager),
|
|
43
43
|
});
|
|
44
44
|
console.log(json ? JSON.stringify(report, null, 2) : renderDoctorReport(report));
|
|
45
|
+
if (report.status === "blocked")
|
|
46
|
+
process.exitCode = 1;
|
|
45
47
|
return true;
|
|
46
48
|
}
|
|
47
49
|
function buildCliModelSetupState(modelRegistry, settingsManager) {
|
|
@@ -66,4 +68,3 @@ function buildCliModelSetupState(modelRegistry, settingsManager) {
|
|
|
66
68
|
availableModels,
|
|
67
69
|
};
|
|
68
70
|
}
|
|
69
|
-
//# sourceMappingURL=cli-command.js.map
|
package/dist/doctor/render.js
CHANGED
package/dist/doctor/report.js
CHANGED
|
@@ -6,6 +6,7 @@ import { getUnsupportedNodeVersionMessage } from "../infra/node-version.js";
|
|
|
6
6
|
import { getConfigPath, getOnboardingPath, getOpenCandleHomeDir, getStateDbPath, resolveOpenCandlePath, } from "../infra/opencandle-paths.js";
|
|
7
7
|
import { probeAllProviderStatuses, probeProviderStatus, } from "../onboarding/provider-status.js";
|
|
8
8
|
import { getProvider, isExternalToolProvider, listAllProviders, } from "../onboarding/providers.js";
|
|
9
|
+
import { loadOnboardingState } from "../onboarding/state.js";
|
|
9
10
|
export const DOCTOR_REPORT_SCHEMA_VERSION = 1;
|
|
10
11
|
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
11
12
|
const require = createRequire(import.meta.url);
|
|
@@ -48,8 +49,8 @@ export function deriveDoctorStatus(checks) {
|
|
|
48
49
|
return "blocked";
|
|
49
50
|
}
|
|
50
51
|
if (checks.some((candidate) => candidate.status === "warn" ||
|
|
51
|
-
candidate.status === "
|
|
52
|
-
(candidate.capability === "
|
|
52
|
+
(candidate.capability === "optional" && candidate.status === "fail") ||
|
|
53
|
+
(candidate.capability === "core" && candidate.status === "unknown"))) {
|
|
53
54
|
return "degraded";
|
|
54
55
|
}
|
|
55
56
|
return "ready";
|
|
@@ -301,16 +302,22 @@ function providerStatusCheck(status, modeOverride) {
|
|
|
301
302
|
tier: provider.tier,
|
|
302
303
|
kind: status.kind,
|
|
303
304
|
state: status.state,
|
|
305
|
+
unlocks: provider.unlocks,
|
|
304
306
|
};
|
|
305
307
|
if (status.kind === "api-key") {
|
|
308
|
+
const configuredBefore = wasProviderConfigured(status.providerId);
|
|
309
|
+
const missing = status.state === "missing";
|
|
310
|
+
const neverConnected = missing && !configuredBefore;
|
|
306
311
|
return {
|
|
307
312
|
id: `provider.${status.providerId}.credential`,
|
|
308
313
|
label: provider.displayName,
|
|
309
|
-
status: status.state === "configured" ? "pass" : "warn",
|
|
314
|
+
status: status.state === "configured" ? "pass" : neverConnected ? "skip" : "warn",
|
|
310
315
|
capability,
|
|
311
316
|
summary: status.state === "configured"
|
|
312
317
|
? `Configured via ${status.credentialSource}`
|
|
313
|
-
:
|
|
318
|
+
: neverConnected
|
|
319
|
+
? "Not connected — optional."
|
|
320
|
+
: "Credential is missing",
|
|
314
321
|
remediation: status.state === "configured"
|
|
315
322
|
? undefined
|
|
316
323
|
: `${provider.instructionsHint}. Run /connect ${provider.id}.`,
|
|
@@ -327,7 +334,7 @@ function providerStatusCheck(status, modeOverride) {
|
|
|
327
334
|
summary: ok ? "Reachable" : `Not reachable (${status.state})`,
|
|
328
335
|
remediation: ok
|
|
329
336
|
? undefined
|
|
330
|
-
:
|
|
337
|
+
: `Check network connectivity and retry. OpenCandle uses ${provider.displayName} through a public HTTP endpoint.`,
|
|
331
338
|
metadata: { ...metadata, statusCode: status.statusCode ?? null },
|
|
332
339
|
};
|
|
333
340
|
}
|
|
@@ -344,6 +351,7 @@ function providerStatusCheck(status, modeOverride) {
|
|
|
344
351
|
};
|
|
345
352
|
}
|
|
346
353
|
const installed = status.state === "installed";
|
|
354
|
+
const missingBeforeSetup = status.state === "missing" && !wasProviderConfigured(status.providerId);
|
|
347
355
|
return {
|
|
348
356
|
id: `provider.${status.providerId}.binary`,
|
|
349
357
|
label: `${provider.displayName} CLI`,
|
|
@@ -352,10 +360,16 @@ function providerStatusCheck(status, modeOverride) {
|
|
|
352
360
|
: status.state === "skipped"
|
|
353
361
|
? "skip"
|
|
354
362
|
: status.state === "missing"
|
|
355
|
-
?
|
|
363
|
+
? missingBeforeSetup
|
|
364
|
+
? "skip"
|
|
365
|
+
: "warn"
|
|
356
366
|
: "unknown",
|
|
357
367
|
capability: "optional",
|
|
358
|
-
summary: installed
|
|
368
|
+
summary: installed
|
|
369
|
+
? "Installed"
|
|
370
|
+
: missingBeforeSetup
|
|
371
|
+
? "Not connected — optional."
|
|
372
|
+
: (status.message ?? `CLI ${status.state}`),
|
|
359
373
|
remediation: installed
|
|
360
374
|
? undefined
|
|
361
375
|
: status.state === "skipped"
|
|
@@ -364,6 +378,9 @@ function providerStatusCheck(status, modeOverride) {
|
|
|
364
378
|
metadata,
|
|
365
379
|
};
|
|
366
380
|
}
|
|
381
|
+
function wasProviderConfigured(providerId) {
|
|
382
|
+
return loadOnboardingState().providers[providerId]?.status === "completed";
|
|
383
|
+
}
|
|
367
384
|
function sessionNotCheckedCheck(provider) {
|
|
368
385
|
return {
|
|
369
386
|
id: `provider.${provider.id}.session`,
|
|
@@ -385,7 +402,11 @@ async function buildGuiChecks(options) {
|
|
|
385
402
|
label: "GUI server",
|
|
386
403
|
status: reachable ? (role === "follower" ? "warn" : "pass") : "skip",
|
|
387
404
|
capability: "optional",
|
|
388
|
-
summary: reachable
|
|
405
|
+
summary: reachable
|
|
406
|
+
? role === "writer"
|
|
407
|
+
? "GUI server is running and can run sessions"
|
|
408
|
+
: `GUI server is ${role}`
|
|
409
|
+
: "GUI server is not running",
|
|
389
410
|
remediation: role === "follower"
|
|
390
411
|
? "Open the writer GUI process to perform setup mutations."
|
|
391
412
|
: reachable
|
|
@@ -415,7 +436,9 @@ async function buildGuiChecks(options) {
|
|
|
415
436
|
status: verified ? (role === "follower" ? "warn" : "pass") : "warn",
|
|
416
437
|
capability: "optional",
|
|
417
438
|
summary: verified
|
|
418
|
-
?
|
|
439
|
+
? role === "writer"
|
|
440
|
+
? "GUI server is running and can run sessions"
|
|
441
|
+
: `GUI server is ${role}`
|
|
419
442
|
: response.ok
|
|
420
443
|
? "OpenCandle GUI health payload was not verified"
|
|
421
444
|
: `GUI health returned HTTP ${response.status}`,
|
|
@@ -449,8 +472,15 @@ function sessionRemediation(providerId, installCmd) {
|
|
|
449
472
|
return installCmd ?? "Install and authenticate the external tool.";
|
|
450
473
|
}
|
|
451
474
|
function buildSummary(status, checks) {
|
|
452
|
-
if (status === "ready")
|
|
453
|
-
|
|
475
|
+
if (status === "ready") {
|
|
476
|
+
const unchecked = checks.filter((candidate) => candidate.status === "unknown");
|
|
477
|
+
if (unchecked.length === 0)
|
|
478
|
+
return "OpenCandle core health is ready.";
|
|
479
|
+
if (unchecked.every((candidate) => candidate.capability === "optional")) {
|
|
480
|
+
return `OpenCandle core health is ready with ${unchecked.length} optional ${unchecked.length === 1 ? "capability" : "capabilities"} unchecked.`;
|
|
481
|
+
}
|
|
482
|
+
return `OpenCandle is usable with ${unchecked.length} unchecked ${unchecked.length === 1 ? "capability" : "capabilities"}.`;
|
|
483
|
+
}
|
|
454
484
|
const firstBlocking = checks.find((candidate) => candidate.capability === "core" && candidate.status === "fail");
|
|
455
485
|
if (firstBlocking)
|
|
456
486
|
return `OpenCandle is blocked: ${firstBlocking.summary}.`;
|
|
@@ -497,4 +527,3 @@ function canAccess(path, mode = constants.R_OK | constants.W_OK) {
|
|
|
497
527
|
return false;
|
|
498
528
|
}
|
|
499
529
|
}
|
|
500
|
-
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AskUserHandler } from "../../types/index.js";
|
|
2
|
+
type AskUserParams = Parameters<AskUserHandler>[0];
|
|
3
|
+
export interface GuiAskUserPrompt extends AskUserParams {
|
|
4
|
+
id: string;
|
|
5
|
+
sessionId: string;
|
|
6
|
+
status: "pending" | "answered" | "cancelled";
|
|
7
|
+
answer: string | null;
|
|
8
|
+
}
|
|
9
|
+
export declare function createAskUserBridge({ broadcast, getSessionId, }: {
|
|
10
|
+
broadcast: (message: unknown) => void;
|
|
11
|
+
getSessionId: () => string;
|
|
12
|
+
}): {
|
|
13
|
+
ask: AskUserHandler;
|
|
14
|
+
askForSession: (sessionId: string) => AskUserHandler;
|
|
15
|
+
answer: (id: string, answer: string) => boolean;
|
|
16
|
+
cancel: (id: string) => boolean;
|
|
17
|
+
getPrompts: () => GuiAskUserPrompt[];
|
|
18
|
+
};
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export function createAskUserBridge({ broadcast, getSessionId, }) {
|
|
2
|
+
let nextId = 1;
|
|
3
|
+
const prompts = new Map();
|
|
4
|
+
const pending = new Map();
|
|
5
|
+
const createAskHandler = (resolveSessionId) => async (params) => {
|
|
6
|
+
const id = `ask-user-${Date.now()}-${nextId++}`;
|
|
7
|
+
const prompt = {
|
|
8
|
+
id,
|
|
9
|
+
sessionId: resolveSessionId(),
|
|
10
|
+
question: params.question,
|
|
11
|
+
questionType: params.questionType,
|
|
12
|
+
options: params.options,
|
|
13
|
+
placeholder: params.placeholder,
|
|
14
|
+
reason: params.reason,
|
|
15
|
+
status: "pending",
|
|
16
|
+
answer: null,
|
|
17
|
+
};
|
|
18
|
+
prompts.set(id, prompt);
|
|
19
|
+
broadcast({ type: "ask_user.prompt", prompt });
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
pending.set(id, { prompt, resolve });
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
const ask = createAskHandler(getSessionId);
|
|
25
|
+
const resolvePrompt = (id, result) => {
|
|
26
|
+
const item = pending.get(id);
|
|
27
|
+
if (!item)
|
|
28
|
+
return false;
|
|
29
|
+
pending.delete(id);
|
|
30
|
+
const prompt = {
|
|
31
|
+
...item.prompt,
|
|
32
|
+
status: result.cancelled ? "cancelled" : "answered",
|
|
33
|
+
answer: result.cancelled ? null : (result.answer ?? null),
|
|
34
|
+
};
|
|
35
|
+
prompts.set(id, prompt);
|
|
36
|
+
broadcast({ type: "ask_user.resolved", prompt });
|
|
37
|
+
item.resolve(result);
|
|
38
|
+
return true;
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
ask,
|
|
42
|
+
askForSession(sessionId) {
|
|
43
|
+
return createAskHandler(() => sessionId);
|
|
44
|
+
},
|
|
45
|
+
answer(id, answer) {
|
|
46
|
+
return resolvePrompt(id, { answer, cancelled: false });
|
|
47
|
+
},
|
|
48
|
+
cancel(id) {
|
|
49
|
+
return resolvePrompt(id, { answer: null, cancelled: true });
|
|
50
|
+
},
|
|
51
|
+
getPrompts() {
|
|
52
|
+
return [...prompts.values()];
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { runLocalAutomationHeartbeat } from "../../market-state/local-automation-service.js";
|
|
2
|
+
import { initDefaultDatabase } from "../../memory/sqlite.js";
|
|
3
|
+
export declare const DEFAULT_AUTOMATION_HEARTBEAT_MS = 60000;
|
|
4
|
+
export declare const MIN_AUTOMATION_HEARTBEAT_MS = 5000;
|
|
5
|
+
export declare function normalizeAutomationHeartbeatMs(raw: string | undefined): number;
|
|
6
|
+
export declare function createAutomationHeartbeatRunner(run: (checkAlerts: boolean) => Promise<void>): (checkAlerts: boolean) => Promise<boolean>;
|
|
7
|
+
type IntervalHandle = ReturnType<typeof setInterval>;
|
|
8
|
+
type SetIntervalFn = (callback: () => void, ms: number) => IntervalHandle;
|
|
9
|
+
type ClearIntervalFn = (handle: IntervalHandle) => void;
|
|
10
|
+
export interface LocalAutomationHeartbeat {
|
|
11
|
+
start(): void;
|
|
12
|
+
stop(): void;
|
|
13
|
+
}
|
|
14
|
+
export interface LocalAutomationHeartbeatOptions {
|
|
15
|
+
role: string;
|
|
16
|
+
getSessionId: () => string;
|
|
17
|
+
intervalMs: number;
|
|
18
|
+
initDatabase?: typeof initDefaultDatabase;
|
|
19
|
+
runHeartbeat?: typeof runLocalAutomationHeartbeat;
|
|
20
|
+
setIntervalFn?: SetIntervalFn;
|
|
21
|
+
clearIntervalFn?: ClearIntervalFn;
|
|
22
|
+
warn?: (message: string) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare function createLocalAutomationHeartbeat({ role, getSessionId, intervalMs, initDatabase, runHeartbeat, setIntervalFn, clearIntervalFn, warn, }: LocalAutomationHeartbeatOptions): LocalAutomationHeartbeat;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { runLocalAutomationHeartbeat } from "../../market-state/local-automation-service.js";
|
|
2
|
+
import { initDefaultDatabase } from "../../memory/sqlite.js";
|
|
3
|
+
export const DEFAULT_AUTOMATION_HEARTBEAT_MS = 60_000;
|
|
4
|
+
export const MIN_AUTOMATION_HEARTBEAT_MS = 5_000;
|
|
5
|
+
export function normalizeAutomationHeartbeatMs(raw) {
|
|
6
|
+
if (raw == null || raw.trim() === "")
|
|
7
|
+
return DEFAULT_AUTOMATION_HEARTBEAT_MS;
|
|
8
|
+
const parsed = Number(raw);
|
|
9
|
+
if (!Number.isFinite(parsed) || parsed < MIN_AUTOMATION_HEARTBEAT_MS)
|
|
10
|
+
return DEFAULT_AUTOMATION_HEARTBEAT_MS;
|
|
11
|
+
return Math.floor(parsed);
|
|
12
|
+
}
|
|
13
|
+
export function createAutomationHeartbeatRunner(run) {
|
|
14
|
+
let inFlight = false;
|
|
15
|
+
return async (checkAlerts) => {
|
|
16
|
+
if (inFlight)
|
|
17
|
+
return false;
|
|
18
|
+
inFlight = true;
|
|
19
|
+
try {
|
|
20
|
+
await run(checkAlerts);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
inFlight = false;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function createLocalAutomationHeartbeat({ role, getSessionId, intervalMs, initDatabase = initDefaultDatabase, runHeartbeat = runLocalAutomationHeartbeat, setIntervalFn = setInterval, clearIntervalFn = clearInterval, warn = (message) => console.warn(message), }) {
|
|
29
|
+
let automationHeartbeat = null;
|
|
30
|
+
async function executeGuiAutomationHeartbeat(checkAlerts) {
|
|
31
|
+
const db = initDatabase();
|
|
32
|
+
try {
|
|
33
|
+
await runHeartbeat(db, {
|
|
34
|
+
ownerId: `gui:${getSessionId()}`,
|
|
35
|
+
ownerKind: "writer",
|
|
36
|
+
ttlSeconds: Math.max(90, Math.ceil((intervalMs * 2) / 1000)),
|
|
37
|
+
checkAlerts,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
warn(`Local automation heartbeat failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
db.close();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const runGuiAutomationHeartbeat = createAutomationHeartbeatRunner(executeGuiAutomationHeartbeat);
|
|
48
|
+
function start() {
|
|
49
|
+
if (role !== "writer")
|
|
50
|
+
return;
|
|
51
|
+
void runGuiAutomationHeartbeat(true);
|
|
52
|
+
automationHeartbeat = setIntervalFn(() => void runGuiAutomationHeartbeat(true), intervalMs);
|
|
53
|
+
}
|
|
54
|
+
function stop() {
|
|
55
|
+
if (automationHeartbeat) {
|
|
56
|
+
clearIntervalFn(automationHeartbeat);
|
|
57
|
+
automationHeartbeat = null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { start, stop };
|
|
61
|
+
}
|